一、并没有想象的神奇
它,与生俱来的“指针”
- 它的声明定义形式(可以认为)
var this=null
是null 暗示着,它将成为一个对象的引用。
- 它的定义形式:
this=window //browser, it is 'global'
this={} //node !=global
- 注意以上均为全局定义和声明(底层代码由C实现,所以代码只是示例)
解释下“普通函数”内部this
this=window //这是你看不见的代码
function outer(){
// 闭包的特性决定,this当然是window
function inner(){
//同样是闭包,this也是winodw
}
}
二、解释下那个让你抓狂的this
1. 函数的使用形式,只是假象
//这是你熟悉的函数定义,其实它只是语法糖
function sum(a,b) {
return a+b;
}
//真正的世界是这样子
var sum=new Function('a','b','return a+b');
sum(1,2)//这行只是语法糖
sum.apply(this,[1,2])//这才是真实的世界
如果,this是函数被调用时被传入的实参,那么this就一定是可以变化的!!!!
2. 解释“对象方法”中的this
obj.m(arg1,arg2) //这是假的
m.apply(obj,[arg1,arg2]) //真的是这样的
3. 解释Dom事件回调函数中的this
//John伪造的示例代码
function HTMLButton() {
this.addActionListener=function (ename,cb) {
//获取event
this=event.target
cb.apply(this,[event]);//this以实参传入
}
}
var button=new HTMLButton();
button.addActionListener('click',function (event) {
//这里的this是button!!!
});
4. 解释下nodejs代码文件中函数的this
this={}//这是一行你看不见的示例代码
Object.preventExtensions(this)//此对象不可以被扩展使用
fn.apply(global,[arg1,arg2])//fn函数中的this,自然就是global对象了
这也同时解释了函数内部的this和全局的this不是同一个的原因
三、箭头函数:语法糖中糖
//这是你熟悉的语法
var sum=(a,b)=>{//这里的this是箭头定义时的this,并且永远不会改变}
//其实它是这个样子的
var sum=function (a,b) {
//这里的this,永远被固定为bind传入的实参this
}.bind(this)
tip:也可以理解为,“箭头函数是没有this的”,它是按照闭包的查找机制,向上查找到this。
四、解释JSON定义对象时,方法中的this
//普通函数成为方法
var obj={name:'john',sayName:function () {
//此时的this,是在方法被调用进动态传入的
console.log(this.name)
}}
obj.sayName()//obj以sayName.apply(obj)方式传入,结果为john
//换成箭头
obj={name:'john',sayName:()=>{
//箭头将当前的this传入(function sayName(){}.bind(this))
//但此时obj对象并没有定义完成,所以this将维持闭包环境中定义域中的this
console.log(this.name);
}}
//obj仍以sayName.apply(obj)方式传入,
// 但此时的实参不起作用,this将维持函数定义的引用状态
//如果当时this上的引用,没有name,结果为undefined
obj.sayName();
五、方法中的this:其实还有更多:
方法调用:
如【二.2】节真实的代码是这样子的:
//你熟悉的代码
function Person(name) {
this.name=name;
this.sayName=function () {
console.log(this.name)
}
}
//下面是真相
function Person([this]/*new的时候传入this*/,name) {
this.name=name
this.sayName=function ([_this]/*说明每次调用,都会有this的传入*/) {
if(this!==_this) this==_this/*如果不是new时传入的this,将变为apply传入的this*/
console.log(this.name)
}
}
let p=new Person([p所指向对象的临时指针_p],'john');
p.sayName()//p.sayName.apply(p);
- 但方法采用箭头定义时:
function Person(name) {
this.name=name;
this.sayName=this.sayName=()=>console.log(this.name)
}
此时,sayName方法的定义,将会延迟到它的构造期,进而永久绑定到new时传入对象上!!!