两种变量创建类型的异同
我们知道,javascript中,除了null、undefined两种类型,一切都是对象。然而:
javascript
var num_obj = new Number(100); var num_val = 100; console.log(typeof num_obj); // "object" console.log(typeof num_val); // "number" num_obj.myCustomAttr = "my custom attrbute"; num_val.myCustomAttr = "my custom attrbute"; console.log(num_obj.myCustomAttr); // "my custom attrbute" console.log(num_val.myCustomAttr); // undefined
那么问题来了
-
通过 new 关键字构造的变量与直接赋值的变量有何不同?
-
分别出现上述两种不同结果的原因是什么?javascript为何要这么设计?
Answers
@mcfog 最后说的对,我再补充一下。题主先理解一下javascript的基本包装类型。
说一下属性赋值
num_obj.myCustomAttr = "my custom attrbute"
,这个为什么能赋值并且能读出来?因为这个num_obj存在于整个上下文中,直到页面关闭,内存清空。
num_val.myCustomAttr = "my custom attrbute"
,js在执行这段话的时候,会
new Number
()出
num_val
这个对象,然后执行属性的添加,最后再执行
num_val = null
;(
这里是js后台自动执行,也是关键所在。
)
说一下取值
前者为什么能读取我就不解释了。
在执行
console.log(num_val.myCustomAttr)
,也是先
new Number()
出
num_val
这个对象,然后去找
myCustomAttr
这个属性,因为这个属性不是继承自父类的,没找到,返回undefined。
总的来说,基本包装类型在后台是自动new成对象的,而且这个对象是临时性的,因为最后是null掉的。
我解释的可能有点乱,没看懂的话联系我。。
补充关于装箱机制,问题中
num_val.myCustomAttr = "my custom attrbute";
console.log(num_val.myCustomAttr);//undefined
的细节
这段代码大致相当于
new Number(num_val).myCustomAttr = "my custom attrbute";//虽然赋值成功,但包装后的Number对象没有引用,直接被抛弃
console.log(new Number(num_val).myCustomAttr);//undefined
包装对象带有一些有用的属性和方法。比如,数字对象就带有toFixed()和toExponential()之类的方法,字符串对象带有substring()、chatAt()和toLowerCase()等方法以及length属性。这些方法非常方便,和原始值相比,这是包装对象的优势,但其实原始值也可以调用这些方法,因为原始值会首先转换为一个临时对象,如果转换成功,则调用包装对象的方法。
因为原始值可以根据需要转换成对象,这样的话,也不必为了用包装对象的方法而将原始值手动“包装”成对象。比如,不必使用new String("hi"),直接使用"hi"即可。
不得不使用包装对象的一个场景是,有时我们需要对值进行扩充并保持值的状态。原始值毕竟不是对象,不能直接对其进行扩充。
javascript 有 2 套类型系统:原始值(primitive)和对象(object)。
原始值类型 boolean, number 以及 string 都有自己对应的包装类型 Boolean, Number 和 String。
原始值是不可变的,你不能给它们添加属性 。
你的问题1:
通过 new 关键字构造的字符串变量与直接赋值的字符串变量有何不同?
-
new
创建的是 String 对象(object)。 - 直接赋值的字符串变量创建的是字符串原始值(primitive)。
分别出现上述两种不同结果的原因是什么?
原始值是不可变的,你不能给它们添加属性。因此输出
undefined
。
javascript为何要这么设计?
不能怪 javascript,大部分语言都这样,都有 2 套类型系统。
但是现在的主流脚本语言正在改变这个现状, 一切都是对象 。
因此,你不仅可以写
"abcde".length()
,你甚至可以写
1.add(3)
表示
1+3
,如果结合闭包,那就更炫酷了:
5.time({print("hello");});
输出
5
次
"hello"
。