我正在参加「掘金·启航计划」
看过《你不知道的JavaScript》这本书都应该知道,书中简述四种this指向分为:(重要的事情说三次:重点不在这里!,在后文!,在后文!,在后文!)
-
默认绑定:在
"use strict"下this指向undefined,否则指向默认全局对象window。function foo() { console.log(this);// window对象,默认绑定:指向全局对象 } foo();function foo() { "use strict" console.log(this);// window对象,默认绑定:指向全局对象 } foo(); -
隐式绑定:调用位置是否有上下文。
function foo() { console.log(this);// 指向obj对象 } var obj = { a: 1, foo: foo } obj.foo(); -
显式绑定:也就是带有call、apply、bind的强制指定this指向的绑定。
function foo() { console.log(this);// 指向window对象 } var obj = { a: 1, foo: foo } obj.foo.call(this); -
new 绑定:构造函数的this指向的是自己。注意地,
new创建构造函数不能改变this指向。function foo() { console.log(this);// 指向foo{}函数 } const bar = new foo();
1 函数调用
在js中有四种函数的调用形式:
function foo(a1,a2){};// 全局对象函数调用
obj.attr.method(a1,a2){};// 对象函数调用
new foo();// 构造函数调用
foo = ()=>{};// 箭头函数
foo.call(context,a1,a2);// 函数上下文调用
构造函数、箭头函数都是es6语法糖的,而全局函数与对象函数都是es5语法糖,而函数上下文调用才是真正的函数调用。
-
箭头函数:箭头函数本身是不支持this,所以内部并没有this,直接把它当作箭头函数外面的this即可。
const foo = () => { console.log(this);// 指向window } foo(); -
构造函数:注意地,构造函数绑定的this是不能改变的。
function foo(a, b) { this.a = a; this.b = b; return { key: this// 指向foo{ } 函数 } } const bar = new foo(); console.log(bar);
全局函数与对象函数都能转换为上下文调用函数,我们也可以从上下文调用的方式去理解这个this的指向:
-
全局函数:严格模式,this指向就是undefined,非严格模式,this指向就是window。
function foo() { console.log(this);// 指向window } foo(); // 等价于 foo.call(); // 等价于 foo.call(undefined); // 等价于 foo.call(null);从上面可以看出上下文调用函数call,
call的第一个参数context值有为空、undefined、null,最终的指向都是全局window对象。为什么?浏览器中规定,如果是在严格模式下使用this绑定的话,默认是undefined;如果在非严格模式下的this没有指向默认为window对象。context的值为有为空、undefined、null时,this指向都是window。也就是说,call的第一个参数context就是this。 -
对象属性函数:this指向的是调用函数前的对象,比如下面转化为上下文函数调用后this分别指向的是obj、obj.obj1。也就是说,
call的第一个参数context就是this。function foo() { console.log(this);// 指向obj } const obj = { a: 1, foo: foo, } obj.foo(); // 等价于或转化为 obj.foo.call(obj);function foo() { console.log(this);// 指向obj1 } const obj = { a: 1, obj1: { a: 2, foo: foo, }, } obj.obj1.foo(); // 等价于或转化为 obj.obj1.foo.call(obj.obj1);
2 数组中函数属性
- 数组中的函数foo,arr[0].foo,我们可以
假想为arr.0(),也就是说0类似于obj.foo调用函数,所以可以假想转化为arr.0.call(arr),所以context值就是arr,this指向的就是arr。function foo() { console.log(this);// 指向arr } const arr = [foo] arr[0]();