摘要:雖然方法定義在對象里面,但是使用方法后,將方法里面的指向了。本文都是在非嚴格模式下的情況。在構造函數內部的內的回調函數,始終指向實例化的對象,并獲取實例化對象的的屬性每這個屬性的值都會增加。否則最后在后執(zhí)行函數執(zhí)行后輸出的是
本篇文章主要針對搞不清this指向的的同學們!不定期更新文章都是我學習過程中積累下的經驗,還請大家多多關注我的文章以幫助更多的同學,不對的地方還望留言支持改進!
首先,必須搞清楚在JS里面,函數的幾種調用方式:
1.普通函數調用
2.作為方法來調用
3.作為構造函數來調用
4.使用apply/call方法來調用
5.Function.prototype.bind方法
6.es6箭頭函數
要點:不管函數以何種方式來調用,誰調用這個函數或方法,this關鍵字就指向誰,牢記這一點。!important
下面我將對每個方法進行實例講解!
1.普通函數調用(function fun(){ this.name="segmentfault"; console.log(this); //window console.log(this.name); //segmentfault })() console.log(window.name); //segmentfault 由此可見name屬性屬于window的屬性。
在這段代碼中fun函數作為普通函數調用,實際上fun是作為全局對象window的一個方法來進行調用的(這點大家應該都知道),即window.fun();所以這個地方是window對象調用了fun方法,那么fun函數當中的this即指window,同時window還擁有了另外一個屬性name,值為segmentfault.
2.作為方法來調用var name="segmentfault";
var fun={
name:"segmentfault-A", showName:function(){ console.log(this.name); //輸出 segmentfault-A }
}
fun.showName();
//這里是fun對象調用showName方法,很顯然this關鍵字是指向fun對象的,所以會輸出name
var funA = fun.showName;
funA(); //輸出 segmentfault
//這里將fun.showName方法賦給funA變量,此時funA變量相當于window對象的一個屬性,因此showNameA()執(zhí)行的時候相當于window.funA(),即window對象調用funA這個方法,所以this關鍵字指向window
換種方式看看:
var funA={ name:"segmentfault", showName:function(){ console.log(this.name); } } var funB={ name:"segmentfault-A", sayName:funA.showName } funB.sayName(); //輸出 segmentfault-A //雖然showName方法是在funA這個對象中定義,但是調用的時候卻是在funB這個對象中調用,因此this對象指向funB3.作為構造函數來調用
function fun(name){ this.name=name; } var funA = fun("segmentfault"); console.log(funA.name); // 輸出 undefined console.log(window.name);//輸出 segmentfault //上面代碼沒有進行new操作,相當于window對象調用fun("segmentfault")方法,那么this指向window對象,并進行賦值操作window.name="segmentfault". var funB=new fun("segmentfault"); console.log(funB.name);// 輸出 segmentfault4.call/apply方法的調用
在JS里函數也是對象,因此函數也有方法。從Function.prototype上繼承到Function.prototype.call/Function.prototype.apply方法
call/apply方法最大的作用就是能改變this關鍵字的指向.
Obj.method.apply(AnotherObj,arguments);
var name="segmentfault-A"; var fun={ name:"segmentfault", showName:function(){ console.log(this.name); } } fun.showName.call(); //輸出 "segmentfault-A" //這里call方法里面的第一個參數為空,默認指向window。 //雖然showName方法定義在fun對象里面,但是使用call方法后,將showName方法里面的this指向了window。因此最后會輸出"segmentfault-A"; function FruitA(n1,n2){ this.n1=n1; this.n2=n2; this.change=function(x,y){ this.n1=x; this.n2=y; } } var fruitA = new FruitA("cheery","banana"); var FruitB={ n1:"apple", n2:"orange" }; fruitA.change.call(FruitB,"pear","peach"); console.log(FruitB.n1); //輸出 pear console.log(FruitB.n2);// 輸出 peach
FruitB調用fruitA的change方法,將fruitA中的this綁定到對象FruitB上。
5.Function.prototype.bind()方法var name="segmentfault-A"; function fun(name){ this.name=name; this.sayName=function(){ setTimeout(function(){ console.log("my name is "+this.name); },50) } } var funA = new fun("segmentfault"); funA.sayName() //輸出 “my name is segmentfault-A”; //這里的setTimeout()定時函數,相當于window.setTimeout(),由window這個全局對象對調用,因此this的指向為window, 則this.name則為segmentfault-A
下面用bind()方法就可以輸出segmentfault
var name="segmentfault"; function fun(name){ this.name=name; this.sayName=function(){ setTimeout(function(){ console.log("my name is "+this.name); }.bind(this),50) //注意這個地方使用的bind()方法,綁定setTimeout里面的匿名函數的this一直指向fun對象 } } var funA = new fun("segmentfault"); funA.sayName() //輸出 “my name is segmentfault”; //這里的setTimeout()定時函數,相當于window.setTimeout(),由window這個全局對象對調用,因此this的指向為window, 則this.name則為segmentfault
這里setTimeout(function(){console.log(this.name)}.bind(this),50);,匿名函數使用bind(this)方法后創(chuàng)建了新的函數,這個新的函數不管在什么地方執(zhí)行,this都指向的fun,而非window,因此最后的輸出為"my name is segmentfault"而不是"my name is segmentfault-A"
另外幾個需要注意的地方:
setTimeout/setInterval/匿名函數執(zhí)行的時候,this默認指向window對象,除非手動改變this的指向。在《javascript高級程序設計》當中,寫到:“超時調用的代碼(setTimeout)都是在全局作用域中執(zhí)行的,因此函數中的this的值,在非嚴格模式下是指向window對象,在嚴格模式下是指向undefined”。本文都是在非嚴格模式下的情況。
該函數執(zhí)行的時候,this綁定到當前作用域的對象上
var name="segmentfault-A"; var fun = { name:"segmentfault", showName:function(){ eval("console.log(this.name)"); } } fun.showName(); //輸出 "segmentfault" var a = fun.showName; a(); //輸出 "segmentfault-A"7.箭頭函數
es6里面this指向固定化,始終指向外部對象,因為箭頭函數沒有this,因此它自身不能進行new實例化,同時也不能使用call, apply, bind等方法來改變this的指向。
function Timer() { this.seconds = 0; setInterval( () => this.seconds ++, 1000); } var timer = new Timer(); setTimeout( () => console.log(timer.seconds), 3000); // 3 // 在構造函數內部的setInterval()內的回調函數,this始終指向實例化的對象,并獲取實例化對象的seconds的屬性,每1s這個屬性的值都會增加1。否則最后在3s后執(zhí)行setTimeOut()函數執(zhí)行后輸出的是0
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/108297.html
摘要:一前言關鍵字是中最復雜的機制之一。對于那些沒有投入時間學習機制的開發(fā)者來說,的指向一直是一件非常令人困惑的事。隨著函數使用場合的不同,的值會發(fā)生變化。還可以傳值,在嚴格模式下和非嚴格模式下,得到值不一樣。 一、前言 this關鍵字是JavaScript中最復雜的機制之一。它是一個很特別的關鍵字,被自動定義在所有函數的作用域中。對于那些沒有投入時間學習this機制的JavaScript開...
摘要:一前言關鍵字是中最復雜的機制之一。對于那些沒有投入時間學習機制的開發(fā)者來說,的指向一直是一件非常令人困惑的事。隨著函數使用場合的不同,的值會發(fā)生變化。還可以傳值,在嚴格模式下和非嚴格模式下,得到值不一樣。 一、前言 this關鍵字是JavaScript中最復雜的機制之一。它是一個很特別的關鍵字,被自動定義在所有函數的作用域中。對于那些沒有投入時間學習this機制的JavaScript開...
摘要:有能力對元胞狀態(tài)添加或者刪除信息,這種能力通過一種叫門的結構來控制。一個有個這種門,來保護和控制元胞狀態(tài)。輸出將會基于目前的元胞狀態(tài),并且會加入一些過濾。同時也將元胞狀態(tài)和隱狀態(tài)合并,同時引入其他的一些變化。 循環(huán)神經網絡(RNN)人們的每次思考并不都是從零開始的。比如說你在閱讀這篇文章時,你基于對前面的文字的理解來理解你目前閱讀到的文字,而不是每讀到一個文字時,都拋棄掉前面的思考,從頭開始...
閱讀 2532·2021-11-17 09:33
閱讀 834·2021-11-04 16:13
閱讀 1391·2021-10-14 09:50
閱讀 748·2019-08-30 15:53
閱讀 3728·2019-08-30 14:18
閱讀 3321·2019-08-30 14:14
閱讀 2159·2019-08-30 12:46
閱讀 3236·2019-08-26 14:05