参考《你不知道的JavaScript》和《JavaScript》忍者秘籍中有关this指向问题,第一次写记录下学习的内容,主要是为了方便下次复习和提供给其他想了解相关知识的同学。有不太好的地方希望大家多包容
this指向谁??
既不指向函数本身也不指向作用域, this是函数执行上下文,在运行时绑定,根据函数的调用方式决定。
绑定规则
1、默认规则 - 函数直接调用
- 严格模式下this指向undefined
function foo() {
"use strict";
console.log(this); //undefined
}
var a = 2;
foo();
- 非严格模式浏览器环境下this指向window
2、隐式规则 - 函数作为对象的方法调用 此时this指向对象
注意:回调中this丢失的问题
3、显示规则 - 通过call、apply、bind显示指定this
三者的区别:call 和 apply传递参数形式不同
- 函数名.call(显示指定this绑定的对象,arg1,arg2...),call传入参数列表
-
函数名.apply(显示指定this绑定的对象,[arg1,arg2...]) apply传入参数数组
-
bind会返回新的函数,它会把指定的参数设置为this的上下文并调用原始函数
bind可以把除了第一个参数(第一个参数用于绑定this)之外的其他参数都传给下层的函数(这种技术称为“部分应用”,是“柯里化”的一种)
function foo(p1, p2) {
this.val = p1 + p2;
}
var bar = foo.bind(null, "p1");
var baz = new bar("p2");
console.log(baz.val); // p1p2
foo.bind(null, "p1")返回新的函数bar, 通过new bar()传入剩下的参数。
4、new绑定 - this指向创建的对象
function foo(a) {
this.a = a;
}
var bar = new foo(3); //新创建的bar绑定到foo里的this
console.log(bar.a); //3
执行new 构造函数过程:
- 创建一个新的空对象
- 空对象的原型指向构造函数的原型
- 空对象作为构造函数的上下文(改变this指向)
- 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
箭头函数的this指向
不满足以上规则,箭头函数根据外部作用域来决定this
function foo() {
return (a) => {
console.log(this.a); //2
};
}
var obj1 = {
a: 2,
};
var obj2 = {
a: 3,
};
var bar = foo.call(obj1); //foo的this指向obj1,箭头函数里的this也指向obj1
console.log(bar);
bar.call(obj2);
var bar = foo.call(obj1); foo.call(obj1)将obj1显示指定foo内部的this,箭头函数的this也指向obj1
绑定规则的优先级
new绑定 > call、bind、apply显示绑定 > 隐式绑定 > 默认绑定
- 如何证明new的优先级比bind高
function foo(something) {
this.a = something;
}
var obj1 = {};
var bar = foo.bind(obj1); //obj1传递到foo内作为this
bar(2);
console.log(obj1.a); //2
var baz = new bar(3);
console.log(obj1.a); //2
console.log(baz.a); //3
var baz = new bar(3)将baz传递给bar内部作为函数上下文this, bar是foo.bind(obj1)返回的新函数,此时显式指定obj1为foo的上下文。先后使用了new和bind改变this的指向,结果证明new的优先级高于bind。
- 如何证明显示绑定高于隐式绑定, 使用call显示调用 vs 对象方法名调用
function foo() {
console.log(this.a);
}
var obj1 = {
a: 2,
foo: foo,
};
var obj2 = {
a: 3,
foo: foo,
};
//隐式规则
obj1.foo(); //2
obj2.foo(); //3
obj1.foo.call(obj2); //3,显示指定obj2作为this
obj2.foo.call(obj1); //2,显示指定obj1作为this
- 如何证明new高于隐式绑定
function foo(something) {
this.a = something;
}
var obj1 = {
foo: foo,
};
var obj2 = {};
obj1.foo(2);
console.log(obj1.a); //2 隐式绑定
var bar = new obj1.foo(4); //new绑定
console.log(obj1.a); //2
console.log(bar.a); //4
var bar = new obj1.foo(4); 先通过new改变this指向bar,再使用隐式绑定obj1.foo()。结果显示obj1.a的值还是2没有改变,而bar.a的值是4,说明new的优先级高于隐式绑定。