7

JavaScript 你不知道的基本包装类型

声明:本文的大部分内容参考自《JavaScript 高级程序设计(第三版)》(中文版 P.118),中间夹杂一些自己阅读这部分内容时的思路。

JavaScript 中共有 6 种基本数据类型:UndefinedNullBooleanNumberStringSymbol (new in ES 6)

举例子入门

基本数据类型的值不是对象,因而从逻辑上讲它们不应该有方法或者属性,然而事实并不是我们所想的那样,看法宝:

var str = "hello world";
str.length;              // 11
str.toUpperCase();       // HELLO WORLD

你对上面的现象有疑问吗?没有的话,可以关掉这个页面了。

引入基本包装类型

为了便于操作基本数据类型的值,JavaScript 中的原始数据类型的值会在后台隐式地被包装为对象,从而引出了基本包装类型(primitive wrapper type)这个概念。

【书中原话】每当读取一个基本类型的值的时候,后台就创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据。

这也是为什么书中会提到这句话,ECMAScript 还提供了3个特殊的引用类型:BooleanNumberString。哦,不对了,现在不是又出现了一种新的数据类型吗?所以,这句话应该改为:ECMAScript 还提供了4个特殊的引用类型:BooleanNumberStringSymbol

除了 null 和 undefined,所有的原始值都有等价的、由对象包装原始值的形式表达,取而代之,nullundefined 常被当作一个全局对象的全局属性来使用。

window.null;          // undefined
window.undefined;     // undefined
null == undefined;    // true
null === undefined;   // false

继续刚开始的那个例子

为了方便,就把前面的代码直接挪过来了。

var str = "hello world";
str.length;              // 11
str.toUpperCase();       // HELLO WORLD

我们看到的代码是上面的样子,其实后台会自动完成下列的处理:

  • 执行到第二行时:

    • 创建 String 类型的一个实例;

    • 在实例上调用指定的属性

    • 销毁这个实例;

  • 执行到第三行时:

    • 创建 String 类型的一个实例;

    • 在实例上调用指定的方法

    • 销毁这个实例;

可以将上面的步骤想象成下列 ECMAScript 代码:

// 执行到第二行时
var str = new String("hello world");
str.length;
str = null;

// 执行到第三行时
var str = new String("hello world");
str.toUpperCase();
str = null;

经过此番处理,基本的字符串值就变得跟对象一样啦。而且,上面的步骤同样适用于 Boolean 类型的 Number 类型对应的布尔值和数字值。

嘿嘿,啰嗦了这么多,搞懂了吗?

引用类型与基本包装类型的区别

引用类型与基本包装类型的主要区别就是对象的生存期。

使用 new 操作符创建的引用类型的实例,在执行流离开当前作用域之前,会一直保存在堆内存中。而后台自动创建的基本包装类型的对象,则只存在一行代码的执行瞬间,然后立即被销毁。这意味着我们不能为基本类型的值添加属性和方法。

看了上面的原理,再来看例子:

var str = "some text";
str.color = "red";
console.log(str.color);   // undefined

在此,第二行表面上看是为 str 添加了 color 属性,但是仔细回想上面的后台执行的那 3 个步骤,会发现,第二行创建的 String 对象在添加了 color 属性后,被销毁了。执行到第三行时,第三行代码又创建了自己的 String 对象,然而这个对象没有 color 属性。一切都显得那么清晰。

为了与上面的例子形成对比,我们显式地创建基本包装类型的对象,代码如下:

var str = new String("some text");
str.color = "red";
console.log(str.color);     // red

书中有警告:除非绝对必要,否则不要显式地创建基本包装类型的对象,因为这种做法很容易让人分不清自己是在处理基本类型还是引用类型的值。

var value = "25";

var number = Number(value);   // 转型函数
console.log(number);          // 25

var obj = new Number(value);  // 构造函数
console.log(typeof obj);      // object 
console.log(obj);             // Number {[[PrimitiveValue]]: 25}

Boolean 引用类型

书中很严肃地说:理解基本类型的布尔值与 Boolean 对象之间的区别非常重要------当然,我们的建议是永远不要使用 Boolean 对象

funny

吐槽一下,segmentfault 好像不让上传本地的无聊表情包,所以只好外链过来了。喔草,我刚刚说了什么。。。

Number 引用类型

【MDN】传送门---Number

var num = 1.2345678;

num.toFixed(2);        // 1.23
num.toPrecision(2);    // 1.2
num.toExponential(2);  // 1.23e+0

String 引用类型

【MDN】传送门---String

这个家伙的方法就很多了。

  • charAt()

  • concat()

  • slice()

  • indexOf()

  • trim()

  • toUpperCase()

  • toLowerCase()

  • match()

  • search()

  • replace()

  • .........

自己进门里面探索去吧!

Symbol 引用类型 (ES 6)

【MDN】传送门---Symbol

额,这个还没怎么用过呢。但是这里还是有一点需要注意下:

var sym = new Symbol();   // TypeError: Symbol is not a constructor

为什么会这样呢?这是因为围绕原始数据类型创建一个显式包装器对象从 ECMAScript 6 开始不再被支持。 然而,现有的原始包装器对象,如 new Booleannew String 以及 new Number 因为遗留原因仍可被创建。

好了,就这样结束吧!


hjxja890980
962 声望54 粉丝

nothing.