箭头函数是ES6的新函数类型,与普通函数不同的是,箭头函数本身没有 this 指针的,必须通过查找作用域来决定,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this
- 在非严格模式下,函数中的 this 是指向的是 window
- 在严格模式下,函数中的 this 指向的是 undefined,但是全局中的 this 还是指向 window
- 使用 let、const 来定义变量并不会绑定到 window 中
一.普通函数
对于普通函数,函数调用时的 this 默认绑定 window,函数可以访问 window 下的全局变量
var c=1
function bar() {
var c = 11;
console.log(c);
console.log(this.c);
function inner() {
console.log(c);
console.log(this.c)
};
inner();
}
bar() // 11, 1, 11, 1
let d = 1
function bak() {
let d = 11;
console.log(d);
console.log(this.d);
function innerh() {
console.log(d);
console.log(this.d)
};
innerh();
}
bak() // 11, undefined, 11, undefined
- let、const 来定义变量并不会绑定到 window 中
- 函数不管套了几层,只要不是箭头函数,默认绑定的 this 始终是 window
- 若有对象调用函数,函数中的 this 就会隐式的绑定到对象上。 this 始终指向函数被调用前的最近的对象,因为可能有嵌套子对象,这时哪个对象最后调用函数,那函数就指向谁。
function foo() {
console.log(this.name);
}
var obj1 = {
name: "obj1",
foo: foo
};
var obj2 = {
name: "obj2",
obj1: obj1
};
obj2.obj1.foo(); // obj1
注: 在函数赋值给变量时,会丢失函数原来绑定对象,将函数作为参数传递时也会丢失绑定对象
function foo () {
console.log(this.a)
}
var obj = { a: 1, foo };
var a = 2;
var foo2 = obj.foo;
obj.foo(); // 1 这是 foo() 函数中的 this 指针指向的是 obj 这个对象
foo2(); // 2 当把 foo() 函数赋值给另一个变量时,foo绑定的obj对象已丢失,所以默认指向了 window
- 普通函数的 this 指向通过call、apply、bind 等方法来强行更改
function foo () {
console.log(this.a)
}
var obj = { a: 1 };
var a = 11;
foo(); // 11 this指向 window
foo.call(obj); // 1 this强行指向 obj 对象
foo.apply(obj); // 1
foo.bind(obj) // 不会执行,只是创建了一个函数,没有调用
foo.bind(obj)(); // 1 这样才会执行
- new 绑定会构造一个新对象并把这个新对象绑定到调用函数中的this
function Person (name) {
this.name = name;
this.foo1 = function () {
console.log(this.name);
};
this.foo2 = function () {
return function () {
console.log(this.name);
}
}
}
var name = 'window';
var person1 = new Person('object');
person1 // Person { name: "object", foo1: ƒ, foo2: ƒ }
person1.foo1() // object
person1.foo2()() // window 指针指向了 window
二. 箭头函数
与普通函数不同的是,箭头函数本身没有 this 指针的,必须通过查找作用域来决定,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined
var name = 'window';
function Person (name) {
this.name = name
this.foo1 = function () {
console.log(this.name);
}
this.foo2 = () => {
console.log(this.name);
}
}
var person2 = {
name: 'person2',
foo2: () => {
console.log(this.name)
}
}
var person1 = new Person('person1');
person1.foo1(); //person1
person1.foo2(); //person1 因为new Person后,person1的this指向了Person了
person2.foo2(); //window 没有使用new操作符,因为箭头函数this向外查找,找到window
箭头函数的this是无法通过 bind、call、apply 来直接修改,但是可以通过改变作用域中 this 的指向来间接修改
var name = 'window';
var obj1 = {
name: 'obj1',
foo1: function () {
console.log(this.name);
return () => {
console.log(this.name);
}
},
foo2: () => {
console.log(this.name);
return function () {
console.log(this.name);
}
}
}
var obj2 = {
name: 'obj2',
}
obj1.foo1.call(obj2)();
//obj2 obj2 -call改变了foo1的this指向,内部的箭头函数也会跟着改
obj1.foo1().call(obj2);
//obj1 obj1 -call无法改变箭头函数的this指向
obj1.foo2.call(obj2)();
//window window -call函数对箭头函数无效
obj1.foo2().call(obj2);
//window obj2 -foo2箭头函数内部是一个普通函数,因此能够改变this指向
总结:
- 函数里面的this是由外层作用域来决定的,且指向函数定义时的this而非执行时
- 创建的对象普通函数,默认作用域是 window,如果里面有箭头函数属性的话,this 指向的是 window
- 构造函数创建的对象,作用域是可以理解为是这个构造函数,且这个构造函数的 this 是指向新建的对象的,因此 this 指向这个对象
- 箭头函数的 this 是无法通过 bind、call、apply 来直接修改,但是可以通过改变作用域中 this 的指向来间接修改