关于this,总结起来,主要有以下几个途径能够被运用到。
1 对象方法中调用this:如果函数被当中对象的一个方法进行调用,则this值指向该对象。
var person = {
name: 'Alice',
sayName: function() {
alert('welcome ' + this.name);
}
}
person.sayName(); // this == person, alert: 'welcome Alice'
在这里,函数的this指向该对象(即 person);但是有一点需要注意,就是当对象的方法被赋予给一个变量时,其则变为了函数触发,此时的this为 window 或者 undefined(严格模式下),如下:
var person = {
name: 'Alice',
sayName: function () {
alert('welcome ' + this.name);
}
}
var name = 'Bob';
var say = person.sayName; // this == window || undefined
say(); // 'welcome Bob' || throw an error: Cannot read property 'name' of undefined(...)
2 函数内部使用
在函数内部当中使用了 this,即函数被当做方法使用,不同于 1 当中作为对象的方法使用,此时调用,是在全局作用域下进行调用,即在window下进行调用,由定义可以知道,在全局作用域下声明一个函数,其自动加为window的一个属性。this此时名正言顺的会指向window,严格模式下为 undefined
function sayThis() {
alert(this == window); // true
}
sayThis()
结合第一点,函数作为对象的一个方法使用,这里存在一个小坑,即闭包;第一点当中存在一个小坑,就是将对象的方法赋予给一个变量的时候,其变为函数触发,此时的 this 实际上是指向 window(非严格模式)。
那么,当函数中返回一个函数,此时在对象当中调用该方法,其就相当于是函数触发,此时的 this,在不做任何上下文绑定的前提之下,其指向 window(非严格模式)。
var name = 'Bob',
person = {
name: 'Alice',
sayName: function() {
console.log(this === person); // true
return function() {
console.log(this === person); // false
console.log(this === window); // true
console.log(this.name); // Bob
};
}
};
person.sayName()();
当然,要解决这个问题的方法,很简单,就是给他绑定一个上下文。
var name = 'Bob',
person = {
name: 'Alice',
sayName: function() {
console.log(this === person); // true
return function() {
console.log(this === person); // true
console.log(this === window); // false
console.log(this.name); // Alice
}.bind(this);
}
};
person.sayName()();
3 new 当中进行使用
我们知道在使用 new 方法创建对象的时候,会经过如下这些个过程:
- 创建对象,将 this 值赋予新的对象
- 调用构造函数,为 this 添加属性和方法
- 返回 this 给当前的对象
function Person(name, age) {
this.name = name;
this.age = age;
}
var person1 = new Person('Alice', 29);
console.log(person1.name); // Alice
这里要记得使用 new 运算符,否则,其只能算是普通的调用,而不是创建一个新的实例对象。而当做普通函数调用的话,实际上即 第 2 种情况下,对函数普通调用,此时的 this 指向 window
function Person(name, age) {
this.name = name;
this.age = age;
return {
name: 'Bob'
};
}
var person1 = new Person('Alice');
console.log(person1.name); // Bob
console.log(person1.age); // undefined
4 使用 call、apply 或 bind 改变 this
使用 apply
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.apply(a),100);
}
};
a.func2() // Cherry
使用 call
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.call(a),100);
}
};
a.func2() // Cherry
使用 bind
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.bind(a)(),100);
}
};
a.func2() // Cherry
apply、call、bind 区别:
apply() 语法:fun.apply(thisArg, [argsArray])
call()语法:fun.call(thisArg[, arg1[, arg2[, …]]])
所以 apply 和 call 的区别是 call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.apply(a,[1,2]) // 3
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.call(a,1,2) // 3
bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
bind 是创建一个新的函数,我们必须要手动去调用:
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.bind(a,1,2)() // 3
5 箭头函数
众所周知,ES6 的箭头函数是可以避免 ES5 中使用 this 的坑的。箭头函数的 this 始终指向函数定义时的 this,而非执行时。,箭头函数需要记着这句话:“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。
var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( () => {
this.func1()
},100);
}
};
a.func2() // Cherry