"this"和普通函数
以下内容 摘自https://www.w3cschool.cn/ivmkf/ivmkf-v3y2250z.html
和https://classroom.udacity.com/nanodegrees/nd001-cn-preview/parts/63e29129-49ba-41cf-87d6-f98246da3f24/modules/166575d1-e43b-4cbf-90da-26c36c6b3c96/lessons/c867d0a9-1ee7-48ce-8275-e0dfb1cf013e/concepts/654cbc3e-5081-49e3-a17e-86198de93db6
和https://classroom.udacity.com/nanodegrees/nd001-cn-preview/parts/63e29129-49ba-41cf-87d6-f98246da3f24/modules/166575d1-e43b-4cbf-90da-26c36c6b3c96/lessons/c867d0a9-1ee7-48ce-8275-e0dfb1cf013e/concepts/32f53f68-4b31-40fb-b136-4eda28b8ff57
要了解箭头函数中的 this
有何区别,让我们快速总结下标准函数中的 this
是如何使用的。如果你已经非常熟悉this
的使用方法,可以跳过此部分。
(与我们常见的很多语言不同,JavaScript 函数中的 this
指向并不是在函数定义的时候确定的,而是在调用的时候确定的。换句话说,函数的调用方式决定了 this
指向。
JavaScript 中,普通的函数调用方式有三种:直接调用、方法调用和 new
调用。除此之外,还有一些特殊的调用方式,比如通过 bind()
将函数绑定到对象之后再进行调用、通过 call()
、apply()
进行调用等。而 es6 引入了箭头函数之后,箭头函数调用时,其 this
指向又有所不同。下面就来分析这些情况下的 this
指向
直接调用
直接调用,就是通过 函数名(...)
这种方式调用。这时候,函数内部的 this
指向全局对象,在浏览器中全局对象是 window
,在 NodeJs 中全局对象是 global
。
这里需要注意的一点是,直接调用并不是指在全局作用域下进行调用,在任何作用域下,直接通过 函数名(...)
来对函数进行调用的方式,都称为直接调用。
bind() 对直接调用的影响
还有一点需要注意的是 bind()
的影响。Function.prototype.bind()
的作用是将当前函数与指定的对象绑定,并返回一个新函数,这个新函数无论以什么样的方式调用,其 this
始终指向绑定的对象。
const obj = {};
function test() {
console.log(this === obj);}
const testObj = test.bind(obj);
test(); // false
testObj(); // true
call 和 apply 对 this 的影响
上面的示例中用到了 Function.prototype.apply(),与之类似的还有 Function.prototype.call()。这两方法的用法请大家自己通过链接去看文档。不过,它们的第一个参数都是指定函数运行时其中的 this
指向。
不过使用 apply
和 call
的时候仍然需要注意,如果目录函数本身是一个绑定了 this
对象的函数,那 apply
和 call
不会像预期那样执行,
const obj = {};
function test() {
console.log(this === obj);
}
// 绑定到一个新对象,而不是 obj
const testObj = test.bind({});
test.apply(obj); // true
// 期望 this 是 obj,即输出 true
// 但是因为 testObj 绑定了不是 obj 的对象,所以会输出 false
testObj.apply(obj); // false
由此可见,bind()
对函数的影响是深远的,慎用!
方法调用
方法调用是指通过对象来调用其方法函数,它是 对象.方法函数(...)
这样的调用形式。这种情况下,函数中的 this
指向调用该方法的对象。但是,同样需要注意 bind()
的影响
方法中 this 指向全局对象的情况
注意这里说的是方法中而不是方法调用中。方法中的 this
指向全局对象,如果不是因为 bind()
,那就一定是因为不是用的方法调用方式,比如
const obj = {
test() {
console.log(this === obj);
}};
const t = obj.test;
t(); // false 这里就是相当于直接调用
t
就是 obj
的 test
方法,但是 t()
调用时,其中的 this
指向了全局。
箭头函数中的 this
箭头函数没有自己的 this
绑定。箭头函数中使用的 this
,其实是直接包含它的那个函数或函数表达式中的 this
不管在什么情况下使用箭头函数,它本身是没有绑定
this
的,它用的是直接外层函数(即包含它的最近的一层函数或函数表达式)绑定的 this
示例中的两个 this
都是由箭头函数的直接外层函数(方法)决定的,而方法函数中的 this
是由其调用方式决定的。上例的调用方式都是方法调用,所以 this
都指向方法调用的对象,即 obj
。
箭头函数让大家在使用闭包的时候不需要太纠结 this
,不需要通过像 _this
这样的局部变量来临时引用 this
给闭包函数使用。
)
this
关键字的价值完全取决于它的函数(或方法)是如何被调用的。this
可以是以下任何内容:
1. 新的对象
如果函数使用 new
被调用:
const mySundae = new Sundae('Chocolate', ['Sprinkles', 'Hot Fudge']);
在上述代码中,Sundae
这个构造函数内的 this
的值是新的对象,因为它使用 new
被调用。
2. 指定的对象
如果函数使用 call
/apply
被调用:
const result = obj1.printName.call(obj2);
在上述代码中,printName()
中的 this
的值将指的是 obj2
,因为 call()
的第一个参数明确设定 this
指代的是什么。
3. 上下文对象
如果函数是对象方法:
data.teleport();
在上述代码中,teleport()
中的 this
的值将指代 data
。
4. 全局对象或 undefined
如果函数被调用时没有上下文:
teleport();
在上述代码中,teleport()
中的 this
的值是全局对象,如果在严格模式下,是 undefined
。