定义
this是函数执行的上下文。
调用方式
1. 作为函数调用,指向window(严格模式报undefined的错)。
var name='hello';
function a() { console.log(this.name)
}
a(); //hellovar c={ name:'haha', d: function(){ a(); }
}
c.d(); //hello
复制代码
2. 作为属性调用,指向该对象。
var name='hello';
function a(){ console.log(this.name)
}
var b={ name:'world', a:a
}
b.a(); //world
复制代码
有个陷阱,作为函数别名调用时,会丢失this。
var name='hello';
function a(){ console.log(this.name)
}
var b={ name:'world', a:a
}var test=b.a;
test(); //hello
复制代码
3. 作为构造函数调用,会把属性挂到new出来的实例上。
function A(){ this.name='xiaoming'
}
var a=new A();
console.log(a.name); //xiaoming
复制代码
如果构造函数有return,且return对象(包括{}、[])
,那么new的实例就是return的值.
function A(){ this.name='xiaoming';return {}
}
var a=new A();
console.log(a.name) //undefined
复制代码
如果return的是字符串、“”、null、undefined
,new的实例和无return时new的实例一样。
function A(){ this.name='xiaoming';return null
}
var a=new A();
console.log(a.name); //xiaoming
复制代码
其实new做了三件事:
创建一个新对象:
var obj={}
;将obj的__proto__指向A.prototype:
obj.__proto__=A.prototype
;该步骤是为了继承构造函数A原型链。将this指向该新对象执行A:
A.call(obj)
。
function Animal(){ this.animal="animal";
}
Animal.prototype.name="9"; //Animal构造函数原型的属性name
function Dog(){ this.dog="dog";
}
Dog.prototype.__proto__=Animal.prototype;var d=new Dog();
var obj={};
obj.__proto__=Dog.prototype;
Dog.call(obj);
复制代码
上面的例子中,对象d和对象obj完全一样,结果都是下图的实例,都能访问Animal构造函数原型的属性name和方法。
改变this指向的三种方式
1.call
使用:Function.call(obj,arg0,arg1...)
将Function的this指向obj,第一个参数是this指向,后面的参数是传入Function的参数,一般用于参数个数固定的的函数。对于改变this指向,我个人理解是把函数里所有用到this的地方替换为obj。
2.apply
使用:Function.apply(obj,[arg0,arg1...])
将Function的this指向obj,第一个参数是this指向,第二个参数是传入Function的参数组成的数组,一般用于参数个数不固定的的函数。
3.bind
使用:Funtion(arg0,arg1...).bind(obj)
误区
误区1:this指向函数本身?
var name='hello'
function a(){ console.log(this.name);
}
a.name='world';
a() ; //打印hello
console.log(a.name) //world
复制代码
题外话:
Object.__proto__ === Function.prototype //true
Object.__proto__ === Function.__proto__//true
Object.prototype === Function.prototype.__proto__ // true
//因此
Function instanceof Object //true
Object instanceof Function //true
复制代码
函数a的原型:
Object
,函数的原型是Object的实例, 因为Function.__proto__.__proto__===Object.prototype
为true,也可以用Function.prototype.isPrototypeOf(Object)
为true判断。是对象就可以增加属性,所以a.name挂在了函数上,那他有没有丢呢?由例子打印的第二个值可以看出来没丢。
是对象都可以增加属性,Array.__proto__.__proto__===Object.prototype
为ture,Array.__proto__.__proto__.isPrototypeOf(Object)
为true,所以Array和Function一样,也可以增加属性。感兴趣可自行测试。
误区2:this是函数局部作用域?
var name='hello'
function a(){ var name='world'; console.log(this.name)
}
a(); //hello
复制代码
上例打印hello,不是world,说明this并不是函数的局部作用域。
误区3:this指向父级函数作用域?
var name='hello'
function a(){ console.log(this.name)
}
function b(){ var name='world'; a();
}
b(); //hello
复制代码
该例子打印的是hello,而不是world,说明this并不是父级函数作用域,而是调用上下文。
误区4:函数的this指向与调用该函数的地方this相同?
var name='hello';
function a(){ console.log(this.name)
}
var c={ name:'haha', d: function(){ console.log(this.name); // haha a(); }
}
c.d(); // haha hello
复制代码
照理说,如果函数的this指向与调用该函数的地方this相同
,那么两个都打印haha,然而事实却是,先打印haha,再打印hello,说明跟调用函数外部的this无关
,可能有人有困惑,为什么会这样呢?我也不知道哈哈