摘要:一前言關鍵字是中最復雜的機制之一。對于那些沒有投入時間學習機制的開發(fā)者來說,的指向一直是一件非常令人困惑的事。隨著函數(shù)使用場合的不同,的值會發(fā)生變化。還可以傳值,在嚴格模式下和非嚴格模式下,得到值不一樣。
一、前言
this關鍵字是JavaScript中最復雜的機制之一。它是一個很特別的關鍵字,被自動定義在所有函數(shù)的作用域中。對于那些沒有投入時間學習this機制的JavaScript開發(fā)者來說,this的指向一直是一件非常令人困惑的事。
二、了解this學習this的第一步是明白this既不指向函數(shù)自身也不指向函數(shù)的詞法作用域,你也許被這樣的解釋誤導過,但其實它們都是錯誤的。隨著函數(shù)使用場合的不同,this的值會發(fā)生變化。但總有一條原則就是JS中的this代表的是當前行為執(zhí)行的主體,在JS中主要研究的都是函數(shù)中的this,但并不是說只有在函數(shù)里才有this,this實際上是在函數(shù)被調(diào)用時發(fā)生的綁定,它指向什么完全取決于函數(shù)在哪里被調(diào)用。如何的區(qū)分this呢?
三、this到底是誰這要分情況討論,常見有五種情況:
1、函數(shù)執(zhí)行時首先看函數(shù)名前面是否有".",有的話,"."前面是誰,this就是誰;沒有的話this就是windowfunction fn(){ console.log(this); } var obj={fn:fn}; fn();//this->window obj.fn();//this->obj function sum(){ fn();//this->window } sum(); var oo={ sum:function(){ console.log(this);//this->oo fn();//this->window } }; oo.sum();2、自執(zhí)行函數(shù)中的this永遠是window
(function(){ //this->window })(); ~function(){ //this->window }();3、給元素的某一個事件綁定方法,當事件觸發(fā)的時候,執(zhí)行對應的方法,方法中的this是當前的元素,除了IE6~8下使用attachEvent(IE一個著名的bug)
DOM零級事件綁定
oDiv.onclick=function(){ //this->oDiv };
DOM二級事件綁定
oDiv.addEventListener("click",function(){ //this->oDiv },false);
在IE6~8下使用attachEvent,默認的this就是指的window對象
oDiv.attachEvent("click",function(){ //this->window });
我們大多數(shù)時候,遇到事件綁定,如下面例子這種,對于IE6~8下使用attachEvent不必太較真
function fn(){ console.log(this); } document.getElementById("div1").onclick=fn;//fn中的this就是#divl document.getElementById("div1").onclick=function(){ console.log(this);//this->#div1 fn();//this->window };4、在構造函數(shù)模式中,類中(函數(shù)體中)出現(xiàn)的this.xxx=xxx中的this是當前類的一個實例
function CreateJsPerson(name,age){ //瀏覽器默認創(chuàng)建的對象就是我們的實例p1->this this.name=name;//->p1.name=name this.age=age; this.writeJs=function(){ console.log("my name is"+this.name +",i can write Js"); }; //瀏覽器再把創(chuàng)建的實例默認的進行返回 } var p1=new CreateJsPerson("尹華芝",48);
必須要注意一點:類中某一個屬性值(方法),方法中的this需要看方法執(zhí)行的時候,前面是否有".",才能知道this是誰。大家不妨看下接下來的這個例子,就可明白是啥意思。
function Fn(){ this.x=100;//this->f1 this.getX=function(){ console.log(this.x);//this->需要看getX執(zhí)行的時候才知道 } } var f1=new Fn; f1.getX();//->方法中的this是f1,所以f1.x=100 var ss=f1.getX; ss();//->方法中的this是window ->undefined5.call、apply和bind
我們先來看一個問題,想在下面的例子中this綁定obj,怎么實現(xiàn)?
var obj={name:"浪里行舟"}; function fn(){ console.log(this);//this=>window } fn(); obj.fn();//->Uncaught TypeError:obj.fn is not a function
如果直接綁定obj.fn(),程序就會報錯。這里我們應該用fn.call(obj)就可以實現(xiàn)this綁定obj,接下來我們詳細介紹下call方法:
call方法的作用:
①首先我們讓原型上的call方法執(zhí)行,在執(zhí)行call方法的時候,我們讓fn方法中的this變?yōu)榈谝粋€參數(shù)值obj;然后再把fn這個函數(shù)執(zhí)行。
②call還可以傳值,在嚴格模式下和非嚴格模式下,得到值不一樣。
//在非嚴格模式下 var obj={name:"浪里行舟 "}; function fn(num1,num2){ console.log(num1+num2); console.log(this); } fn.call(100,200);//this->100 num1=200 num2=undefined fn.call(obj,100,200);//this->obj num1=100 num2=200 fn.call();//this->window fn.call(null);//this->window fn.call(undefined);//this->window
//嚴格模式下 fn.call();//在嚴格模式下this->undefined fn.call(null);// 在嚴格模式 下this->null fn.call(undefined);//在嚴格模式下this->undefined
**apply和call方法的作用是一模一樣的,都是用來改變方法的this關鍵字并且把方法
執(zhí)行,而且在嚴格模式下和非嚴格模式下對于第一個參數(shù)是null/undefined這種情況的規(guī)
律也是一樣的。**
兩者唯一的區(qū)別:call在給fn傳遞參數(shù)的時候,是一個個的傳遞值的,而apply不是一個個傳,而是把要給fn傳遞的參數(shù)值統(tǒng)一的放在一個數(shù)組中進行操作。但是也相當子一個個的給fn的形參賦值。總結一句話:call第二個參數(shù)開始接受一個參數(shù)列表,apply第二個參數(shù)開始接受一個參數(shù)數(shù)組
fn.call(obj,100,200); fn.apply(obj,[100,200]);
bind:這個方法在IE6~8下不兼容,和call/apply類似都是用來改變this關鍵字的,但是和這兩者有明顯區(qū)別:
fn.call(obj,1,2);//->改變this和執(zhí)行fn函數(shù)是一起都完成了 fn.bind(obj,1,2);//->只是改變了fn中的this為obj,并且給fn傳遞了兩個參數(shù)值1、2, 但是此時并沒有把fn這個函數(shù)執(zhí)行 var tempFn=fn.bind(obj,1,2); tempFn(); //這樣才把fn這個函數(shù)執(zhí)行
bind體現(xiàn)了預處理思想:事先把fn的this改變?yōu)槲覀兿胍慕Y果,并且把對應的參數(shù)值也準備好,以后要用到了,直接的執(zhí)行即可。
call和apply直接執(zhí)行函數(shù),而bind需要再一次調(diào)用。
var a ={ name : "Cherry", fn : function (a,b) { console.log( a + b) } } var b = a.fn; b.bind(a,1,2)
上述代碼沒有執(zhí)行,bind返回改變了上下文的一個函數(shù),我們必須要手動去調(diào)用:
b.bind(a,1,2)() //3
必須要聲明一點:遇到第五種情況(call apply和bind),前面四種全部讓步。
四、箭頭函數(shù)this指向箭頭函數(shù)正如名稱所示那樣使用一個“箭頭”(=>)來定義函數(shù)的新語法,但它優(yōu)于傳統(tǒng)的函數(shù),主要體現(xiàn)兩點:更簡短的函數(shù)并且不綁定this。
var obj = { birth: 1990, getAge: function () { var b = this.birth; // 1990 var fn = function () { return new Date().getFullYear() - this.birth; // this指向window或undefined }; return fn(); } };
現(xiàn)在,箭頭函數(shù)完全修復了this的指向,箭頭函數(shù)沒有自己的this,箭頭函數(shù)的this不是調(diào)用的時候決定的,而是在定義的時候處在的對象就是它的this。
換句話說,箭頭函數(shù)的this看外層的是否有函數(shù),如果有,外層函數(shù)的this就是內(nèi)部箭頭函數(shù)的this,如果沒有,則this是window。
上例中,由于箭頭函數(shù)不會創(chuàng)建自己的this,它只會從自己的作用域鏈的上一層繼承this。其實可以簡化為如下代碼:
let btn1 = document.getElementById("btn1"); let obj = { name: "kobe", age: 39, getName: function () { console.log(this) } }; obj.getName();
那假如上一層并不存在函數(shù),this指向又是誰?
上例中,雖然存在兩個箭頭函數(shù),其實this取決于最外層的箭頭函數(shù),由于obj是個對象而非函數(shù),所以this指向為Window對象
由于this在箭頭函數(shù)中已經(jīng)按照詞法作用域綁定了,所以,用call()或者apply()調(diào)用箭頭函數(shù)時,無法對this進行綁定,即傳入的第一個參數(shù)被忽略:
var obj = { birth: 1990, getAge: function (year) { var b = this.birth; // 1990 var fn = (y) => y - this.birth; // this.birth仍是1990 return fn.call({birth:2000}, year); } }; obj.getAge(2018); // 28
文章于2018.9.25重新修改,如果文章對你有些許幫助,歡迎在我的GitHub博客點贊和關注,感激不盡!
參考文章 廖雪峰的官方網(wǎng)站 JS中的箭頭函數(shù)與this this、apply、call、bind文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/53068.html
摘要:一前言關鍵字是中最復雜的機制之一。對于那些沒有投入時間學習機制的開發(fā)者來說,的指向一直是一件非常令人困惑的事。隨著函數(shù)使用場合的不同,的值會發(fā)生變化。還可以傳值,在嚴格模式下和非嚴格模式下,得到值不一樣。 一、前言 this關鍵字是JavaScript中最復雜的機制之一。它是一個很特別的關鍵字,被自動定義在所有函數(shù)的作用域中。對于那些沒有投入時間學習this機制的JavaScript開...
摘要:有能力對元胞狀態(tài)添加或者刪除信息,這種能力通過一種叫門的結構來控制。一個有個這種門,來保護和控制元胞狀態(tài)。輸出將會基于目前的元胞狀態(tài),并且會加入一些過濾。同時也將元胞狀態(tài)和隱狀態(tài)合并,同時引入其他的一些變化。 循環(huán)神經(jīng)網(wǎng)絡(RNN)人們的每次思考并不都是從零開始的。比如說你在閱讀這篇文章時,你基于對前面的文字的理解來理解你目前閱讀到的文字,而不是每讀到一個文字時,都拋棄掉前面的思考,從頭開始...
摘要:雖然方法定義在對象里面,但是使用方法后,將方法里面的指向了。本文都是在非嚴格模式下的情況。在構造函數(shù)內(nèi)部的內(nèi)的回調(diào)函數(shù),始終指向?qū)嵗膶ο螅@取實例化對象的的屬性每這個屬性的值都會增加。否則最后在后執(zhí)行函數(shù)執(zhí)行后輸出的是 本篇文章主要針對搞不清this指向的的同學們!不定期更新文章都是我學習過程中積累下的經(jīng)驗,還請大家多多關注我的文章以幫助更多的同學,不對的地方還望留言支持改進! ...
摘要:其實,來源于包,也是屬于集合框架中的一份子,不同于存放單一數(shù)據(jù)和存放具有映射關系的數(shù)據(jù),主要用于集合元素的迭代輸出,所以它的對象又被稱為迭代器。 ????上一篇文章中我在集合元素的遍歷中已經(jīng)有涉及到Iterator的普遍使用方法,但是并沒有對此進行解釋。????其實,Iterator來源于java.util包,也是屬于Java集合框架中的一份子,不同于Collection(存放單一數(shù)據(jù)...
閱讀 1410·2021-11-17 09:33
閱讀 3018·2021-10-13 09:39
閱讀 2686·2021-10-09 10:01
閱讀 2447·2021-09-29 09:35
閱讀 3891·2021-09-26 10:01
閱讀 3518·2019-08-26 18:37
閱讀 3149·2019-08-26 13:46
閱讀 1910·2019-08-26 13:39