Re: [问题] undefined null的差别?

楼主: s25g5d4 (function(){})()   2013-12-02 12:13:10
※ 引述《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
楼主: s25g5d4 (function(){})()   2013-02-02 12:13:00
哭哭 打到一半PTT断线 还好有暂存盘 可是P币变少了
作者: danny8376 (钓到一只猴子@_@)   2013-02-02 14:49:00
用心推 不过... !!info_obj.message <- 这样也是未定义真想避免所谓的未定义行为请用typeof去判断...不过... 对obj(?这样用到也没啥问题... JS其实有些地方真的是颇麻烦 OTZ而undefined这东西... 主要是因为他实际上完整是window.undefined 实质上也就是个全域变量但这全域一般来说应该都是readonly才是
作者: mrbigmouth (大嘴先生)   2013-02-02 15:10:00
不对喔 你可以写var undefined=123; XD
作者: danny8376 (钓到一只猴子@_@)   2013-02-02 17:02:00
楼上 再怎改window.undefined都不会变啊...readonly的是window.undefined 又不是local...
作者: mrbigmouth (大嘴先生)   2013-02-02 17:17:00
readonly是旧版js没有的功能 至少我刚模拟IE7,8都是能改的何况在local改变undefined的值是能成功的因此还是不要太相信undefined真的是undefined比较好
作者: akiratw   2013-02-02 17:24:00
有看过用 void 0 来取代 undefined 的void 是运算子,后面不管接什么都会回传真正的 undefined所以可以用 if (foo === void 0) 来检查是否 undefined而不会有 undefined 被复写的疑虑
楼主: s25g5d4 (function(){})()   2013-02-02 18:09:00
这好酷... XDD
作者: danny8376 (钓到一只猴子@_@)   2013-02-02 21:45:00
mrbigmouth IE是啥 早就随他了XDlocal的问题... 大多时候都能自己掌控吧XD不过像很多lib都会自己在定义一次undefined就是wwws25g5d4 看到最后一段就感觉好多 直接end了XDD不过void这部分 a tag的inline看很多了script里倒是没看过www原PO修文有提到closure了www
作者: tomin (Schrödinger's cat)   2013-02-02 21:53:00
推 写得很详细

Links booklink

Contact Us: admin [ a t ] ucptt.com