作者s25g5d4 (function{}())
看板Ajax
标题Re: [问题] undefined null的差别?
时间Mon Dec 2 12:13:10 2013
※ 引述《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
1F:→ 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)
2F:推 danny8376:用心推 不过... !!info_obj.message <- 这样也是未定义 12/02 14:49
3F:→ danny8376:真想避免所谓的未定义行为请用typeof去判断... 12/02 14:49
4F:→ danny8376:不过... 对obj(?这样用到也没啥问题... JS其实有些地方 12/02 14:54
5F:→ danny8376:真的是颇麻烦 OTZ 12/02 14:54
这算是未定义行为阿... QQ
也是可以写 obj.message === undefined 啦
但就是怕 undefined 被窜改,这点可以透过 closure 解决:
(function (undefined) {
...
}());
不传入任何参数,这样 undefined 就会是 undefined 了~
6F:→ danny8376:而undefined这东西... 主要是因为他实际上 12/02 14:55
7F:→ danny8376:完整是window.undefined 实质上也就是个全域变数 12/02 14:55
8F:→ danny8376:但这全域一般来说应该都是readonly才是 12/02 14:56
对,但这点下面也有人提到旧版的浏览器是可能被覆盖的
9F:推 mrbigmouth:不对喔 你可以写var undefined=123; XD 12/02 15:10
10F:→ danny8376:楼上 再怎改window.undefined都不会变啊... 12/02 17:02
11F:→ danny8376:readonly的是window.undefined 又不是local... 12/02 17:03
12F:推 mrbigmouth:readonly是旧版js没有的功能 至少我刚模拟IE7,8都是能 12/02 17:17
13F:→ mrbigmouth:改的 12/02 17:17
14F:→ mrbigmouth:何况在local改变undefined的值是能成功的 12/02 17:18
15F:→ mrbigmouth:因此还是不要太相信undefined真的是undefined比较好 12/02 17:18
16F:推 akiratw:有看过用 void 0 来取代 undefined 的 12/02 17:24
这我没看过,详细希望
--
话说最後一段有个好大的错误都没人纠正...XD
整篇文章我重新修正一遍了,请各位板友有时间再重看一遍并订正我,谢谢 :D
※ 编辑: s25g5d4 来自: 140.117.183.96 (12/02 18:00)
17F:推 akiratw:void 是运算子,後面不管接什麽都会回传真正的 undefined 12/02 18:03
18F:→ akiratw:所以可以用 if (foo === void 0) 来检查是否 undefined 12/02 18:04
19F:→ akiratw:而不会有 undefined 被复写的疑虑 12/02 18:05
20F:→ s25g5d4:这好酷... XDD 12/02 18:09
21F:→ danny8376:mrbigmouth IE是啥 早就随他了XD 12/02 21:45
22F:→ danny8376:local的问题... 大多时候都能自己掌控吧XD 12/02 21:45
23F:→ danny8376:不过像很多lib都会自己在定义一次undefined就是www 12/02 21:46
24F:→ danny8376:s25g5d4 看到最後一段就感觉好多 直接end了XDD 12/02 21:47
25F:→ danny8376:不过void这部分 a tag的inline看很多了 12/02 21:48
26F:→ danny8376:script里倒是没看过www 12/02 21:48
27F:→ danny8376:原PO修文有提到closure了www 12/02 21:50
28F:推 tomin:推 写得很详细 12/02 21:53