首頁  >  文章  >  web前端  >  javascript中This用法的實例教程

javascript中This用法的實例教程

零下一度
零下一度原創
2017-06-25 09:38:121417瀏覽

《你不知道的javascript》這本書讀了有好幾遍了,似乎每一次讀都有新發現,有些內容並不是一下子可以弄懂的,每次讀似乎都能明白一些概念。
再重讀一下this關鍵字。這個概念非常靈活,也非常難掌握,所以我覺得經常讀讀沒有壞處。期待javascript一桶江湖,這樣學習的成本就低!
參考本書的第二部分的第一章,第二章。

this關鍵字是js中最複雜的機制之一。他被自動定義到所有函數的作用域。

在學習這個關鍵字的過程中似乎也走了很長時間的彎路。你要問我為什麼走了很長時間的彎路,關鍵的地方還是沒有對核心的概念徹底學習和領會,這一點和小學生學習新知識沒有任何區別。要掌握this這個關鍵字,需要緊扣關鍵概念,不要憑空想像這到底是怎麼一回事。

關鍵概念:js中的函數在呼叫的時候,一定,一定,一定會綁定在一個物件上,在分析this關鍵字的時候,一定要知道函數在呼叫的時候這個物件到底是誰? 。
切記:js中函數的呼叫和定義是沒有任何關係的,函數所綁定的物件直到他被呼叫的時候才能知道。

this關鍵字的不確定定是把雙刃劍,一是函數呼叫時的物件不確定性,是js中函數的使用具有很大靈活性,每個物件都可以藉用其他函數來完成功能。二是這也造成了this學習的一些困擾。所以在學習的時候先要理解this關鍵字的優點,然後再去學習造成困擾的地方

先看看第一段程式碼
page 75

//注意只是定义了一个函数,并未调用,这时候函数是没有绑定任何对象function identify() {return this.name.toUpperCase();
}//同上面的函数,但是这个函数内部有点复杂,如果下面的代码看不懂//可以只看上面的函数function speak() {var greeting = "Hello, I'm " + identify.call( this );console.log( greeting );
}var me = { //定义了一个字面量对象
    name: "Kyle"
};var you = {//定义了一个字面量对象
    name: "Reader"
};//通过call方式把函数identify分别绑定到两个对象上//这时的this是指向me对象,和you对象
identify.call( me ); // KYLE  
identify.call( you ); // READER//通过call方式把函数call分别绑定到两个对象上//这时的this是指向me对象,和you对象
speak.call( me ); // Hello, I'm KYLE
speak.call( you ); // Hello, I'm READER

#在javascript中定義函數的時候,函數是不屬於任何物件的。這一點非常的關鍵,非常的關鍵,非常的關鍵。這是理解this關鍵字的第一個障礙。

this關鍵字在js函數定義的時候的不確定性使得js函數使用有極大的靈活性,任何物件都可以使用他。

this到底是什麼?

this的綁定和函數定義的位置沒有任何關係,只取決於函數呼叫的方式.
javascript當一個函數被呼叫的時候,會建立一個活動記錄(有時也稱上下文)。這個記錄包括函數在哪裡被調用,函數的調用方法,傳入的參數。 this就是記錄中的屬性。

這樣在學習javascript關鍵字的首要問題是要解決怎麼知道到函數的呼叫位置.

js物件綁定規則

#每個js函數在呼叫的時候一定要找到一個對象,綁定以後才能使用。 這裡是理解了js函數的定義和調用的區別以後需要掌握的一個規模最龐大的概念,在js中一共有四種綁定方式.就我個人來看,綁定規則並不難,難點還是在js的函數作用域的理解. 尤其是預設綁定.這個綁定方式有極大的迷惑性。

預設綁定

這個是函數的獨立調用,也就是在一個函數直接調用的時候,似乎是沒有綁定到物件上的,但是根據前面的介紹,js中函數呼叫時必須要綁定到一個物件上。
看下面程式碼 page 83

  function foo() { //这是函数的定义位置console.log( this.a );
}  var a = 2;//这个变量定义的含义是什么呢?仅仅是赋值给a吗?

  foo(); // 2  //这是函数的调用位置。为什么会打印出2呢?

很多函數都是這麼呼叫的,照貓畫虎也可以寫出來,但是理解了具體的意義就不一樣了。
foo這個函數定義在全域作用域中(window作用域中),巧合的是他的呼叫也是在全域作用域中,注意這只是巧合,巧合。 那麼foo()呼叫的時候為什麼會印出變數 a的值呢?儘管使用了var這個關鍵字,但分析作用域可以知道,a這個變數實際上是全域變量,說的再明白一點,a實際上是window這個全域物件的一個屬性,2是這個屬性的屬性值。
foo()呼叫的時候是一絲不掛的全裸狀態,只是函數本身,沒有任何修飾符,這時候他也沒有任何函數包裹,處在全域作用域下面,所以foo()裡面的this是指向全域物件的,當要印出this.a的時候,尋找foo()呼叫位置會找到全域作用域,找全域作用域的屬性this.a的時候會印出2這個屬性值。

我們在使用setTimeout,setInterval函數的時候,實際這兩個函數就是一絲不掛的,同樣綁定在window物件上。

隱式綁定

函數在呼叫的時候被加入了修飾符。看下面這個程式碼
page 85

  function foo() { //定义在全局作用下的函数,仅仅是定义,不是调用位置console.log( this.a );
}var obj = { //定义一个对象
    a: 2,foo: foo
};

obj.foo(); // 2  给foo()函数找了一个对象,this就指向这个对象了

這是最常見的方式了,如果不寫前面的obj是不是就是上面的預設綁定了?

隱含遺失
常在js程式碼的巢狀回呼函數中看到在外層函數開始的一句

   var  that=this; //这是什么含义

或許你已經會用了,但理解了其中意義用起來會更加得心應手啊

看下面段代码.这段代码其实以前我也不太理解,问题还是没有彻底领悟js函数定义和调用之间是没有关系的这一点。
page 86

function foo() { //定义了一个函数console.log( this.a );
}var obj = { //定义了一个对象字面量
    a: 2,foo: foo  //函数作为对对象的属性
};var bar = obj.foo; //把obj对象的函数foo属性赋值给bar变量//这里就是理解这个问题的关键,如果你现在认为调用bar()的时候绑定的对象//是obj那就完全搞错了。这个时候仅仅是把函数foo赋值给了var变量,//并没有把对象也给bar变量,因为这里还不是foo()函数的调用位置,现在//foo函数还没有绑定对象,那么调用bar()的时候对象到底是谁?不知道。//调用的时候才知道。var a = "oops, global"; // 任然是全局对象的属性
bar(); // "oops, global" 这里执行的是默认绑定,this就是去全局对象啦

下面这段代码就是使用var that=this的场景
在使用回调函数的时候要留心。js中函数是一等对象,可以作为另一个函数的参数传入函数。 问题就出在这里了,函数一旦作为实参代替形参的时候,实际也执行了和上面代码一样的赋值过程,实际只是传递了函数本身,原先的对象就没有了。

page 86

function foo() { //定义一个函数console.log( this.a );
}function doFoo(fn) { //fn是形参// 如果函数作为实参传入相当于代码 var fn=obj.foo//和上面一段代码是完全一样的,只是函数本身,并没有绑定任何对象

    fn(); // 在这里调用的时候,由于fn只代表foo()函数,被绑定到全局对象上了
}var obj = {a: 2,foo: foo
};var a = "oops, global"; // `a` also property on global object

doFoo( obj.foo ); // "oops, global"不要被obj.foo迷惑了//没有实际执行函数的调用,此时obj.foo仅仅代表没有绑定任何对象的函数//这个代码块看着眼熟么?这就是javascript中回调函数的样子,当//一个函数作为参数传递进另一个函数的时候,这个参数函数就找不到自己绑定的对象是谁了,//所以就默认绑定到全局对象上了。但是我们既然在一个函数里调用另一个函数,肯定是要用这个函数操作当前的对象,那么既然找不到了,我们就手动给他指定一个对象吧。这就是为什么要使用//var  that=this的原因。我觉得理解这个概念,js的功力至少会增加5%

以上是javascript中This用法的實例教程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn