JavaScript深入之类型转换

JavaScript 是弱类型的语言,它的取值非常灵活。你期望一种类型值的时候,你可以提供任何类型的值,JavaScript 将根据需要自行转换类型,在 JavaScript 中通常将它们统称为 强制类型转换

ECMAScript 规范Type Conversion 章节中定义了转换规则。这里我们着重介绍 **ToPrimitiveToBoolean**、 ToNumberToString

ToPrimitive

在 JavaScript 中,想要将对象转换成原始值,必然会调用 toPrimitive()内部函数,那么它是如何工作的呢?

1
2
ToPrimitive(input [, PreferredType])
input 是输入的值,preferedType 是期望转换的类型,
输入类型 结果
Undefined 返回 input 自身
Null 返回 input 自身
Boolean 返回 input 自身
Number 返回 input 自身
String 返回 input 自身
Symbol 返回 input 自身
Object 返回该对象的默认值。具体过程请(通过内部操作 DefaultValue ,参见 ES5 规范 8.12.8 节)

如果 PreferredType 是 Number,执行顺序如下:

  1. 如果 input 为 primitive,返回。
  2. 否则,input 为 Object。调用 obj.valueOf()。如果结果是 primitive,返回。
  3. 否则,调用 obj.toString(). 如果结果是 primitive,返回。
  4. 如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。
  5. 如果 PreferredType 是 String,步骤 2 跟 3 互换,如果 PreferredType 为空,Date 类型默认为 String,其他都是 Number。

ToBoolean

ToBoolean 运算符根据下表将其参数转换为布尔值类型的值:

输入类型 结果
Undefined false
Null false
Boolean 结果等于输入的参数(不转换)。
Number 如果参数是 +0, -0, 或 NaN,结果为 false ;否则结果为 true。
String 如果参数参数是空字符串(其长度为零),结果为 false,否则结果为 true。
Object true
Symbol true

ToNumber

ToNumber 运算符根据下表将其参数转换为数值类型的值:

输入类型 结果
Undefined NaN
Null +0
Boolean 如果参数是 true,结果为 1。如果参数是 false,此结果为 +0。
Number 直接返回。
String 参见下文的文法和注释。
Symbol TypeError
Object 执行下列步骤:
1. 设 primValue 为 ToPrimitive( 输入参数 , hint Number)。
2.返回 ToNumber(primValue)。

ToString

ToString 运算符根据下表将其参数转换为字符串类型的值:

输入类型 结果
Undefined “undefined”
Null “null”
Boolean 如果参数是 true,那么结果为 “true”。
如果参数是 false,那么结果为 “false”。
Number 详见7.1.12.1NumberToString
String 直接返回 。
Symbol TypeError
Object 执行下列步骤:
1、设 primValue 为 ToPrimitive( 输入参数 , hint String)。
2、返回 ToString(设 primValue 为 )。

参考资料

Type Conversion and Testing
Type Conversion

JavaScript深入之引用类型

基本类型

JavaScript 变量可以用来保存两种类型的值:基本类型值和引用类型值。基本类型值指的是 简单的数据段,包括以下 6 种基本数据类型:Undefined、Null、Boolean、Number 、 String 和 Symbol。
基本类型保存在栈中,存储的是具体的值,是轻量级的数据存储方式。

引用类型

引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存中的位置, 也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。 为此,引用类型的值是按引用访问的。

Object 类型

Object 是一个基础类型,其他所有类型都从 Object 继承了基本的行为。
创建 Object 实例的方式有两种。第一种是使用 new 操作符后跟 Object 构造函数,另一种方式是使用对象字面量表示法。

1
2
3
4
5
6
7
8
9
10
// new操作符创建对象
let person1 = new Object();
person.name = 'Zubin';
person.age = 18;

// 字面量表示法
let person2 = {
name: 'Zubin',
age: 18,
};

Array 对象

除了 Object 之外,Array 类型恐怕是 ECMAScript 中最常用的类型了。而且,ECMAScript 中 的数组与其他多数语言中的数组有着相当大的区别。

  • ECMAScript 数组的每一项可以保存任何类型的数据。
  • ECMAScript 数组的大小是可以动态调整的,即可以随着数据的添加自动增长以容 纳新增数据。

方法:

  1. Array.from()
    从类数组对象或者可迭代对象中创建一个新的数组实例。

  2. Array.isArray()
    用来判断某个变量是否是一个数组对象。

  3. Array.of()
    根据一组参数来创建新的数组实例,支持任意的参数数量和类型。

数组实例的常用方法:

方法名称 说明
concat 用于连接两个或更多的数组并返回结果,arr1.concat(arr2)
join 把数组的所有元素放入一个字符串,元素通过制定的分隔符进行分离 arr1.join(‘,’)
pop 删除并返回数组中的最后一个元素 arr1.pop()
push 向数组的末尾添加一个或更多元素,并返回新的长度 arr1.push(1)
reverse 颠倒数组中的元素顺序,arr1.reverse()
shift 删除并返回数组中的第一个元素 arr1.shift()
slice 从某个已有的数组返回指定的元素
sort 对数组的元素进行排序 arr1.sort()
splice 删除元素,并向数组中添加新元素
toString 把数组转成字符串 arr1.toString()
toLocaleString 把数组转换为本地字符串 arr1.toLocaleString()
valueOf 返回数组对象的原始值

Date 对象

创建 Date 实例用来处理日期和时间。Date 对象基于 1970 年 1 月 1 日(世界标准时间)起的毫秒数。

1
2
3
4
5
6
7
8
var today = new Date();
var today = new Date(1453094034000); // by timestamp(accurate to the milliseconds)
var birthday = new Date('December 17, 1995 03:24:00');
var birthday = new Date('1995-12-17T03:24:00');
var birthday = new Date(1995, 11, 17);
var birthday = new Date(1995, 11, 17, 3, 24, 0);

var unixTimestamp = Date.now(); // in milliseconds

方法

  1. Date.now()
    返回自 1970-1-1 00:00:00 UTC (世界标准时间)至今所经过的毫秒数。
  2. Date.parse()
    解析一个表示日期的字符串,并返回从 1970-1-1 00:00:00 所经过的毫秒数。
  3. Date.UTC()
    接受和构造函数最长形式的参数相同的参数(从 2 到 7),并返回从 1970-01-01 00:00:00 UTC 开始所经过的毫秒数。

RegExp 类型

类型是 ECMAScript 支持正则表达式的一个接口,提供了最基本的和一些高级的正则表 达式功能。

1
2
3
4
5
6
7
8
9
10
11
var regex1 = /\w+/;
var regex2 = new RegExp('\\w+');

console.log(regex1);
// expected output: /\w+/

console.log(regex2);
// expected output: /\w+/

console.log(regex1 === regex2);
// expected output: false

Function 类型

Function 构造函数 创建一个新的 Function 对象。 在 JavaScript 中, 每个函数实际上都是一个 Function 对象。

1
2
3
4
var sum = new Function('a', 'b', 'return a + b');

console.log(sum(2, 6));
// expected output: 8

参考文档

MDN JavaScript
JavaScript 高级程序设计(第 3 版)

JavaScript深入之原生函数

JavaScript 为基本数据类型值提供了封装对象,称为原生函数,常见的原生函数包括

  • String()
  • Number()
  • Boolean()
  • Array()
  • Object()
  • Function()
  • RegExp()
  • Date()
  • Error()
  • Symbol()

它们可以被当作构造函数来使用, 但其构造出来的对象可能会和我们设想的有所 出入

1
2
3
4
let a = new String('abc');
typeof a; // 是"object",不是"String"
a instanceof String; // true
Object.prototype.toString.call(a); // "[object String]"

通过构造函数(如 new String(“abc”) )创建出来的是封装了基本类型值(如 “abc” )的封 装对象。

内部属性[[Class]]

所有 typeof 返回值为 “object” 的对象(如数组)都包含一个内部属性 [[Class]] (我们可 以把它看作一个内部的分类,而非传统的面向对象意义上的类)。这个属性无法直接访问, 一般通过 Object.prototype.toString(..) 来查看。例如:

1
2
3
4
5
6
7
8
9
Object.prototype.toString.call([1, 2, 3]); // "[object Array]"
Object.prototype.toString.call(/regex-literal/i); // "[object RegExp]"

Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"

Object.prototype.toString.call('abc'); // "[object String]"
Object.prototype.toString.call(42); // "[object Number]"
Object.prototype.toString.call(true); // "[object Boolean]"

内部属性和创建该对象的内建原生构造函数相对应,虽然 Null() 和 Undefined() 这样的原生构造函数并不存在,但是内部属性值仍 然是 “Null” 和 “Undefined” 。
其他基本类型值(如字符串、数字和布尔)的情况有所不同,它们的值被各自的封装对象自动包装,所以它们的内部属性值分别为 “String” 、 “Number” 和 “Boolean” 。

封装

原生函数为基本数据类型值提供了该子类型所特有的方法和属性(如:String#trim() 和 Array#concat(..))。

对于简单标量基本类型值,比如 “abc” ,如果要访问它的 length 属性或 String.prototype 方法, JavaScript 引擎会自动对该值进行封装(即用相应类型的封装对象来包装它)来实现对这些属性和方法的访问。

1
2
3
4
5
6
7
8
9
var a = 'abc';

a.length; // 3
a.toUpperCase(); // "ABC"

var b = new Boolean(false);
if (!b) {
console.log('Oops'); // 执行不到这里
}

拆封

如果想要得到封装对象中的基本类型值,可以使用 valueOf() 函数:

1
2
3
4
5
6
7
var a = new String('abc');
var b = new Number(42);
var c = new Boolean(true);

a.valueOf(); // "abc"
b.valueOf(); // 42
c.valueOf(); // true

参考文档

你不知道的 JavaScript(中卷)

JavaScript深入之数据类型

一、内置类型

最新的 ECMAScript 标准定义了 7 种数据类型:

  • 空值(null)
  • 未定义(undefined)
  • 布尔值(boolean)
  • 数字(number)
  • 字符串(string)
  • 符号(symbol,ES6 中新增)
  • 对象(object)

除对象为“复杂类型”之外,其他统称为“基本类型”。

阅读更多

JavaScript面向对象有感

面向对象程序设计(简称 OOP)是现在最流行的程序设计方法,JavaScript 的核心是支持面向对象的,Prototype 是 JavaScript 实现与管理继承的一种机制。最近在读《你不知道的 JavaScript》一书中了解到除了使用类实现外,还可以用一种“对象关联”(OLOO,objects linked to other objects)的编程风格

阅读更多

《你不知道的JavaScript》笔记-闭包

闭包就好像从 JavaScript 中分离出来的一个充满神秘色彩的未开化世界,只有最勇敢的人才能够到达那里。但实际上它只是一个普通且明显的事实,那就是我们在词法作用域的环境下写代码,而其中的函数也是值,可以随意传来传去。

当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包。

阅读更多

《你不知道的JavaScript》笔记-this用法

this 绑定规则

this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各种条件。this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。

当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方式、传入的参数等信息。this 就是这个记录的一个属性,会在函数执行的过程中用到。

阅读更多