码文不易,转载请带上本文链接,感谢~ https://www.cnblogs.com/echoyya/p/14506269.html

this 的指向

“this” 关键字允许在调用函数或方法时决定哪个对象应该是焦点。

在JavaScript中this可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式,this 绑定的对象即函数执行的上下文环境,在 ES5 中,其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象,正是由于调用function的对象不同,才导致了this的指向不同。

关于this的指向及绑定,请关注博文 JS五种绑定彻底弄懂this,默认绑定、隐式绑定、显式绑定、new绑定、箭头函数绑定详解

// e.g.1
var test = {
a: 5,
b: 6,
sum: function (a, b) {
function getA(a) {
this.a = a; // 在window上增加了一个全局变量a
return this.a; // 此处this = window
} function getB(b) {
this.b = b; //在window上增加了一个全局变量b
return this.b; // 此处this = window
}
return getA(a) + getB(b);
}
}
console.log(test.sum(4, 3)); // 7
console.log(a); // 4 (打印结果为 window.a)
console.log(b); // 3 (打印结果为 window.b)
// e.g.2
var user = {
name: 'Echoyya',
age: 27,
greet() {
console.log(this.name)
},
bf: {
name: 'KK.unlock',
greet() {
console.log(this.name)
}
}
} user.greet() // Echoyya
user.bf.greet() // KK.unlock

如果 greet 函数不是 user 对象的函数,只是一个独立的函数。

function greet () {
console.log(this.name)
} var user = { name: 'Echoyya' }

如何能让 greet 方法调用的时候将 this 指向 user 对象?不能再像之前使用 user.greet(),因为 user 并没有 greet 方法。我们可以通过一些方法去改变this的指向

怎样改变 this 的指向

(1)使用ES6中箭头函数

箭头函数中的 this 始终指向函数定义时的 this,而非执行时。箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。

也正因如此,箭头函数不能用于构造函数

var name = "windowsName";

var obj = {
name: "Echoyya",
func1: function () {
console.log(this.name)
},
func2: () => {
console.log(this.name)
}
}; obj.func1() // Echoyya obj.func2() // windowsName

(2)函数内部使用 _this = this

如果不使用 ES6,那么这种方式应该是最简单且不易出错的方式了,先将调用这个函数的对象保存在变量 _this 中,然后在函数中都使用这个 _this

obj调用functhis 指向obj,防止setTimeout 被 window 调用,导致 setTimeout 中的 this 指向 window,设置 var _this = this,将 this(指向变量 obj) 赋值给一个变量 _this,这样,在 func 中使用_this 就指向对象 obj

var name = "windowsName";

var obj = {
name: "Echoyya",
func: function () {
var _this = this;
setTimeout(function () {
console.log(_this.name)
}, 1000);
}
}; obj.func() // Echoyya

(3)使用call,apply,bind方法

call、apply、bind 方法是每个函数都有的一个方法,允许在调用函数时为函数指定上下文。可以改变 this 指向

call 与 apply
  • call 方法,第一个参数会作为函数被调用时的上下文。即this 指向传给 call 的第一个参数。
  • 传递参数给使用 .call 调用的函数时,需要在指定上下文(第一个参数)后一个一个地传入。
  • 语法:fun.call(thisArg [, arg1[, arg2[, ...]]])

站在函数应用的角度我们知道了call与apply的用途,那这两个方法又有什么区别呢,其实区别就一点,参数传递方式不同。

  1. call方法中接受的是一个参数列表,第一个参数指向this,其余的参数在函数执行时都会作为函数形参传入函数。

    • 语法:fn.call(this, arg1, arg2, ...);
  2. 而apply不同的地方是,除了第一个参数作为this指向外,其它参数都被包裹在一个数组中,在函数执行时同样会作为形参传入。

    • 语法:fn.apply(this, [arg1, arg2, ...]);

除此之外,两个方法的效果完全相同:

var o = {
a: 1
}; function fn(b, c) {
console.log(this.a + b + c);
};
fn.call(o, 2, 3); // 6
fn.apply(o, [2, 3]); //6
关于 bind

bind要单独说一下,因为它与call,apply还不太一样。call与apply在改变this的同时,就立刻执行,而bind绑定this后并不会立马执行,而是返回一个新的绑定函数,需要在执行一下。

var o = {
a: 1
}; function fn(b, c) {
console.log(this.a + b + c);
}; var fn2 = fn.bind(o, 2, 3); fn2(); //6
var name = 'windowsName'

function greet () {
console.log(this.name)
} var user = { name: 'Echoyya' } greet() // windowsName
greet.bind()() // windowsName (非严格模式下,默认指向window)
greet.bind(user)() // Echoyya
var obj = {
name: "Echoyya",
func: function () {
setTimeout(function () {
console.log(this.name)
}.bind(obj)(), 100);
}
}; obj.func() // Echoyya
call、apply、bind 区别

call、apply、bind 都是可以改变 this 的指向的,但是这三个函数稍有不同。

var test = {
a: 5,
b: 6,
sum: function (a, b) {
var self = this; function getA() {
return self.a;
} function getB() {
return self.b;
}
console.log(a, b); // call, apply, bind 传入参数
return getA() + getB();
}
}
var obj = {
a: 2,
b: 3
}; console.log(test.sum.call(obj, 4, 5)); // 4,5,5 (self = this = obj)
console.log(test.sum.apply(obj, [6, 7])); // 6,7,5 (self = this = obj)
console.log(test.sum.bind(obj, 8, 9)()); // 8,9,5 (self = this = obj)

apply 和 call 的区别

  • .apply.call 本质相同,他们的区别只是传入的参数不同。

    • 传递参数给使用 .call 调用的函数时,需要在指定上下文(第一个参数)后一个一个地传入(参数列表)。
    • 传递参数给使用 .apply 调用的函数时,可以用数组传参而且 .apply 会在函数中自动展开(参数数组)。

call、apply、bind到底有什么区别?bind返回的方法还能修改this指向吗?

  1. apply与call是函数应用,指定this的同时也将方法执行,bind不同,它只是负责绑定this并返回一个新方法,不会执行。

  2. 尝试打印返回的新函数fn2,可以看到它并不是一个普通的function,而是一个bound function,简称绑定函数

    • TargetFunction 指向 bind 前的函数
    • BoundThis 是绑定的 this 指向
    • BoundArgs 是传入的其它参数了

  3. 当我们执行fn2时,有点类似于TargetFunction.apply(BoundThis,BoundArgs)。可以得出一个结论,当执行绑定函数时,this指向与形参在bind方法执行时已经确定了,无法改变。

  4. bind多次后执行,函数this还是指向第一次bind的对象。

    var o1 = { a: 1 };
    var o2 = { a: 2 }; function fn(b, c) {
    console.log(this.a + b + c);
    }; var fn1 = fn.bind(o1, 2, 3); //尝试再次传入形参
    fn1(4, 4); //6 //尝试改变this
    fn1.call(o2); //6 //尝试再次bind
    fn1.bind(o2, 1, 1)() // 6

其实很好理解,当执行fn1时,本质上等于window.fn1(),如果this还能被改变,那this岂不是得指向window,那bind方法就没太大意义了。

一文搞懂 this、apply、call、bind的更多相关文章

  1. 一文搞懂RAM、ROM、SDRAM、DRAM、DDR、flash等存储介质

    一文搞懂RAM.ROM.SDRAM.DRAM.DDR.flash等存储介质 存储介质基本分类:ROM和RAM RAM:随机访问存储器(Random Access Memory),易失性.是与CPU直接 ...

  2. 基础篇|一文搞懂RNN(循环神经网络)

    基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...

  3. 一文搞懂 Prometheus 的直方图

    原文链接:一文搞懂 Prometheus 的直方图 Prometheus 中提供了四种指标类型(参考:Prometheus 的指标类型),其中直方图(Histogram)和摘要(Summary)是最复 ...

  4. Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

    本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...

  5. 一文搞懂vim复制粘贴

    转载自本人独立博客https://liushiming.cn/2020/01/18/copy-and-paste-in-vim/ 概述 复制粘贴是文本编辑最常用的功能,但是在vim中复制粘贴还是有点麻 ...

  6. 三文搞懂学会Docker容器技术(中)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 6,Docker容器 6.1 创建并启动容器 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] --na ...

  7. 三文搞懂学会Docker容器技术(下)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 三文搞懂学会Docker容器技术(中) 7,Docker容器目录挂载 7.1 简介 容器目录挂载: 我们可以在创建容器的时候,将宿主机的目录与容器 ...

  8. 一文搞懂所有Java集合面试题

    Java集合 刚刚经历过秋招,看了大量的面经,顺便将常见的Java集合常考知识点总结了一下,并根据被问到的频率大致做了一个标注.一颗星表示知识点需要了解,被问到的频率不高,面试时起码能说个差不多.两颗 ...

  9. 一文搞懂 js 中的各种 for 循环的不同之处

    一文搞懂 js 中的各种 for 循环的不同之处 See the Pen for...in vs for...of by xgqfrms (@xgqfrms) on CodePen. for &quo ...

  10. 一文搞懂如何使用Node.js进行TCP网络通信

    摘要: 网络是通信互联的基础,Node.js提供了net.http.dgram等模块,分别用来实现TCP.HTTP.UDP的通信,本文主要对使用Node.js的TCP通信部份进行实践记录. 本文分享自 ...

随机推荐

  1. BIM技术基础-Revit2019建筑

    第三章 三维信息建模(中) 3.5 拉伸屋顶的创建 拉伸屋顶→ 在立面中创建,屋顶的形状在垂直截面上一致的 利用参照平面或者已有的墙面或者已有的轴线 3.5.1利用拾取平面创建 画一个参照平面作为屋檐 ...

  2. HDU 4628 Pieces(状压DP)题解

    题意:n个字母,每次可以删掉一组非连续回文,问你最少删几次 思路:把所有回文找出来,然后状压DP 代码: #include<set> #include<map> #includ ...

  3. gradle中的build script详解

    目录 简介 project和task 一个例子 task详细讲解 task脚本 task依赖 动态task 默认task build script的外部依赖 gradle中的build script详 ...

  4. js中当for循环中有事件要使用循环变量时,变量用var声明和let声明的区别

    var 声明一个全局变量,声明的变量会变量提升: let 声明一个局部变量: 当页面加载完后,for循环也结束了,如果用var声明的变量此时也随着for循环的结束而自增到满足结束循环的条件, 此时调用 ...

  5. UA 广告 All In One

    UA 广告 All In One UA 广告是什么 广告投放 / 市场营销 互联网营销和分析专用名词速览 http://www.chinawebanalytics.cn/digital-marketi ...

  6. Dart DevTools & Flutter

    Dart DevTools & Flutter https://flutter.dev/docs/development/tools/devtools/overview https://dar ...

  7. code magic

    code magic CI/CD for mobile app projects https://codemagic.io https://codemagic.io/apps flutter http ...

  8. Azure 计费 & 成本管理 & 取消 Azure 订阅

    Azure 计费 & 成本管理 & 取消 Azure 订阅 https://docs.microsoft.com/zh-cn/azure/cost-management-billing ...

  9. javascript disable scroll event

    javascript disable scroll event Document: scroll event https://developer.mozilla.org/en-US/docs/Web/ ...

  10. USDN代币发行 关于USDN代币

    "稳定币"是数字货币的一种,但与主流币存在的差异是,它可以通过锚定法币和加密资产等手段来维持币价的相对稳定.提及稳定币,一般会先介绍三种模式: 法币托管模式.数字资产抵押模式和无抵 ...