JS中的this
本文从两方面讨论this:常规函数和箭头函数
首先明确:this指向JavaScript实例,因此只有在函数调用时才可以确定下来,而在函数声明时是无法确定的!
一、全局中的this
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。
// 在浏览器中, window 对象同时也是全局对象:console.log(this === window); // true
二、常规函数中的this
1.纯粹的函数调用
1 //----------------------------example1------------------------------- 2 // 非严格模式下 3 function f1(){ 4 return this; 5 } 6 //在浏览器中: 7 f1() === window; //在浏览器中,全局对象是window 8 9 //在Node中: 10 f1() === global; // true 11 12 //----------------------------example2------------------------------- 13 // 严格模式下 14 function f2(){ 15 "use strict"; // 这里是严格模式 16 return this; 17 } 18 19 f2() === undefined; // true 此处的this为undefined是因为f2是直接被调用的,而不是作为某个对象的方法(如 window.f2())被调用。 20 21 //----------------------------example3------------------------------- 22 // 将一个对象作为call和apply的第一个参数,this会被绑定到这个对象。 23 var obj = {a: 'Custom'}; 24 25 // 这个属性是在global对象定义的。 26 var a = 'Global'; 27 28 function whatsThis(arg) { 29 return this.a; // this的值取决于函数的调用方式 30 } 31 32 whatsThis(); // 写法1,严格模式为undefined,非严格模式为'Global' 33 whatsThis.call(undefined); // 写法2,严格模式为undefined,非严格模式为'Global' 34 whatsThis.call(obj); // 可指定this,'Custom' 35 whatsThis.apply(obj); // 可指定this,'Custom' 36 whatsThis.bind(obj)(); // 可绑定this,'Custom' 37 whatsThis.bind(obj).bind({a: 'aHhha'})(); // this只可绑定一次,'Custom'
上面的写法1和写法2是等价的,写法1是写法2 的语法糖。
写法2中call方法接收的第一个参数就是this,这里传了一个undefined,此时有如下定义:
如果你传的 context 是 null 或者 undefined,那么非严格模式下, window 对象(浏览器)或global(Node)就是默认的 context,严格模式下默认 context是 undefined。
2.对象中的函数的this
当函数作为对象里的方法被调用时,它们的 this 是调用该函数的对象。最靠近的引用优先级最高。
1 var o = {prop: 37}; 2 3 function independent() { 4 return this.prop; 5 } 6 7 o.f = independent; 8 9 console.log(o.f()); // logs 37, 函数调用关系为从o的f成员调用 10 11 o.b = {g: independent, prop: 42}; 12 console.log(o.b.g()); // 42 最靠近的引用优先级最高 13 console.log(o.f.call({prop: 53})); // 使用call可改变this
3.构造函数中的this
当函数作为构造函数被new返回一个对象时,该对象即为this。
1 function C(){ 2 this.a = 37; 3 } 4 5 var o = new C(); 6 console.log(o.a); // logs 37 7 8 9 function C2(){ 10 this.a = 37; 11 return {a:38}; 12 } 13 14 o = new C2(); 15 console.log(o.a); // logs 38
4.作为DOM元素的监听处理函数的this
当函数被作为DOM元素的监听处理函数时,它的this指向监听器所在的DOM元素,但只有最外层代码中的this是这样的:
1 <button onclick="alert(this.tagName.toLowerCase());"> <!-- button --> 2 Show this 3 </button> 4 <button onclick="alert((function(){return this})());"> <!-- 非严格模式下指向global/window --> 5 Show inner this 6 </button>
5.window.setTimeout()和window.setInterval()的this
window.setTimeout()和window.setInterval()的函数中的this默认是window对象。
总结:常规函数中,有以下总结:
this只有在函数被调用时才能确定下来,this指向调用函数的对象;this最靠近的引用优先级最高;可以用call()或bind()指定this;构造函数的this指向new返回的对象;DOM元素的监听处理函数的this指向监听器所在的DOM元素;window.setTimeout()和window.setInterval()的函数中的this默认是window对象。
三、箭头函数的this
1.箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。
1 function Person() { 2 // Person() 构造函数定义 `this`作为它自己的实例. 3 this.age = 0; 4 5 setInterval(function growUp() { 6 // 在非严格模式, growUp()函数定义 `this`作为全局对象, 7 // 与在 Person()构造函数中定义的 `this`并不相同. 8 this.age++; 9 console.log(this.age) //NAN 10 }, 1000); 11 } 12 13 var p = new Person();
1 function Person(){ 2 this.age = 0; 3 4 setInterval(() => { 5 this.age++; // |this| 正确地指向 p 实例,继承作用域链 箭头函数=>Person 6 }, 1000); 7 } 8 9 var p = new Person();
2.箭头函数不能用call()指定this
1 const obj = { 2 a: () => { 3 console.log(this) 4 } 5 } 6 obj.a.call('123') //window,继承作用域链 箭头函数=>window
3.箭头函数不能用bind()指定this
1 var globalObject = this; 2 var foo = (() => this); 3 var obj = {foo: foo}; 4 foo = foo.bind(obj); 5 console.log(foo() === globalObject); // true
总结:箭头函数中,有以下总结:
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this;箭头函数不能用call()或bind()指定this。
欢迎留言交流。
本文参考:
https://juejin.im/post/5aa1eb056fb9a028b77a66fd
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arrow_functions
2019.9.12
yangqianqian