整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          JavaScript開發(fā)中this給程序員挖的坑,你

          JavaScript開發(fā)中this給程序員挖的坑,你遇到過嗎?

          于程序員來說,this這個關(guān)鍵字應(yīng)該是再熟悉不過了,在C++、C#以及Java中,它的身影隨處可見,this也可以說是編程語言JavaScript的精髓,但是一定也有不少JavaScript開發(fā)者都遇到過this的陷阱。

          在C++、C#、Java中,this擁有十分明確的含義,就是單純指向當(dāng)前的對象實例,但是,在動態(tài)編程語言JavaScript中,相同的this寫法,卻有不同的含義。

          JavaScript中的this代表函數(shù)運行時自動生成的一個內(nèi)部對象,只能在函數(shù)內(nèi)部使用。并且,你不能在創(chuàng)建統(tǒng)計this的時候就確定它,而應(yīng)該在函數(shù)執(zhí)行時進行確定,所以,一不留神,你就會掉進意想不到的坑!

          0、誰調(diào)用了就誰來負責(zé)

          我們先來看看代碼:

          var name='a';

          var obj={

          name: 'b',

          getName: function() {

          console.log(this.name);

          }

          };

          obj.getName(); // b

          var getName=obj.getName;

          getName(); // a

          var obj2=(function() {

          return function() {

          console.log(this.name);

          }

          })();

          obj2(); // a

          首先,obj.getName()打印出來b,因為,obj調(diào)用了getName(),所以其this指向obj,this.name就是b。

          其次,getName()打印出a的原因:理由是此時的obj并不調(diào)用getName(),而是全局變量window,因此,結(jié)果是a

          最后,obj2中,因為采用了立即執(zhí)行函數(shù),它返回一個函數(shù),而當(dāng)我們調(diào)用時,調(diào)用它的也是全局變量window,所以打印結(jié)果也是a。

          需要注意的是,匿名函數(shù)內(nèi)的this是指向window的,更準確的說是指向調(diào)用者。

          1、必須了解new的過程

          function Test() {

          console.log(this.name);

          }

          Test(); // a

          var test=new Test(); // undefined

          function Test2() {

          this.name='c';

          }

          var test2=new Test2();

          console.log(test2.name); // c

          為什么這個例子最終打印出來的是c呢?這里new的過程不可忽略,new Test2() 其實執(zhí)行了三步動作:

          首先,創(chuàng)建一個空對象obj(var obj={};),然后,將這個空對象的[[Prototype]](__proto__)成員指向了Test2函數(shù)對象prototype成員對象最后,將Test2函數(shù)對象的this指針替換成obj:

          obj.__proto__=Test2.prototype;

          Test2.call(obj);

          當(dāng)沒有顯式返回值或者返回為基本類型、null時,默認將 this 返回(參考2)

          因此,在這個例子中,當(dāng)你使用new的時候,函數(shù)內(nèi)部的this指向已經(jīng)改變了,不再指向window。

          主要應(yīng)該搞清楚new的過程,然后就知道打印出c的原因了。

          2、奇怪的return

          看過上面的例子后,你是否覺得已經(jīng)掌握了new的函數(shù)內(nèi)的this指向?千萬別掉以輕心,在JavaScript中,多的是例外,如:

          function Test3() {

          this.name='d';

          return {};

          }

          var test3=new Test3();

          console.log(test3.name); // undefined

          function Test4() {

          this.name='d';

          return 1;

          }

          var test4=new Test4();

          console.log(test4.name); // d

          可以再試試return 'd' | null | undefined中的一個或更多類型。

          結(jié)論:如果return的是一個對象(null除外),那么this指向的這個對象,否則this依舊指向?qū)嵗龑ο蟆?/p>

          當(dāng)下 Web 編程大行其道時,JavaScript無疑是使用最為廣泛的前端語言。JavaScript為我們提供了極佳的體驗,同時,我們在使用JavaScript時,又經(jīng)常會因為JavaScript的一些奇怪的特性所坑。當(dāng)然我們可能用一些簡單的方法即可避免這些問題。通過這些簡單的做法,你可以使JavaScript成為一門更好的語言,也讓你自己成為一個更好的程序員。

          ==、!=操作符

          JavaScript有兩組相等運算符:===和!==,以及它們邪惡的李生兄弟==和!=。===和!==這一組運算符會按照你期望的方式工作。如果兩個運算數(shù)類型一致且擁有相同的值,那么===返回true, !==返回false。而它們邪惡的孿生兄弟只有在兩個運算數(shù)類型一致時才會做出正確的判斷,如果兩個運算數(shù)是不同的類型,它們試圖去強制轉(zhuǎn)換值的類型。轉(zhuǎn)換的規(guī)則復(fù)雜且難以記憶。這里有一些有趣的例子:

          • ''=='0' //false

          • 0=='' //true

          • 0=='0' //true

          • false=='false' //false

          • false=='0' //true

          • false==undefined //false

          • false==null //false

          • null==undefined //true

          • ' \t\r\n'==0 //true

          ==運算符對傳遞性的缺乏值得我們警惕。我的建議是永遠不要使用那對邪惡的孿生兄弟。相反,請始終使用===和 !==。如果以上所有的比較使用===運算符,結(jié)果都是 false。

          with 語句

          JavaScript提供了一個with語句,本意是想用它來快捷地訪問對象的屬性。不幸的是,它的結(jié)果可能有時不可預(yù)料,所以應(yīng)該避免使用它。下面的語句:

          with (obj) { a * b;}

          和下面的代碼做的是同樣的事情:

          1. if (obj.a===undefined) {

          2. a * obj.b===undefined ? b : obj.b;

          3. } else {

          4. obj.a=obj.b===undefined ? b : obj.b;

          5. }

          所以,它等于這些語句中的某一條:

          1. a=b

          2. a=obj.b;

          3. obj .a=b;

          4. obj.a=obj.b;

          通過閱讀程序代碼,你不可能辨別出你會得到的是這些語句中的哪一條。它可能隨著程序運行到下一步時發(fā)生變化。它甚至可能在程序運行過程中就發(fā)生了變化。如果你不能通過閱讀程序而了解它將會做什么,你就無法確信它會正確地做你想要做的事情。

          With語句在這門語言里存在,本身就嚴重影響了 JavaScript處理器的速度,因為它阻斷了變量名的詞法作用域綁定。它的本意是好的,但如果沒有它,JavaScript語言會更好一點。

          eval 語句

          eval函數(shù)傳遞一個字符串給JavaScript編譯器,并且執(zhí)行其結(jié)果。它是一個被濫用得最多的JavaScript特性。那些對JavaScript語言一知半解的人們最常用到它。例如,如果你知道點表示法,但不知道下標表示法,就可能會這么寫:

          eval ("myValue=myObject." + myKey + ";")

          而不是這么寫:

          myvalue=myObject[myKey];

          使用eval形式的代碼更加難以閱讀。這種形式使得性能顯著降低,因為它需要運行編譯器,但也許只是為了執(zhí)行一個微不足道的賦值語句。它也會讓JSLint 失效,讓此工具檢測問題的能力大打折扣。eval函數(shù)還減弱了你的應(yīng)用程序的安全性,因為它給被求值的文本授予了太多的權(quán)力。而且就像with語句執(zhí)行的方式一樣,它降低了語言的性能。Function構(gòu)造器是eval的另一種形式,同樣也應(yīng)該避免使用它。瀏覽器提供的setTimeout和setlnterval函數(shù),它們能接受字符串參數(shù)或函數(shù)參數(shù)。當(dāng)傳遞的是字符串參數(shù)時,setTimeout和setlnterval會像eval那樣去處理。同樣也應(yīng)該避免使用字符串參數(shù)形式。

          位運算符

          JavaScript有著與Java相同的一套位運算符:

          1. & and按位與

          2. | or按位或

          3. ^ xor按位異或

          4. ~ not按位非

          5. >> 帶符號的右位移

          6. >>> 無符號的(用0補足的) 右位移

          7. << 左位移

          在Java里,位運算符處理的是整數(shù)。JavaScript沒有整數(shù)類型,它只有雙精度的浮點數(shù)。因此,位操作符把它們的數(shù)字運算數(shù)先轉(zhuǎn)換成整數(shù),接著執(zhí)行運算,然后再轉(zhuǎn)換回去。在大多數(shù)語言中,這些位運算符接近于硬件處理,所以非??臁5獼avaScript的執(zhí)行環(huán)境一般接觸不到硬件,所以非常慢。JavaScript很少被用來執(zhí)行位操作。還有,在JavaScript程序中,& 非常容易被誤寫為 && 運算符。位運算符出現(xiàn)在JavaScript中降低了這門語言的冗余,使得bug更容易被隱藏起來。

          function 函數(shù)對比 function 表達式

          JavaScript既有function語句,同時也有function表達式。這令人困惑,因為它們看起來好像就是相同的。一個function語句就是其值為一個函數(shù)的var語句的速記形式。

          下面的語句:

          function foo () {}

          意思相當(dāng)于:

          var foo=function foo () {};

          我們建議使用的是第2種形式,因為它能明確表示foo是一個包含一個函數(shù)值的變量。要用好這門語言,理解函數(shù)就是數(shù)值是很重要的。

          function語句在解析時會發(fā)生被提升的情況。這意味著不管function被放置在哪里,它會被移動到被定義時所在作用域的頂層。這放寬了函數(shù)必須先聲明后使用的要求,而我認為這會導(dǎo)致混亂。在if語句中使用function語句也是被禁止的。結(jié)果表明大多數(shù)的瀏覽器都允許在if語句里使用function語句,但它們在解析時的處理上各不相同。這就造成了可移植性的問題。

          一個語句不能以一個函數(shù)表達式開頭,因為官方的語法假定以單詞 function 開頭的語句是一個function語句。解決方法就是把函數(shù)調(diào)用括在一個圓括號之中。

          1. (function () {

          2. var hidden_variable;

          3. //這個函數(shù)可能對環(huán)境有一些影響,但不會引入新的全局變量,

          4. })();

          于程序員來說,this這個關(guān)鍵字應(yīng)該是再熟悉不過了,在C++、C#以及Java中,它的身影隨處可見,this也可以說是編程語言JavaScript的精髓,但是一定也有不少JavaScript開發(fā)者都遇到過this的陷阱。

          在C++、C#、Java中,this擁有十分明確的含義,就是單純指向當(dāng)前的對象實例,但是,在動態(tài)編程語言JavaScript中,相同的this寫法,卻有不同的含義。

          JavaScript中的this代表函數(shù)運行時自動生成的一個內(nèi)部對象,只能在函數(shù)內(nèi)部使用。并且,你不能在創(chuàng)建統(tǒng)計this的時候就確定它,而應(yīng)該在函數(shù)執(zhí)行時進行確定,所以,一不留神,你就會掉進意想不到的坑!

          0、誰調(diào)用了就誰來負責(zé)

          我們先來看看代碼:

          var name='a';

          var obj={

          name: 'b',

          getName: function() {

          console.log(this.name);

          }

          };

          obj.getName(); // b

          var getName=obj.getName;

          getName(); // a

          var obj2=(function() {

          return function() {

          console.log(this.name);

          }

          })();

          obj2(); // a

          首先,obj.getName()打印出來b,因為,obj調(diào)用了getName(),所以其this指向obj,this.name就是b。

          其次,getName()打印出a的原因:理由是此時的obj并不調(diào)用getName(),而是全局變量window,因此,結(jié)果是a

          最后,obj2中,因為采用了立即執(zhí)行函數(shù),它返回一個函數(shù),而當(dāng)我們調(diào)用時,調(diào)用它的也是全局變量window,所以打印結(jié)果也是a。

          需要注意的是,匿名函數(shù)內(nèi)的this是指向window的,更準確的說是指向調(diào)用者。

          1、必須了解new的過程

          function Test() {

          console.log(this.name);

          }

          Test(); // a

          var test=new Test(); // undefined

          function Test2() {

          this.name='c';

          }

          var test2=new Test2();

          console.log(test2.name); // c

          為什么這個例子最終打印出來的是c呢?這里new的過程不可忽略,new Test2() 其實執(zhí)行了三步動作:

          首先,創(chuàng)建一個空對象obj(var obj={};),然后,將這個空對象的[[Prototype]](__proto__)成員指向了Test2函數(shù)對象prototype成員對象最后,將Test2函數(shù)對象的this指針替換成obj:

          obj.__proto__=Test2.prototype;

          Test2.call(obj);

          當(dāng)沒有顯式返回值或者返回為基本類型、null時,默認將 this 返回(參考2)

          因此,在這個例子中,當(dāng)你使用new的時候,函數(shù)內(nèi)部的this指向已經(jīng)改變了,不再指向window。

          主要應(yīng)該搞清楚new的過程,然后就知道打印出c的原因了。

          2、奇怪的return

          看過上面的例子后,你是否覺得已經(jīng)掌握了new的函數(shù)內(nèi)的this指向?千萬別掉以輕心,在JavaScript中,多的是例外,如:

          function Test3() {

          this.name='d';

          return {};

          }

          var test3=new Test3();

          console.log(test3.name); // undefined

          function Test4() {

          this.name='d';

          return 1;

          }

          var test4=new Test4();

          console.log(test4.name); // d

          可以再試試return 'd' | null | undefined中的一個或更多類型。

          結(jié)論:如果return的是一個對象(null除外),那么this指向的這個對象,否則this依舊指向?qū)嵗龑ο蟆?/p>


          主站蜘蛛池模板: 亚洲视频一区在线播放| 国产在线不卡一区二区三区| 国产未成女一区二区三区| 无码人妻AⅤ一区二区三区| 精品视频一区二区观看| 国产精品亚洲一区二区在线观看| 日韩在线一区二区| 亚洲一区二区电影| 亚洲午夜一区二区电影院| 精品一区二区三区在线观看视频| 日韩精品无码一区二区三区不卡 | 亚洲中文字幕无码一区| 成人精品视频一区二区三区不卡 | 老熟妇仑乱一区二区视頻| 3d动漫精品一区视频在线观看| 一区二区在线免费观看| 精品国产一区二区三区久久久狼| 亚洲一区二区三区成人网站| 在线免费视频一区| 日韩一区二区在线观看| 国产高清在线精品一区二区三区 | 无码乱人伦一区二区亚洲| 久久精品午夜一区二区福利 | 亚洲AV无码一区东京热久久| 日韩制服国产精品一区| 国产精品日本一区二区不卡视频 | 精品人妻一区二区三区毛片| 成人无码AV一区二区| 亚洲一区二区影院| 亚洲欧美一区二区三区日产| 国产一区二区三区日韩精品| 亚洲欧洲一区二区三区| 熟女精品视频一区二区三区| 亚洲色无码专区一区| av无码一区二区三区| 久久无码AV一区二区三区| 国产一区二区三区樱花动漫| 亚洲熟妇av一区二区三区| 欧美成人aaa片一区国产精品 | 国产一区精品视频| 日韩电影一区二区三区|