记录ES6 为各种内置原生类型和对象新增的静态属性和方法

269 阅读6分钟

前言

本文参考了 《你不知道的JavaScript(下)》

从值的转换到数学计算,ES6 为各种内置原生类型和对象新增了很多静态属性和方法,用 来辅助完成一些常见的任务。另外,某些原生类型的实例通过新的原型方法有了新的功能。

本文会介绍 Array,Object,Number,String四个内置对象新增的一些api,在不同的阶段读相同的书会有不一样的收获,也许这一次的认真思考后我们会多一种实现方式。 0030F061.png

Array

静态函数 Array.of(..)

Array(..) 构造器有一个众所周知的陷阱,就是如果只传入一个参数,并且这个参数是数 字的话,那么不会构造一个值为这个数字的单个元素的数组,而是构造一个空数组,其 length 属性为这个数字。这个动作会产生不幸又诡异的“空槽”行为,这是 JavaScript 数组广为人所诟病的一点。

Array.of(..) 取代了 Array(..) 成为数组的推荐函数形式构造器,因为 Array.of(..) 并没 有这个特殊的单个数字参数的问题。考虑:

// Array(..)
var a = Array(3); // [empty × 3]
a.length;         // 3
a[0];             // undefined

// Array.of(..)
var b = Array.of(3); // [3]
b.length;            // 1
b[0];                // 3

静态函数 Array.from(..)

JavaScript 中的“类(似)数组对象”是指一个有 length 属性。但不能使用数组的其他api,比如函数的arguments , 还有NodeList

普遍的需求就是把它们转 换为真正的数组,这样就可以应用各种 Array.prototype 方法。Array.from(..)便是优雅简洁的实现方法

function test(){
 console.log(Array.from(arguments).map(item => item))
}
test(1,2,3,4) // [1,2,3,4]

原型方法 copyWithin(..)

Array#copyWithin(..) 是一个新的修改器方法,(包括带类型的数组在内的) 所有数组都支持。copyWithin(..) 从一个数组中复制一部分到同一个数组的另一个位置, 覆盖这个位置所有原来的值。 参数是 target(要复制到的索引)、start(开始复制的源索引,包括在内)以及可选的 end (复制结束的不包含索引)。如果任何一个参数是负数,就被当作是相对于数组结束的相 对值。 考虑:

[1,2,3,4,5].copyWithin( 3, 0 );      // [1,2,3,1,2] 
[1,2,3,4,5].copyWithin( 3, 0, 1 );   // [1,2,3,1,5] 
[1,2,3,4,5].copyWithin( 0, -2 );     // [4,5,3,4,5]
[1,2,3,4,5].copyWithin( 0, -2, -1 ); // [4,2,3,4,5]

原型方法 fill(...)

可以通过 ES6 原生支持的方法 Array#fill(..) 用指定值完全(或部分)填充已存在的数 组:

考虑如下代码

// Array(..)
var a = Array(3); // [empty × 3]
a.length;         // 3
a[0];             // undefined

现在我们希望数组每一项默认用{}来填充

var a = Array(3).fill({}) // [{},{},{}]
// fill(..) 可选地接收参数 start 和 end,它们指定了数组要填充的子集位置,比如:
var b = Array(3).fill({} , 1,2) // [empty, {}, empty]

原型方法 entries()values()keys()

以从传统角度来说,它可能不会被看作是 “集合”,但是它提供了同样的迭代器方法 entries()values()keys(),从这个意义上 说,它是一个集合。考虑:

var a = [1,2,3]; 
[...a.values()];   // [1,2,3] 
[...a.keys()];    // [0,1,2] 
[...a.entries()]; // [ [0,1], [1,2], [2,3] ]

Object

静态函数 Object.is(..)

静态函数 Object.is(..) 执行比 === 比较更严格的值比较。考虑:

var x = NaN, y = 0, z = -0; 
x === x;           // false 
y === z;           // true 
Object.is( x, x ); // true 
Object.is( y, z ); // false

如果需要严格识别 NaN 或者 -0 值,那么应该选择 Object.is(..)

静态函数 Object.getOwnPropertySymbols(..)

Symbol 很 可 能 会 成 为 对 象 最 常 用 的 特 殊( 元 ) 属 性。 所 以 引 入 了 工 具 Object. getOwnPropertySymbols(..),它直接从对象上取得所有的符号属性:

var o = { 
foo: 42, 
[ Symbol( "bar" ) ]: "hello world", 
baz: true 
};
Object.getOwnPropertySymbols( o ); // [ Symbol(bar) ]

静态函数Object.setPrototypeOf(..)

设置对象的[[Prototype]]用于行为委托 , 考虑:

var o1 = { 
    foo() { console.log( "foo" ); 
    } 
}; 
var o2 = { 
// .. o2的定义 .. 
}; 
Object.setPrototypeOf( o2, o1 ); // 委托给o1.foo() 
o2.foo(); // foo

静态函数 Object.assign(..)

很多 JavaScript 库 / 框架提供了用于把一个对象的属性复制 / 混合到另一个对象中的工具 (比如,JQuery extent(..))。这些不同的工具之间有各种细微的区别,比如是否忽略值 为 undefined 的属性。

ES6 新增了 Object.assign(..),这是这些算法的简化版本。第一个参数是 target,其他 传入的参数都是源,它们将按照列出的顺序依次被处理。对于每个源来说,它的可枚举 和自己拥有的(也就是不是“继承来的”)键值,包括符号都会通过简单 = 赋值被复制。 Object.assign(..) 返回目标对象。

考虑这个对象设定:

var target = {}, o1 = { a: 1 }, o2 = { b: 2 }, o3 = { c: 3 }, o4 = { d: 4 }; 
// 设定只读属性 
Object.defineProperty( o3, "e", {
    value: 5,
    enumerable: true, 
    writable: false,
    configurable: false 
} ); 
// 设定不可枚举属性 
Object.defineProperty( o3, "f", { 
    value: 6, 
    enumerable: false 
} ); 
o3[ Symbol( "g" ) ] = 7; 
// 设定不可枚举符号 
Object.defineProperty( o3, Symbol( "h" ), {
value: 8, 
enumerable: false 
} ); 
Object.setPrototypeOf( o3, o4 ); 
只有属性 a、b、c、e 以及 Symbol("g") 会被复制到 target 中:
Object.assign( target, o1, o2, o3 ); 
target.a; // 1 
target.b; // 2 
target.c; // 3 
Object.getOwnPropertyDescriptor( target, "e" ); 
// { value: 5, writable: true, enumerable: true, 
// configurable: true } 
Object.getOwnPropertySymbols( target ); // [Symbol("g")]

Number

更重要的是,要让程序正常工作,必须精确处理数字。

ES6 新增了额外的属性和函数来提 供常用数字运算。

Number 的两个新增内容就是指向已有的全局函数的引用:Number.parseInt(..)Number.parseFloat(..)

Number的静态属性

Number.EPSILON 任意两个值之间的最小差:2^-52

Number.MAX_SAFE_INTEGER JavaScript 可以用数字值无歧义“安全”表达的最大整数:2^53 - 1

Number.MIN_SAFE_INTEGER JavaScript 可以用数字值无歧义“安全”表达的最小整数:-(2^53 - 1) 或 (-2)^53 + 1

静态函数 Number.isNaN(..)

标准全局工具 isNaN(..) 自出现以来就是有缺陷的,它对非数字的东西都会返回 true,而 不是只对真实的 NaN 值返回 true,因为它把参数强制转换为数字类型(可能会错误地导致NaN)。

ES6 增加了一个修正工具 Number.isNaN(..),可以按照期望工作:

var a = NaN, b = "NaN", c = 42; 
isNaN( a ); // true 
isNaN( b ); // true--oops! 
isNaN( c ); // false 
// ---------------------
Number.isNaN( a ); // true 
Number.isNaN( b ); // false--修正了! 
Number.isNaN( c ); // false

静态函数 Number.isFinite(..)

看到像 isFinite(..) 这样的函数名,我们常常认为它的意思就是“非无限的”。但是这并 不完全正确。这个 ES6 新工具有一些微妙之处。考虑:

var a = NaN, b = Infinity, c = 42; 
Number.isFinite( a ); // false 
Number.isFinite( b ); // false 
Number.isFinite( c ); // true

标准的全局 isFinite(..) 会对参数进行强制类型转换,但是 Number.isFinite(..) 会略去 这种强制行为:

var a = "42"; 
isFinite( a ); // true 
Number.isFinite( a ); // false

String

静态函数String.raw(..)

String.raw(..) 工具作为内置标签函数提供,与模板字符串字面值一起使 用,用于获得不应用任何转义序列的原始字符串。

这个函数基本上不会被手动调用,而是与标签模板字面值一起使用:

var str = "bc"; 
String.raw`\ta${str}d\xE9`; // "\tabcd\xE9", 而不是" abcdé"

原型函数 repeat(..)

PythonRuby 这样的语言中,可以这样重复字符串: "foo" * 3; // "foofoofoo"

JavaScript 不支持这种形式,因为乘法 * 只对数字有定义,因此 "foo" 被强制转换成了数 字 NaN。

然而,ES6定义了一个字符串原型方法 repeat(..) 来完成这个任务:

"foo".repeat( 3 ); // "foofoofoo"

字符串检查函数

除了 ES6 之前的 String#indexOf(..)String#lastIndexOf(..),又新增了 3 个用于搜索 / 检查的新方法:startsWith(..)endsWidth(..)includes(..)

var palindrome = "step on no pets"; 
palindrome.startsWith( "step on" ); // true 
palindrome.startsWith( "on", 5 );  // true 
palindrome.endsWith( "no pets" );  // true 
palindrome.endsWith( "no", 10 );  // true 
palindrome.includes( "on" );      // true 
palindrome.includes( "on", 6 );   // false

END