this是什么?
this是一个指针,指向调用函数的对象。
this的绑定规则:
- 默认绑定
- 隐式绑定
- 显式绑定
- new绑定
默认绑定 fun()
默认绑定,在不能应用其它绑定规则时使用的默认规则,通常是独立函数调用。
function sayHi(){
console.log('Hello,', this.name);//hello,curry或者undefined
}
var name = 'curry';
sayHi();
在调用Hi()时,应用了默认绑定,this指向全局对象(非严格模式下),严格模式下,this指向undefined,undefined上没有this对象,会抛出错误。
隐式绑定 obj.fun()
函数的调用时在某个对象上触发的。
function sayHi(){
console.log('Hello,', this.name);
}
var person = {
name: 'YvetteLau',
sayHi: sayHi
}
var name = 'Wiliam';
person.sayHi();//hello,YvetteLau
需要注意的是:对象属性链中只有最后一层会影响到调用位置。
function sayHi(){
console.log('Hello,', this.name);
}
var person2 = {
name: 'Christina',
sayHi: sayHi
}
var person1 = {
name: 'YvetteLau',
friend: person2
}
person1.friend.sayHi();//hello,chirstina
隐式绑定有一个大陷阱,绑定很容易丢失
function sayHi(){
console.log('Hello,', this.name);
}
var person = {
name: 'YvetteLau',
sayHi: sayHi
}
var name = 'William';
var Hi = person.sayHi;
Hi();//hello,william
Hi直接指向了sayHi的引用,在调用的时候,跟person没有半毛钱的关系.
fun()前面如果什么都没有,那肯定不是隐式绑定。
除了上面这种丢失之外,隐式绑定的丢失是发生在回调函数中(事件回调也是其中一种),eg:
function sayHi(){
console.log('Hello,', this.name);
}
var person1 = {
name: 'YvetteLau',
sayHi: function(){
setTimeout(function(){
console.log('Hello,',this.name);
})
}
}
var person2 = {
name: 'Christina',
sayHi: sayHi
}
var name='Wiliam';
person1.sayHi();
setTimeout(person2.sayHi,100);
setTimeout(function(){
person2.sayHi();
},200);
结果为:
Hello, Wiliam
Hello, Wiliam
Hello, Christina
- 第一条,
setTimeout的回调函数,this使用的是默认绑定,非严格模式下,指向全局对象。 - 第二条,
setTimeout(fn, delay){fun();}, 相当于将person2.sayHi赋值给了一个变量,最后执行了这个变量,此时sayHi中的this就和person2没有关系了 - 第三条,执行的
person2.sayHi()使用的是隐式绑定。
显式绑定
call,apply,bind。
call和apply作用一样,只是传参方式不同。call和apply都会执行对应的函数,二bind方法不会。
function sayHi(){
console.log('Hello,', this.name);
}
var person = {
name: 'YvetteLau',
sayHi: sayHi
}
var name = 'Wiliam';
var Hi = person.sayHi;
Hi.call(person); //Hi.apply(person), hello,yvette
使用显式绑定将this绑定在了person上
但使用显式绑定还是会出现绑定丢失:
function sayHi(){
console.log('Hello,', this.name);
}
var person = {
name: 'YvetteLau',
sayHi: sayHi
}
var name = 'Wiliam';
var Hi = function(fn) {
fn();
}
Hi.call(person, person.sayHi); //Hello, Wiliam.
Hi.call(person, person.sayHi)的确是将this绑定到Hi中的this了。但是在执行fn的时候,相当于直接调用了sayHi方法(记住: person.sayHi已经被赋值给fn了,隐式绑定也丢了),没有指定this的值,对应的是默认绑定。
new绑定
new的过程:
- 创建一个空对象,构造函数中的this指向这个空对象
- 这个新对象被执行 [[原型]] 连接
- 执行构造函数方法,属性和方法被添加到this引用的对象中
- 如果构造函数中没有返回其它对象,那么返回this,即创建的这个的新对象,否则,返回构造函数中返回的对象。
function sayHi(name){
this.name = name;
}
var Hi = new sayHi('Yevtte');
console.log('Hello,', Hi.name);
输出结果为 Hello, Yevtte, 原因是因为在var Hi = new sayHi('Yevtte');这一步,会将sayHi中的this绑定到Hi对象上。
绑定优先级
new > 显式绑定 > 隐式绑定 > 默认绑定