this指向规则
函数在执行过程中的调用位置决定this的指向
一、默认绑定(独立函数调用)
函数直接使用不带任何修饰的函数引用进行调用
function foo() {
console.log(this.a);
}
var a = 2;
foo(); // 2
函数直接使用不带任何修饰的函数引用进行调用 function foo() {
console.log(this.a);
}
var a = 2;
foo(); // 2
但是如果使用严格模式,则this指向的是undefined,而不是全局对象
function foo() {
"use strict";
console.log(this); // undefined
console.log(this.a);
}
var a = 2;
foo(); // TypeError: this is undefined
foo只有在严格模式下运行this才会指向undefined,如果只是在严格模式下调用foo则不影响
function foo() {
console.log(this.a);
}
var a = 2;
(function() {
"use strict";
foo(); // 2
})();
二、隐式绑定
当函数引用有上下文对象时,隐式绑定规则会使函数调用中的this指向这个上下文对象
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
对象属性引用链中只有最后一层在调用位置中起作用
function foo() {
console.log(this.a);
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
当函数引用有上下文对象时,隐式绑定规则会使函数调用中的this指向这个上下文对象 function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
对象属性引用链中只有最后一层在调用位置中起作用
function foo() {
console.log(this.a);
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
隐式丢失
- 函数别名调用
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
var bar = obj.foo; // 只是函数的一个别名而已
var a = "global";
bar(); // global(此时bar其实是一个不带任何修饰的调用调用)
- 函数作为入参调用
function doFoo(fn) {
fn();
}
var obj = {
a: 2,
foo: foo
};
var a = "global";
doFoo(obj.foo); // "global"
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
var bar = obj.foo; // 只是函数的一个别名而已
var a = "global";
bar(); // global(此时bar其实是一个不带任何修饰的调用调用)
function doFoo(fn) {
fn();
}
var obj = {
a: 2,
foo: foo
};
var a = "global";
doFoo(obj.foo); // "global"
三、显示绑定
直接指定this的指向
额外知识点:装箱 传入一个原始值作为this的指向,这个原始值会被转换为它的对象形式
function foo() {
console.log(this);
}
foo.call(2); // Number {2}
foo.call("a"); // String {"a"}
直接指定this的指向额外知识点:装箱 传入一个原始值作为this的指向,这个原始值会被转换为它的对象形式
function foo() {
console.log(this);
}
foo.call(2); // Number {2}
foo.call("a"); // String {"a"}
apply, call, bind, 使用这种方式改变this的指向时,无论之后如何调用函数,this的指向都会是这三种方式改变的那个对象
四、new绑定
使用new来调用函数时,会构造一个新对象,并把this指向该对象
- 创建一个新对象
- 链接到原型(使该对象的__proto__等于构造函数的prototype), 可以访问到构造函数原型中的属性
- this指向该对象
- 如果函数没有返回其他对象,那么new表达式中的函数会自动返回这个新对象
使用new来调用函数时,会构造一个新对象,并把this指向该对象判断this
- 函数是否通过new 调用,如果是的话this指向新对象
var bar = new foo() - 函数是否通过call,apply或硬绑定调用,如果是的话this指向绑定的对象
var bar = foo.call(obj2) - 函数是否通过对象调用,是的话指向这个对象
var bar = obj1.foo() - 如果都不是的话,就是默认绑定,在严格模式下,this就指向undefined,否则指向全局对象
var bar = foo()
var bar = new foo()var bar = foo.call(obj2)var bar = obj1.foo()var bar = foo()特殊情况
- 如果把null和undefined作为call、apply或者bind的第一个参数,这些值在调用时会被忽略,实际是默认绑定
function foo() {
console.log(this.a);
}
var a = 2;
foo.call(null); // 2
应用:把数组展开为参数
foo.apply(null, [2, 3]);
- 间接引用
function foo() {
console.log(this.a);
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2 (这里调用的直接是foo())
- 箭头函数 根据外层(函数或全局)作用域来决定,会继承外层函数内的this指向
function foo() {
console.log(this.a);
}
var a = 2;
foo.call(null); // 2
应用:把数组展开为参数
foo.apply(null, [2, 3]);
function foo() {
console.log(this.a);
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2 (这里调用的直接是foo())