this指針真是前端初學者比較頭疼的一塊內容了,面試筆試中也基本是必出內容,可是不真正搞懂的話就很難答出,可是我發現先去理解再去作題反倒效率很是低下,每次都是作了下題就把上題遺忘了。可是我發現每次遇到的面試題目卻能記憶深入。
我決定反其道而行之,先找出全部this的可能性作一遍,再反過來反思當時的思路哪裏有問題, 很快的我就基本掌握了全部this的題目,我在下面理出我所知道的全部this類型,若是有遺忘再回來查找回想。
如有遺漏或錯誤歡迎各位大佬在評論區補充。html
首先,請看三句話,帶着這三句話去思考全部題目。
1.this永遠指向對象
2.this取決於js運行時的調用者,而不是上下文中的位置
3.經過函數名()直接調用:this指向window。(嚴格模式下爲undefined)
前端
對象中使用this應該是最多見的了,先上例子。面試
var fullName = "三角";
var obj = {
fullName: "方塊",
prop: {
fullName: "圓",
getFullName: function () {
return this.fullName;
}
}
}
console.log(obj.prop.getFullName());
var getFullName = obj.prop.getFullName;
console.log(getFullName());
複製代碼
答案是:圓 三角
這一題的第一問關鍵就是,套嵌的對象中,內部的this指向內部對象。因此輸出了圓。
segmentfault
第二問,咱們須要先把代碼變形一下,方便理解。
當執行到 var getFullName = obj.prop.getFullName;
此時的代碼已經變成windows
var getFullName = function () {
return this.fullName;
}
console.log(getFullName()); //undefined
複製代碼
時咱們須要想到上面的三句話中的2和3, 便可理解。(不說的太透徹,第二問是筆試常考內容,須要本身好好領悟)數組
當使用new(經過構造函數)生成一個對象,這個對象下的全部this都會默認綁定在這個對象上。 做爲對象方法調用時,this指向調用該方法的對象。bash
function Func() {
this.fullName = '方塊';
this.getFullName = function () {
return this.fullName;
}
}
let func = new Func();
console.log(func.getFullName());
複製代碼
答案是方塊閉包
借用上面的例子。app
var getFullName = function () {
return this.fullName;
}
console.log(getFullName());
複製代碼
答案是undefined
首先,想到三句話中的3,便可知道在window下直接調用的都指向window。聯繫到第一句話:this永遠指向對象---由於它已在最外層,因此指向的對象就是window對象。函數
function func() {
console.log(this);
}
var arr = [func, 1, 2, 3];
arr[0]();
複製代碼
答案是 this--->arr
首先要知道的是:js中array是特殊的對象, 這裏不作拓展。聯想到三句話中的1,2。
function func() {
console.log(this);
}
setTimeout(func, 1000);//
setInterval(func,1000);//
複製代碼
答案是 this--->window this--->window
能夠那麼理解:系統內部函數的調用者就是windows對象。
那麼你們思考一下,上面這個問題能夠解決嗎?
那就是經過閉包, 若沒有什麼想法,來看答案。
var obj = {
name: 'test',
foo: function () {
console.log(this);
},
foo2: function () {
var that = this;
setTimeout(function () {
console.log(this); // Window
console.log(that); // Object -->obj
}, 1000);
}
}
obj.foo2();
複製代碼
成功獲取到了外部的this。 衆所周知,閉包的特性就是:函數內部能夠引用外部的參數和變量。 。 經過一個變量來保存指針,再經過閉包來調用到它的外部屬性
(function(){console.log(this === window)})(); //true
複製代碼
匿名函數的this指向window
詳細解答請前往 www.zhihu.com/question/21…
先看題。
var bo = 10;
function foo() {
console.log(bo);
}
(function() {
var bo = 20;
foo();
})();
(function (func) {
var bo = 30;
func();
})(foo)
複製代碼
答案是10,10
我是那麼理解的:首先咱們須要知道的是,當即執行函數會造成一個塊級做用域。 因此兩次var給bo賦值都並無影響到window下的bo,這很是關鍵。
第二點,咱們看到萬能三句中的1,3都適用這題。 由於當即執行函數不是對象,因此塊級做用域的this指向了它的上級window。
箭頭函數沒有this!它的this是從它的調用者那裏借來的。因此即便對其適用bind、call、apply也沒有效果
事先申明:mozilla推薦在通常狀況下不要在對象中使用箭頭函數。
我建議:用到this的方法都不要用箭頭函數,出了問題真的很難發現。
可是咱們仍是來舉個例子。
var x = 11;
var obj = {
x: 22,
say: () => {
console.log(this.x);
}
}
obj.say();
複製代碼
答案是11
這裏容易錯的問題就是this爲何沒有指向obj卻指向了window,這裏就要引出一個執行上下文的概念。say這個箭頭函數所在的父執行環境不是obj,而是window。
要注意:簡單對象(不是經過構造函數生成的)是沒有執行上下文的!
再來一個例子加深印象
function Func() {
this.fullName = '方塊';
this.props = {
fullName: '圓',
getFullName: ()=>{
return this.fullName;
},
getFullName1: function(){
return this.fullName;
}
}
}
let func = new Func();
console.log(func.props.getFullName());
console.log(func.props.getFullName1());
複製代碼
答案是:方塊 圓
getFullName方法的執行環境不是props(由於他沒有),而是func中,因此this指向func對象,返回方塊。
你們都知道,這三個方法的功能就是:強制改變this指向
有兩點要注意的是:
var fullName = "三角";
function Func() {
this.fullName = '方塊';
this.getFullName = function () {
return this.fullName;
}
}
function Func1() {
this.fullName = '方塊1';
this.getFullName = function () {
return this.fullName;
}
}
let func = new Func();
let func1 = new Func1();
console.log(func.getFullName());//方塊
console.log(func.getFullName.call(null)) //三角
console.log(func.getFullName.call(func1)) //方塊1
複製代碼
答案是:方塊 三角 方塊1
本來指向func的方法,經過call讓它從新指向了window或func1,apply和bind同理。
其實這些包括萬能三句都仍是取巧的方法,要想真正從根本理解this,還須要從執行環境 詞法做用域 做用域鏈 的相關知識。同時也能夠經過this的這些問題來鞏固基礎知識,豈不美哉!
參考資料:
皇問天 www.cnblogs.com/huangwentia…
知乎 www.zhihu.com/question/21…
技術雜談 zhuanlan.zhihu.com/p/24107744
當即執行函數的做用域鏈是什麼樣子 segmentfault.com/q/101000000…
Sugar www.cnblogs.com/var-chu/p/8…
安歌 segmentfault.com/a/119000001…