javascript筆記:深入分析javascript裡對象的建立(上)續篇

來源:互聯網
上載者:User

  今天回來一看我的部落格居然有這麼多人推薦真是開心極了,看來大家對我的研究有了認可,寫部落格的動力越來越大了,而且我發現寫javascript在部落格園裡比較受歡迎,寫java的受眾似乎少多了,可能部落格園裡java的程式員要少點吧,也可能是javascript使用的人太多了吧,不過寫javascript的文章還是比較福士化,以後多寫寫javascript了。

  本篇文章不是《深入分析javascript裡對象的建立》的下篇,而是對我上篇寫錯的地方以及有童鞋不明白的地方做做解答。

  首先是下面一位童鞋的留言:

寫的精彩啊.關於// 深入分析函數式 2有點困惑.
window.sayHello();//為什麼輸出的會是//id:102@!@name:InnerObj0@!@teststring:Test InnerObj0而不//id:007@!@name:My Name is obj7@!@teststring:Test Obj7..求解

  上篇裡我寫這個例子目的是要加深對“不論哪裡直接調用函數,裡面的this都是指向全域的”運用,因此寫了一個函數內部的方法來驗證,希望大家能熟記這個原理,其實這個是可以用javascript原理來進行解釋的。

  我開始思考這個問題時候,想這個產生的原因是不是因為function定義的方式不同所產生的(這個想法很讓我興奮,我前面有篇博文叫《javascript筆記:javascript裡面不同function定義的區別》,其實這篇文章裡面討論的問題我到現在還有點類比兩可,究其原因還是沒有找到好的執行個體代碼說明這個問題),如是我改了下代碼:

// 深入分析函數式 2function OuterObj(id1,name1,teststring1){this.id = id1;this.name = name1;this.teststring = teststring1;this.sayHello = function(){console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);}var InnerObj = function(id2,name2,teststring2){this.id = id2;this.name = name2;this.teststring = teststring2;this.sayHello = function(){ console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);}}var innerVal = new InnerObj('101','InnerObj','Test InnerObj');console.log(innerVal instanceof InnerObj);//trueinnerVal.sayHello();//id:101@!@name:InnerObj@!@teststring:Test InnerObjInnerObj('102','InnerObj0','Test InnerObj0');}var outObj = new OuterObj('007','My Name is obj7','Test Obj7');outObj.sayHello();//id:007@!@name:My Name is obj7@!@teststring:Test Obj7sayHello();//id:102@!@name:InnerObj0@!@teststring:Test InnerObj0window.sayHello();//id:102@!@name:InnerObj0@!@teststring:Test InnerObj0console.log(id);//102console.log(name);//InnerObj0console.log(teststring);//Test InnerObj0

  結果一樣,哎,實在有點沮喪。不過回過頭來思考“不論哪裡直接調用函數,裡面的this都是指向全域的”這句話,似乎又更加理解了這句話的含義。我記得前篇博文裡說道“javascript是可以做物件導向編程的,我們不能把它當做面向過程的語言”,我想javascript設計人員不可能在設計這套語言時候憑空做了兩套函數執行方式(就是我自己擅自訂的建構函式式和函數式),理由很簡單,因為沒有任何書籍這麼寫道,從我多年開發的經驗我感覺一群優秀的程式員,不可能會傻到平白無故的做兩套解析器,二者一定有關係。關係在那裡呢?答案就是window。

  下面是我的分析:大家都知道頁面嵌入了javascript(瀏覽器支援javascript的意思),javascript解析器會自動構建window對象,這個道理可以這麼理解,瀏覽器的javascript解析器裡早就寫好了window類,頁面一載入window對象就被new了一下,為了簡便程式員的開發,這個window對象一般可以省略,但是它確實肯定以及一定存在我們的頁面裡。此外javascript有個我們常常會忽視的特點:極晚綁定,也就是說在javascript對象執行個體化後我們任然可以為該對象定義方法和屬性

  那麼我可以這麼猜想了,其實javascript裡面都是通過new來產生執行個體對象,window也不例外,而且方法的調用都是[某某對象].[方法]的格式,我們平時直接在script標籤裡面寫function方法,然後直接調用其實就是通過極晚綁定來為window對象定義新方法,在javascript沒有不屬於任何對象的function,當javascript發現某個方法被調用時候找不到該方法的對象,javascript自動會把這個棄兒丟給window這個福利院

  哈哈,這個理解似乎完美,不知道對不對,請大蝦人多多指教啊。

  此外還有位童鞋指出了我前一篇博文裡面的錯誤,哎,大庭廣眾下丟人,所以今天熬夜趕寫博文糾正啊。這位童鞋的留言如下:

@深藍色夢想
樓主的// 深入分析建構函式1 下面的sayHello()和window.sayHello()的結果錯了,結果應該都是
id:004@!@name:My Name is obj4@!@teststring:Test Obj4

因為執行個體化的時候傳參都傳給了windows對象(id,name,teststring),而調用sayHello方法的時候裡面的this也指向了windows對象的屬性,所以結果不會是undefined...

回樓上的,因為InnerObj('102','InnerObj0','Test InnerObj0');
樓主已經說了:直接調用function,this指標都是指向window,也就是全域對象.
這裡是直接調用,所以指向了windows,所以調用window.sayHello()就會得到它自己(window)的屬性值...
而007那個值是屬於outObj對象的.

  上篇博文跨天寫的,第二天對我前一天寫的執行個體沒有認真回憶體會,其實深入分析建構函式1的原始碼是:

function Obj(id,name,teststring)
{
id = id;
name = name;
teststring = teststring;
sayHello = function(){
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
var obj = new Obj('004','My Name is obj4','Test Obj4');
sayHello();//id:undefined@!@name:@!@teststring:undefined
window.sayHello();//id:undefined@!@name:@!@teststring:undefined
obj.sayHello();//obj.sayHello is not a function [在此錯誤處中斷] obj.sayHello();

  結果是id和teststring為undefined,而name為空白值。當時寫時候這個方法結果沒有反應出我的初衷,但是當時沒有深入分析就休息了,第二天趕寫時候根據模糊的記憶,覺得變數命名要明確不要重複,這樣能更好的講出自己的主題,沒想確犯了低級錯誤。下面我就這個原始寫法做深入分析。

  上面代碼問題就是id、name和teststring到底是在那個範圍下定義,javascript有個定義變數的關鍵字var,但是javascript同時也可以對沒有做var定義的變數進行正確的解析,如果變數本身範圍裡找到該變數的var定義,javascript解析器會一直向上一層範圍尋找知道找到該變數的var定義為止,但是如果到了window範圍下還沒有var定義,那麼javascript解析器會自動把這個變數授予window對象。看下面代碼,我把程式改為和我上篇部落格一樣,並且列印window.id等屬性:

function Obj(id1,name1,teststring1)
{
id = id1;
name = name1;
teststring = teststring1;
sayHello = function(){
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
var obj = new Obj('004','My Name is obj4','Test Obj4');
console.log(window.id);
console.log(window.name);
console.log(window.teststring);
sayHello();//id:004@!@name:My Name is obj4@!@teststring:Test Obj4
window.sayHello();//id:004@!@name:My Name is obj4@!@teststring:Test Obj4
obj.sayHello();//obj.sayHello is not a function [在此錯誤處中斷] obj.sayHello();

  結果就是那位童鞋指出的那樣,而且我們發現沒有this的屬性和方法都是屬於window的。

  疑問來了,為什麼function Obj(id,name,teststring)定義的結果就會產生id和teststring為undefined,而name為空白值呢?如果按上面分析直觀理解的話,就是id、name和teststring都是屬於Obj對象,而不是window的,那麼id、name和teststring本身都是有值的,但結果為什麼又各不相同了?

function Obj(id,name,teststring)
{
console.log(window.id);//undefined
console.log(window.name);//(an empty string)
console.log(window.teststring);//undefined
id = id;
name = name;
teststring = teststring;
sayHello = function(){
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
console.log(window.id);//undefined
console.log(window.name);//(an empty string)
console.log(window.teststring);//undefined
var obj = new Obj('004','My Name is obj4','Test Obj4');
sayHello();//id:undefined@!@name:@!@teststring:undefined
window.sayHello();//id:undefined@!@name:@!@teststring:undefined
obj.sayHello();//obj.sayHello is not a function [在此錯誤處中斷] obj.sayHello();

  結果在window下,id、name和teststring的確沒有被定義,我測試的頁面只有這一個function,那麼id、name和teststring只可能被定義在Obj內部了,如是我做了下面測試:

function Obj(id,name,teststring)
{
id = id;
name = name;
teststring = teststring;

console.log(window.id);//undefined
console.log(window.name);//(an empty string)
console.log(window.teststring);//undefined

console.log(id);//004
console.log(name);//My Name is obj4
console.log(teststring);//Test Obj4

sayHello = function(){
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
var obj = new Obj('004','My Name is obj4','Test Obj4');
sayHello();//id:undefined@!@name:@!@teststring:undefined
window.sayHello();//id:undefined@!@name:@!@teststring:undefined
obj.sayHello();//obj.sayHello is not a function [在此錯誤處中斷] obj.sayHello(

  看來id、name和teststring的確定義在Obj內部了,但是為什麼this.id、this.name和this.teststring列印出了window下的id、name和teststring的結果了?

  這個解釋很簡單,因為this指標在javascript裡面都是指向調用該屬性和方法的對象,sayHello屬於window的,自然this指向的是window下的id、name和teststring了。

  這裡面還有一個疑難雜症:為什麼id和teststring是undefined而那麼是Null 物件了?

  如是我做了如下測試:

function TestObj()
{
console.log(teststring);//teststring is not defined
}

var testobj = new TestObj();

  接下來是id的:

function TestObj()
{
console.log(id);//id is not defined
}

var testobj = new TestObj();

  最後來是name的:

function TestObj()
{
console.log(name);//(an empty string)
}

var testobj = new TestObj();

  大家不把id、name和teststring放到自訂function裡,而是直接寫到window下也是一樣結果,這就表明javascript自身對象裡就定義好了name屬性,因此name的值為空白,而其他都是未定義。

  寫完了,總結下吧:我現在定位自己是在做研究,所以我時刻要求自己要嚴謹,雖然自己本身有粗心毛病。我寫部落格也是想以文會友,希望大家多交流多提建議,大家一起進步了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.