Object

几个额外的静态帮助方法已经被加入Object。从传统意义上讲,这种种类的函数是关注于对象值的行为/能力的。

但是,从ES6开始,Object静态函数还用于任意种类的通用全局API —— 那些还没有更自然地存在于其他的某些位置的API(例如,Array.from(..))。

Object.is(..) 静态函数

Object.is(..)静态函数进行值的比较,它的风格甚至要比===比较还要严格。

Object(..)调用底层的SameValue算法(ES6语言规范,第7.2.9节)。SameValue算法基本上与===严格等价比较算法相同(ES6语言规范,第7.2.13节),但是带有两个重要的例外。

考虑如下代码:

  1. var x = NaN, y = 0, z = -0;
  2. x === x; // false
  3. y === z; // true
  4. Object.is( x, x ); // true
  5. Object.is( y, z ); // false

你应当为严格等价性比较继续使用===Object.is(..)不应当被认为是这个操作符的替代品。但是,在你想要严格地识别NaN-0值的情况下,Object.is(..)是现在的首选方式。

注意: ES6还增加了一个Number.isNaN(..)工具(在本章稍后讨论),它可能是一个稍稍方便一些的测试;比起Object.is(x, NaN)你可能更偏好Number.isNaN(x)。你 可以 使用笨拙的x == 0 && 1 / x === -Infinity来准确地测试-0,但在这种情况下Object.is(x,-0)要好得多。

Object.getOwnPropertySymbols(..) 静态函数

第二章中的“Symbol”一节讨论了ES6中的新Symbol基本值类型。

Symbol可能将是在对象上最经常被使用的特殊(元)属性。所以引入了Object.getOwnPropertySymbols(..),它仅取回直接存在于对象上的symbol属性:

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

Object.setPrototypeOf(..) 静态函数

还是在第二章中,我们提到了Object.setPrototypeOf(..)工具,它为了 行为委托 的目的(意料之中地)设置一个对象的[[Prototype]](参见本系列的 this与对象原型)。考虑如下代码:

  1. var o1 = {
  2. foo() { console.log( "foo" ); }
  3. };
  4. var o2 = {
  5. // .. o2 的定义 ..
  6. };
  7. Object.setPrototypeOf( o2, o1 );
  8. // 委托至 `o1.foo()`
  9. o2.foo(); // foo

另一种方式:

  1. var o1 = {
  2. foo() { console.log( "foo" ); }
  3. };
  4. var o2 = Object.setPrototypeOf( {
  5. // .. o2 的定义 ..
  6. }, o1 );
  7. // 委托至 `o1.foo()`
  8. o2.foo(); // foo

在前面两个代码段中,o2o1之间的关系都出现在o2定义的末尾。更常见的是,o2o1之间的关系在o2定义的上面被指定,就像在类中,而且在对象字面量的__proto__中也是这样(参见第二章的“设置[[Prototype]]”)。

警告: 正如展示的那样,在对象创建之后立即设置[[Prototype]]是合理的。但是在很久之后才改变它一般不是一个好主意,而且经常会导致困惑而非清晰。

Object.assign(..) 静态函数

许多JavaScript库/框架都提供将一个对象的属性拷贝/混合到另一个对象中的工具(例如,jQuery的extend(..))。在这些不同的工具中存在着各种微妙的区别,比如一个拥有undefined值的属性是否被忽略。

ES6增加了Object.assign(..),它是这些算法的一个简化版本。第一个参数是 目标对象 而所有其他的参数是 源对象,它们会按照罗列的顺序被处理。对每一个源对象,它自己的(也就是,不是“继承的”)可枚举键,包括symbol,将会好像通过普通=赋值那样拷贝。Object.assign(..)返回目标对象。

考虑这种对象构成:

  1. var target = {},
  2. o1 = { a: 1 }, o2 = { b: 2 },
  3. o3 = { c: 3 }, o4 = { d: 4 };
  4. // 设置只读属性
  5. Object.defineProperty( o3, "e", {
  6. value: 5,
  7. enumerable: true,
  8. writable: false,
  9. configurable: false
  10. } );
  11. // 设置不可枚举属性
  12. Object.defineProperty( o3, "f", {
  13. value: 6,
  14. enumerable: false
  15. } );
  16. o3[ Symbol( "g" ) ] = 7;
  17. // 设置不可枚举 symbol
  18. Object.defineProperty( o3, Symbol( "h" ), {
  19. value: 8,
  20. enumerable: false
  21. } );
  22. Object.setPrototypeOf( o3, o4 );

仅有属性abce,和Symbol("g")将被拷贝到target

  1. Object.assign( target, o1, o2, o3 );
  2. target.a; // 1
  3. target.b; // 2
  4. target.c; // 3
  5. Object.getOwnPropertyDescriptor( target, "e" );
  6. // { value: 5, writable: true, enumerable: true,
  7. // configurable: true }
  8. Object.getOwnPropertySymbols( target );
  9. // [Symbol("g")]

属性df,和Symbol("h")在拷贝中被忽略了;非枚举属性和非自身属性将会被排除在赋值之外。另外,e作为一个普通属性赋值被拷贝,而不是作为一个只读属性被复制。

在早先一节中,我们展示了使用setPrototypeOf(..)来在对象o2o1之间建立一个[[Prototype]]关系。这是利用Object.assign(..)的另外一种形式:

  1. var o1 = {
  2. foo() { console.log( "foo" ); }
  3. };
  4. var o2 = Object.assign(
  5. Object.create( o1 ),
  6. {
  7. // .. o2 的定义 ..
  8. }
  9. );
  10. // 委托至 `o1.foo()`
  11. o2.foo(); // foo

注意: Object.create(..)是一个ES5标准工具,它创建一个[[Prototype]]链接好的空对象。更多信息参见本系列的 this与对象原型