this是js里面很常用的关键字,而灵活的js也赋予了这个关键字无穷的生命力,相信你也有被它糊弄的时候,我总结了一个6字原则,大部分场合都能清醒分辨this到底指向who,跟大家分享一下,欢迎指正。
谁调用指向谁!
首先介绍一个大boss: window, 他是一个隐形大侠,没有确定的调用者的时候,肯定是它出手, 也就是说,如果一个对象没有显性的调用者时,this指向的就是window。
先看下面的例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
var x = 10; function test(){ console.log("--- test this.x---"); console.log(this.x); } var fruit = { x: 20, apple: function(){ console.log("--- apple this.x---"); console.log(this.x); } }; fruit.banana = function(){ var y = 20; this.z = 20; function pear(){ console.log("--- pear this.x---"); console.log(this.x); } console.log("--- banana y---"); console.log(y); console.log("--- banana this.y---"); console.log(this.y); console.log("--- banana this.z---"); console.log(this.z); pear(); } var myfruit = { x: 30 } myfruit.mylove = fruit.apple; test(); fruit.apple(); fruit.banana(); test.call(fruit) myfruit.mylove();
运行结果分析:
1 --- test this.x--- 2 10 // this: window 3 --- apple this.x--- 4 20 // this: fruit 5 --- banana y--- 6 20 7 --- banana this.y--- 8 undefined // this: fruit, we have not assign y to fruit. 9 --- banana this.z--- 10 20 // this: fruit 11 --- pear this.x--- 12 10 // this: window 13 --- test this.x--- 14 20 // this: fruit, it is fruit to call test. 15 --- apple this.x--- 16 30 // this: myfruit
从上述结果可以看到:
test();
// test()的调用者为隐形boss, this指向window。
fruit.apple();
// apple()的调用者为fruit, this指向fruit。
fruit.banana();
// banana()的调用者为fruit, this 指向fruit。
// 而banana()里面的pear(), 没有显性的调用者,尽管pear()在banana()定义,但是pear()为隐形boss调用,this指向的是window。
test.call(fruit)
// test()在window层面定义,然而实际调用者为fruit,所以this指向fruit。
myfruit.mylove();
// mylove()直接采用了apple()的定义,实际调用者为myfruit,并非fruit,所以this指向myfruit。
综上所述,6字原则可以非常完美的指认this是谁。 这种简单粗暴的方法屡试不爽。谁调用指向谁!!
温馨提示
在回调函数中使用this, 请谨慎谨慎谨慎。先上example:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
var x = 10; var fruit = { x: 20 }; fruit.slice = function(callback){ console.log("--- slice ---"); console.log(this.x); console.log("--- callback begin---"); callback(); } fruit.slice(function(){ console.log("--- callback output---"); console.log(this.x); });
输出结果如下:
1 --- slice --- 2 20 3 --- callback begin--- 4 --- callback output--- 5 10
回调函数里边的this竟然指向window!!!
我也被这个坑得不轻,回调函数里边的this并非指向宿主函数(调用回调函数的函数)的调用者,6字原则在这里还是非常灵光的,callback()调用时有显性调用者吗?没有!!!!因此,this指向是隐形boss window啦。
当然,例子中希望回调函数指向fruit也不难,call可以帮你忙,请看例子。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
var x = 10; var fruit = { x: 20 }; fruit.slice = function(callback){ console.log("--- slice ---"); console.log(this.x); console.log("--- callback begin---"); callback.call(this); } fruit.slice(function(){ console.log("--- callback output---"); console.log(this.x); });
妥妥输出:
--- slice ---
20
--- callback begin---
--- callback output---
20
再强调一遍,6字原则在确定js关键字this是谁的问题上屡试不爽, 谁调用指向谁!言下之意,没有调用者就是隐形boss window。
细心的看官也许会问, 第一个例子中的pear(), 既然里边的this指向window, 为什么不能在全局域中使用window.pear() or pear()呢?
Good question!
把这个问题用代码还原其实是这样:
var fruit = {}; fruit.banana = function(){ function pear(){} } // 这样调用会出错咯 pear(); // 这样调用也不行 window.pear();
这两种方式调用都有exception,因为pear()只能在banana里面assign给banana的变量,或者在banana内部调用。
这样调用是对的;
var fruit = {}; fruit.banana = function(){ this.callPear = pear; // assign 给callPear function pear(){ console.log("I am pear!");} pear(); // 内部调用 } var instant = new fruit.banana(); instant.callPear();
这涉及另外一个话题,作用域,scope!下次再跟大家详细分享scope。