两种变量创建类型的异同

我们知道,javascript中,除了null、undefined两种类型,一切都是对象。然而:

javascriptvar 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

那么问题来了

  1. 通过 new 关键字构造的变量与直接赋值的变量有何不同?

  2. 分别出现上述两种不同结果的原因是什么?javascript为何要这么设计?

JavaScript 并非所有的东西都是对象


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"

包装对象带有一些有用的属性和方法。比如,数字对象就带有toFixed()和toExponential()之类的方法,字符串对象带有substring()、chatAt()和toLowerCase()等方法以及length属性。这些方法非常方便,和原始值相比,这是包装对象的优势,但其实原始值也可以调用这些方法,因为原始值会首先转换为一个临时对象,如果转换成功,则调用包装对象的方法。

因为原始值可以根据需要转换成对象,这样的话,也不必为了用包装对象的方法而将原始值手动“包装”成对象。比如,不必使用new String(“hi”),直接使用”hi”即可。
不得不使用包装对象的一个场景是,有时我们需要对值进行扩充并保持值的状态。原始值毕竟不是对象,不能直接对其进行扩充。

Source: 第三章 字面量和构造函数

我记得在JavaScript中,字符串是基本数据类型,单就你给基本数据类型这个赋值操作本身就是错的。同过new String构造方法会得到一个字符串类对象。所以typeof取到的是object。跟他进行赋值操作,肯定是可以成功的。

然后回答一下性能上的问题,直接赋值字符串,性能更好。

为什么要这么设计:我只能说。大部分oo的语言都有装箱和拆箱设计。

补充关于装箱机制,问题中

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

@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掉的。
我解释的可能有点乱,没看懂的话联系我。。

  1. 是typeof不是type of
  2. var num_val = 100;
    typeof num_val返回的是”number”不是”string”
    请问题主你用的什么测试的?
  • 关于pm2的fork启动模式和cluster模式的区别
  • 怎样把从服务器获取的日期转换成年月日的形式
  • HTML5 初始弹起小键盘
  • ejs例子中的for循环出问题了
  • JS 中为什么 isNaN({}) 是 true 呢?
  • 有段关于jquery代码不是很理解,求解。
  • 在vue的{{ }}中能渲染出html吗?
  • 关于autocomplete的问题,求高手解答
  • 获取不到上面的数据
  • 谁能解释一下glMatrix中的几个函数。
  • 如何通过点击删除按钮把选中的所在的行全部删除掉?