看板 Ajax 關於我們 聯絡資訊
※ 引述《lunamiou (○苗○烏)》之銘言: : 看書的前面寫到 : var firstName = null; 這行後面 = null 是無意義的, 因為變數宣告在 javascript 有一個動作叫做 hoisting, hoisting 就是 interpreter(解譯器) 會先掃過目前的 scope(作用域), 將所有 var 關鍵字抓出來,然後將每個變數宣告建立其專屬空間。 考慮以下程式碼: function foo() { bar = 2; var bar; console.log(bar); } foo(); // print 2 console.log(bar); // will throw an error 在直觀上我們會認為當執行 function foo 時, 因為尚未宣告 bar 就直接賦值,因此 bar 會成為全域變數 而造成可能的全域變數汙染。 但其實不然,因為 hoisting 的關係所以在執行 function foo 時, 變數 bar 會先被宣告並賦值 undefined 再從第一行執行。 另外這個 hoisting 對 function declartion(函數宣告)也是具有作用的 考慮以下程式碼: console.log(foo()); // print 'bar' function foo() { return 'bar'; } 對於寫過 C/C++ 的程式設計師來說,這是違反傳統觀念的, 因為 foo 在被宣告前就被使用,理論上在這裡會噴錯誤, 但因為 hoisting 的關係,所以是可以正常執行的。 回到原題, var firstName = null; 為什麼我說沒意義,是因為當關鍵字 var 出現時,其後跟著的變數 會在該 scope 開始執行前先被宣告並賦值 undefined, (注意 hoisting 只對變數做宣告而忽略等號右邊) 此時當解譯器執行到 firstName = null 時 會把 firstName 賦值 null, 可以說這是多此一舉, 除非令 firstName = null 是你有意為之並且有特殊用途的。 考慮以下程式碼: function foo() { console.log(bar); // print undefined bar = 1; console.log(bar); // print 1 var bar = 2; console.log(bar); // print 2 } foo(); console.log(bar); // will throw an error 所以既然變數宣告會被 hoist, 那不如一開始寫的時候就先把變數宣告好, 也就是所有變數在使用 var 宣告時,一律放置在該 function 第一行, 至於要不要在宣告時賦值隨便你。 如果是想釋放變數儲存空間的話,是可以在該變數使用完後 令其等於 null, 這樣 JavaScript 引擎會自動作 garbage collection. : 上面的程式一般用於初始化變數,表示尚不需要為該變數賦與一個實際值; : 例如下面的程式,Object的一個實例info_obj的屬性message尚未初始化, : 那麼,其值就是null: : var info_obj = new Object(); : info_obj.message; : alert(info_obj.message == null); //true 當然是 true 阿,這叫自動型態轉換,謝謝 這本書可以丟了,真的 同樣的例子,考慮 alert(info_obj.message === null); 結果就會不一樣了 (茶) 至於 undefined == null 是怎麼成為 true 的, 是有聽說這是歷史共業啦 (感謝 IE), 不過我傾向這是未定義行為,應該要避開。 如上要判斷 object property 是否有值的話,我會建議用 !!info_obj.message 一個 ! 代表 not, 把 true 變 false, 反之亦然 所以上面那行的詮釋為: info_obj.message 未被賦值,其值為 undefined -> 自動型態轉換為 false -> not false 轉換為 true -> not true 轉換為 false 當然如果 info_obj.message 本身就有值而且為 0, [], '' ... 等等 會被自動轉換為 false 的值,此時就要有額外的策略去判斷, 但在大部分應用中其實是不影響結果的。 如果這不是你要的結果,那可以用 obj.message === undefined 來判斷, 但要注意 undefined 值有可能會被覆蓋,這點可以透過用 closure 解決: (function (undefined) { .... }()); 不傳入任何參數的話, undefined 值當然就是 undefined 了 (好饒舌 XD) 類似的用法可以參考 jQuery 原始碼,在此以 2.0.2為代表: http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.js 可以看到程式開頭即為 closure 形式: (function( window, undefined ) { 而結尾為: })( window ); 會傳入 window 主要是效能問題,因為加了一層 closure 等於多了一層作用域, 讓 window 成為 local 變數,就可以省下解譯器往上層作用域尋找的時間。 其原因為當解譯器在當前作用域找不到變數時,會往上一作用域搜尋。 : undefined 常數 : undefined常數用於尚未初始化的變數或未初始化的 : 動態物件屬性的特殊值。 : 例如下面的兩個變數都是undefined : var firstName; : var lastName; : 這個跟null有差別嗎? undefined 與 null 做不嚴謹相等比較 (==) 時為 true, 但做 === 時就不會返回 true, 這絕對是地雷,恭喜你踩到了 \:D/ == 與 === 的差別在於前者會做自動型態轉換,後者不會, 因此若等號兩邊型態不同,後者會直接返回 false. 考慮以下程式碼: console.log(undefined == null); // print true console.log(undefined === null); // print false console.log(0 == false); // print true console.log(0 === false); // print false 另外要注意一點,undefined 是可以被覆蓋的,也就是說: function foo() { var undefined = 10; console.log(undefined); } foo(); // print 10 console.log(undefined); // print undefined 好消息是在新版瀏覽器中 global object (全域物件,在瀏覽器環境中即為 window) 下的 undefined 是 read only 唯讀變數, 但在舊版瀏覽器中要小心全域變數 undefined 是有可能被竄改的。 undefined 的正身便是在全域物件下的變數 undefined, 如果以下敘述執行當下的作用域(包含其上層作用域)裡並沒有對 undefined 賦予其他值,那麼所有 foo === undefined 等價於 foo === window.undefined. 另外為什麼說 undefined 是全域物件的變數而不是全域物件的屬性, 其實當然是可以這樣叫的,所有全域變數都是全域物件的一個屬性。 : 再看下面的程式,user是Object類別的一個實例,該實例的sex屬性如果 : 未初始化,那麼其屬性值為undefined,而非null,因為Object並非動態 : 類別。例如下面的程式: : var user = new Object(); : alert(user.sex); //輸出undefined : ---------------------------- : 以上看完還是疑惑,什麼樣的結果是null,什麼會是undefined呢? : 這本書寫的「類別」是什麼意思,英文的原文會是? Class 但一般稱此為 Constructor (建構式),比較不常稱 Class, 這是要跟使用 Class 的物件導向語言作區別。 所以說以下程式碼: function Person(name, gender, age) { this.name = name; this.gender = gender; this.age = age; } Person.prototype.sayHello = function () { console.log('My name is ' + this.name + ". I'm " + this.gender + ". I'm " + this.age + (this.age === 1) ? ' year' : ' years' + ' old.'); } var jack = new Person('jack', 'male', 20); Person 稱為 Constructor (建構式) 或稱 Class (類別), jack 稱為 Instance of constructor Person (Person 建構式的實例), jack.name, jack.gender, jack.age 稱為 Property (屬性), jack.sayHello 稱為 Method (方法). : 另外「動態物件屬性」、「動態類別」的意思分別是? : 小的才學疏淺,這邊看了幾次還是不太懂, 對不起我也不懂... 麻煩給一下上下文,謝謝 QQ : 還請大家指教一下,感激感激~~~ <(__ __)> 以上,不知道 console.log 是甚麼也可以用 alert() 代替 延伸閱讀: https://developer.mozilla.org/en-US/docs/Web/ JavaScript/Reference/Statements/var ( 縮網址:http://ppt.cc/CNFY ) http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html http://stackoverflow.com/questions/6429225/javascript-null-or-undefined -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.117.183.96
s25g5d4:哭哭 打到一半PTT斷線 還好有暫存檔 可是P幣變少了 12/02 12:13
※ 編輯: s25g5d4 來自: 140.117.183.96 (12/02 12:14) ※ 編輯: s25g5d4 來自: 140.117.183.96 (12/02 12:15) ※ 編輯: s25g5d4 來自: 140.117.183.96 (12/02 12:36)
danny8376:用心推 不過... !!info_obj.message <- 這樣也是未定義 12/02 14:49
danny8376:真想避免所謂的未定義行為請用typeof去判斷... 12/02 14:49
danny8376:不過... 對obj(?這樣用到也沒啥問題... JS其實有些地方 12/02 14:54
danny8376:真的是頗麻煩 OTZ 12/02 14:54
這算是未定義行為阿... QQ 也是可以寫 obj.message === undefined 啦 但就是怕 undefined 被竄改,這點可以透過 closure 解決: (function (undefined) { ... }()); 不傳入任何參數,這樣 undefined 就會是 undefined 了~
danny8376:而undefined這東西... 主要是因為他實際上 12/02 14:55
danny8376:完整是window.undefined 實質上也就是個全域變數 12/02 14:55
danny8376:但這全域一般來說應該都是readonly才是 12/02 14:56
對,但這點下面也有人提到舊版的瀏覽器是可能被覆蓋的
mrbigmouth:不對喔 你可以寫var undefined=123; XD 12/02 15:10
danny8376:樓上 再怎改window.undefined都不會變啊... 12/02 17:02
danny8376:readonly的是window.undefined 又不是local... 12/02 17:03
mrbigmouth:readonly是舊版js沒有的功能 至少我剛模擬IE7,8都是能 12/02 17:17
mrbigmouth:改的 12/02 17:17
mrbigmouth:何況在local改變undefined的值是能成功的 12/02 17:18
mrbigmouth:因此還是不要太相信undefined真的是undefined比較好 12/02 17:18
akiratw:有看過用 void 0 來取代 undefined 的 12/02 17:24
這我沒看過,詳細希望 -- 話說最後一段有個好大的錯誤都沒人糾正...XD 整篇文章我重新修正一遍了,請各位板友有時間再重看一遍並訂正我,謝謝 :D ※ 編輯: s25g5d4 來自: 140.117.183.96 (12/02 18:00)
akiratw:void 是運算子,後面不管接什麼都會回傳真正的 undefined 12/02 18:03
akiratw:所以可以用 if (foo === void 0) 來檢查是否 undefined 12/02 18:04
akiratw:而不會有 undefined 被複寫的疑慮 12/02 18:05
s25g5d4:這好酷... XDD 12/02 18:09
danny8376:mrbigmouth IE是啥 早就隨他了XD 12/02 21:45
danny8376:local的問題... 大多時候都能自己掌控吧XD 12/02 21:45
danny8376:不過像很多lib都會自己在定義一次undefined就是www 12/02 21:46
danny8376:s25g5d4 看到最後一段就感覺好多 直接end了XDD 12/02 21:47
danny8376:不過void這部分 a tag的inline看很多了 12/02 21:48
danny8376:script裡倒是沒看過www 12/02 21:48
danny8376:原PO修文有提到closure了www 12/02 21:50
tomin:推 寫得很詳細 12/02 21:53