函数内的this值可以根据函数调用时的上下文而改变,也就是俗称的谁调用就指向谁。
即只有函数执行,才有this指向。
如下4个绑定规则,越往下优先级越高。(前提:以下代码都是在浏览器环境下)
- 默认绑定规则
全局执行期上下文的this指向window
console.log(this === window); //true
函数的独立调用,默认的函数执行期上下文指向window
function test(){
console.log(this === window); //true
}
test();
var obj = {
foo: function () {
console.log(this); //obj
function test() {
console.log(this); //window
}
//函数独立调用,注意
return test;
}
}
obj.foo()();
预编译的过程中,实参被赋值为形参,值的拷贝是浅拷贝
function foo(){
console.log(this); //window
}
function bar(fn){
fn();
}
var obj = {
foo
}
bar(obj.foo);
- 隐式绑定规则
对象的方法调用
var obj = {
foo: function () {
console.log(this); //obj
function test() {
console.log(this); //window
}
//函数独立调用,注意
test();
}
}
obj.foo();
function foo(){
console.log(this); //obj
}
var obj = {
foo: foo
}
obj.foo();
---------------------------------
function foo(){
console.log(this); //window
}
var obj = {
foo: foo
}
var bar = obj.foo;
//独立调用
bar();
隐式丢失,立即执行函数,this指向window
(function(){
console.log(this); //window
})();
API接口中指明的
父函数有能力决定子函数的this指向
var arr = [1, 2, 3];
arr.forEach(function(item, idx, arr){
console.log(this);
}, this);
- 显示绑定:
call、apply、bind都是改变this指向
区别:1、传参方式不同,apply以数组形式穿参
2、bind不立即执行
fn.call(this, arg1, arg2, ...);
fn.apply(this, [arg1, arg2, ...]);
fn.bind(this)(arg1, arg2, ...);
function foo(a, b){
console.log(a, b);
console.log(this);
}
var obj = {
foo
}
var bar = obj.foo;
//this指向window
bar(1, 2);
//this指向obj
obj.foo(1, 2);
bar.call(obj, 1, 2);
bar.apply(obj, [1, 2]);
bar.bind(obj)(1, 2);
//绑定原始值,会找相应包装类
//null与undefined没有包装类,绑定失败,
bar.call(null); //window
bar.apply(undefined); //window
bar.bind(1)(); //Number{1}
- new 绑定规则
function foo(b) {
this.a = b;
}
var obj = {};
var bar = foo.bind(obj);
bar(2);
//var bar = function foo(b){ this.a = b; }
console.log(obj.a);
var baz = new bar(3);
console.log(obj.a);
console.log(baz.a);
箭头函数,ES6语法
所有绑定规则对箭头函数不适用,即没有this绑定,其this指向由外层非箭头函数。
var name = 'window';
var obj1 = {
name: '1',
fn1: function () {
console.log(this.name)
},
fn2: () => console.log(this.name),
fn3: function () {
return function () {
console.log(this.name)
}
},
fn4: function () {
return () => console.log(this.name)
}
}
var obj2 = {
name: '2'
};
obj1.fn1(); //1
obj1.fn1.call(obj2); //2
obj1.fn2(); //window
obj1.fn2.call(obj2); //window
obj1.fn3()(); //window
obj1.fn3().call(obj2); //2
obj1.fn3.call(obj2)(); //window
obj1.fn4()(); //1
obj1.fn4().call(obj2); //1
obj1.fn4.call(obj2)(); //2