文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JavaScript原始值与包装对象的示例分析

2023-06-15 00:21

关注

这篇文章主要介绍JavaScript原始值与包装对象的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

JavaScript有什么特点

1、js属于一种解释性脚本语言;2、在绝大多数浏览器的支持下,js可以在多种平台下运行,拥有着跨平台特性;3、js属于一种弱类型脚本语言,对使用的数据类型未做出严格的要求,能够进行类型转换,简单又容易上手;4、js语言安全性高,只能通过浏览器实现信息浏览或动态交互,从而有效地防止数据的丢失;5、基于对象的脚本语言,js不仅可以创建对象,也能使用现有的对象。

正文

原始类型 (Primitive types)

原始类型也被称为“基本类型”。

目前在 JavaScript 中有以下几种原始类型:

? 如下:

typeof 'chenpipi';  // "string"typeof 12345;       // "number"typeof true;        // "boolean"typeof null;        // "object"typeof undefined;   // "undefined"typeof 12345n;      // "bigint"typeof Symbol();    // "symbol"

? 特别注意

typeof null 虽然返回 "object",但是这不代表 null 就是对象,这其实是 JavaScript 的一个 Bug,且从 JavaScript 诞生以来便如此。

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"。

The history of “typeof null”:https://2ality.com/2013/10/typeof-null.html

原始值 (Primitive values)

原始值也就是原始类型的值(数据)。

A primitive value is data that is not an object and has no methods.

原始值是一种没有任何方法的非对象数据。

也就是说,string、number 和 boolean 等原始类型的值本身是没有任何属性和方法的。

 这个时候嗅觉敏锐的小伙伴是不是已经察觉到有什么不对劲了?

是孜然!我加了孜然!(手动狗头并划掉)

? 这里有一个非常有意思的点,但是在讨论这个问题之前,先让我们认识下包装对象。

包装对象 (Wrapper objects)

除了 null 和 undefined 外的原始类型都有其相应的包装对象:

对象 (Object)

对象是引用类型。

首先,包装对象本身是一个对象,也是函数。

String instanceof Object;   // trueString instanceof Function; // true
构造函数 (Constructor)

实例 (Instance)

其中 String、Number 和 Boolean 均支持使用 new 运算符来创建对应的包装对象实例。

? 例如 String 的声明(节选):

interface StringConstructor {  new(value?: any): String;  (value?: any): string;  readonly prototype: String;}declare var String: StringConstructor;

? 使用 new 运算符得到的数据是对象(Object):

// 字符串typeof 'pp';                      // "string"typeof new String('pp');          // "object"new String() instanceof Object;   // true// 数字typeof 123;                       // "number"typeof new Number(123);           // "object"new Number() instanceof Object;   // true// 布尔typeof true;                      // "boolean"typeof new Boolean(true);         // "object"new Boolean() instanceof Object;  // true

? 我们可以调用包装对象实例的 valueOf() 函数来获取其原始值:

// 字符串let s = new String('pp');s.valueOf();                // "pp"typeof s.valueOf();         // "string"// 数字let n = new Number(123);n.valueOf();                // 123typeof n.valueOf();         // "number"// 布尔let b = new Boolean(true);b.valueOf();                // truetypeof b.valueOf();         // "boolean"

“异类” (Attention)

而 BigInt 和 Symbol 都属于“不完整的类”,不支持 new 运算符。

? 例如 BigInt 的声明(节选):

interface BigIntConstructor {  (value?: any): bigint;  readonly prototype: BigInt;}declare var BigInt: BigIntConstructor;

可以看到 BigInt 的声明中没有 new 运算符相关函数。

普通函数 (Function)

包装对象也可以作为普通函数来使用。

其中 String()、Number() 和 Boolean() 函数都可以用来对任意类型的数据进行显式类型转换。

另外 Object() 函数也可用于显式类型转换,但本文不再展开。

String

? 示例代码:

typeof String();    // "string"String();           // ""String('pp');       // "pp"String(123);        // "123"String(true);       // "true"String(false);      // "false"String(null);       // "null"String(undefined);  // "undefined"String([]);         // ""String({});         // "[object Object]"

? 小贴士 1

当我们使用 String() 函数来转换对象时,JavaScript 会先访问对象上的 toString() 函数,如果没有实现,则会顺着原型链向上查找。

? 举个栗子:执行 String({ toString() { return 'pp'; } }) 返回的结果是 "pp",并非 "[object Object]"。

所以 String() 函数并不能够用来判断一个值是否为对象(会翻车)。

? 小贴士 2

常用的判断对象的方式为 Object.prototype.toString({}) === '[object Object]'。

? 举个栗子:执行 Object.prototype.toString({ toString() { return 'pp'; } }) 返回的是 "[object Object]"。

Number

? 示例代码:

typeof Number();    // "number"Number();           // 0Number('');         // 0Number('pp');       // NaNNumber(123);        // 123Number(true);       // 1Number(false);      // 0Number(null);       // 0Number(undefined);  // NaNNumber([]);         // 0Number({});         // NaN

? 小贴士

对于 Number() 函数来说,可能最实用的转换就是将 true 和 false 转换为 1 和 0 吧。

Boolean

? 示例代码:

typeof Boolean();   // "boolean"Boolean();          // falseBoolean('');        // falseBoolean('pp');      // trueBoolean(0);         // falseBoolean(1);         // trueBoolean(null);      // falseBoolean(undefined); // falseBoolean([]);        // trueBoolean({});        // true

? 小贴士

某些情况下,我们会在数据中使用 0 和 1 来表示真假状态,此时就可以使用 Boolean() 进行状态的判断。

BigInt

BigInt() 函数用于将整数转换为大整数。

该函数接受一个整数作为参数,传入参数若为浮点数或任何非数字类型数据都会报错。

? 示例代码:

BigInt(123);        // 123nBigInt(123n);       // 123ntypeof 123n;        // "bigint"typeof BigInt(123); // "bigint"

BigInt & Number

需要注意的是,BigInt 和 Number 是不严格相等(宽松相等)的。

? 示例代码:

123n === 123; // false123n == 123;  // true

Symbol

Symbol() 函数用于创建一个 symbol 类型的值。

该函数接受一个字符串作为描述符(参数),如果传入其他类型的值则会被转换为字符串(除了 undefined)。

注意,每一个 symbol 值都是独一无二的,即使它们的描述符都是一样的。

且 symbol 类型的数据只能通过 Symbol() 函数来创建。

? 示例代码:

// 后面的返回值是 Devtools 模拟出来的,并非实际值Symbol('pp');                   // Symbol(pp)Symbol(123);                    // Symbol(123)Symbol(null);                   // Symbol(null)Symbol({});                     // Symbol([object Object])// 类型typeof Symbol('pp');            // "symbol"Symbol('pp') === Symbol('pp');  // false// 描述符Symbol('pp').description;       // "pp"Symbol(123).description;        // "123"Symbol({}).description;         // "[object Object]"Symbol().description;           // undefinedSymbol(undefined).description;  // undefined

原始值不是对象 (Primitive not Object)

? 有意思的来了~

没有属性和方法 (No properties, no functions)

本文前面有提到:「原始值是一种没有任何方法的非对象数据。」

我们都知道对象(Object)上可以有属性和方法。

但是字符串不是对象,所以你不能给字符串增加属性。

? 做个小实验:

let a = 'chenpipi';console.log(a.length);  // 8// 尝试增加新的属性a.name = '吴彦祖';console.log(a.name);    // undefined// 尝试修改已有的属性typeof a.slice;         // "function"a.slice = null;typeof a.slice;         // "function"

? 渣皮小剧场

此时一位头铁的小伙伴使用了反驳技能。

渣皮你别在这忽悠人了,我平时写 Bug 哦不写代码的时候明明可以调用到字符串、数字和布尔值上的方法!

? 比如下面这段代码,能够正常执行并得到符合预期的结果:

// 字符串let s = 'chenpipi';s.toUpperCase();      // "CHENPIPI"'ChenPiPi'.slice(4);  // "PiPi"// 数字let n = 123;n.toString();         // "123"(123.45).toFixed(2);  // "123.5"// 布尔值let b = true;b.toString();         // "true"false.toString();     // "false"

? 无用小知识

有没有发现,数字的字面量后面不能直接调用函数?例如执行 123.toString() 会报 SyntaxError(语法错误)。

这是因为数字(浮点数)本身会用到小数点 .,而调用函数也需要用小数点,这时就出现了歧义(字符串和布尔值就没有这种烦恼)。

对于这种情况,我们可以使用括号 () 将数字包裹起来,如 (123).toString();或者使用两个连续的小数点 .. 来调用函数,如 123..toString()。

? 奇了怪了

那么既然字符串不是对象,那么为什么字符串会有属性和方法呢?

转念一想,数字就是数字,数字身上怎么会有方法呢?

这确实不符合逻辑,但是这又与实际相矛盾。

咋回事呢???

替身使者 (I can't translate this)

答案揭晓~

? 暗中操作

以字符串(string)为例,当我们在代码中读取字符串的属性或者方法时, JavaScript 会静默地执行下面的操作:

  1. 将字符串通过 new String() 的方式来创建一个临时的包装对象实例;

  2. 通过创建的对象来执行我们的代码逻辑(读取属性或执行函数);

  3. 临时对象不再使用,可以被销毁。

? 如下面的栗子:

let a = 'chenpipi';console.log(a);   // "chenpipi"// ------------------------------let b1 = a.length;console.log(b1);  // 8// 上面的代码相当于:let b2 = (new String(a)).length;console.log(b2);  // 8// ------------------------------let c1 = a.toUpperCase();console.log(c1);  // "CHENPIPI"// 上面的代码相当于:let c2 = (new String(a)).toUpperCase();console.log(c2);  // "CHENPIPI"

数字(number)和布尔值(boolean)同理,但数字通过 new Number() 来创建临时对象,而布尔值则通过 new Boolean() 来创建。

? 除了上面的例子,最有力的证明,就是他们的构造函数:

'chenpipi'.constructor === String;  // true(12345).constructor === Number;     // truetrue.constructor === Boolean;       // true

这一切都是 JavaScript 在暗中完成的,且过程中产生的临时对象都是一次性的(用完就丢)。

? 原来如此

芜湖,这么一来就说得通了!

这也就能解释为什么我们能够访问字符串上的属性和方法,却不能增加或修改属性。

那是因为我们实际操作的目标其实是 JavaScript 创建的临时对象,而并非字符串本身!

所以我们的增加或修改操作实际上是生效了的,只不过是在临时对象上生效了!

? 就像这样:

// 代码中:let a = 'chenpipi';a.name = '吴彦祖';console.log(a.name);  // undefined// 相当于:let a = 'chenpipi';(new String(a)).name = '吴彦祖';console.log(a.name);  // undefined// 相当于:let a = 'chenpipi';let temp = new String(a);temp.name = '吴彦祖';console.log(a.name);  // undefined

最后我们来总结一下:

  1. 多数原始类型都有相应的包装对象;

  2. 有些包装对象可以被 new,有些不行;

  3. 包装对象一般被用来进行显式的类型转换;

  4. 对象上有属性和方法;

  5. 原始值上没有属性和方法;

  6. 原始值上也不能有属性和方法;

  7. 但我们可以像操作对象一样来操作原始值;

  8. 这是因为 JavaScript 在执行代码的时候偷偷搞小动作;

  9. JavaScript 会用临时的包装对象来替原始值执行操作。

以上是“JavaScript原始值与包装对象的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯