什么是纯粹的JS对象??

昨天我们的分享会聊到ES6的collections部分,回头我看了下es6-in-depth,里面有这么一句话:“纯粹的对象不可遍历,也就是,它们不能配合for-of
循环或...操作符等语法。”
阿咧?!纯粹的对象是什么鬼👻。。。

传统的JS对象都是不纯粹的

var obj = {},你觉得obj是个纯粹的对象嘛?答案是否定的。
控制台里敲上上线的语句,然后看看obj是什么:

你可能觉得obj = {},它就什么都没有了,但实际上{}这个东西的声明方式是通过原型链继承了Object,也就生来自带了Object的一系列内置属性和方法,不信你可以继续验证:


所以说,
var obj = {}相当于是执行了这个语句 var obj = Object.create(Object.prototype)

那么到这里为止,我们就可以知道var obj = {}声明得到的obj,它一点儿都不纯粹。然而悲催的是,虽然它生来自带了一串东西,但是这些东西不是enumerable的,所以又不能被遍历出来。用obj.propertyIsEnumerable()来判断,都是false;用for...in遍历,毛线都没有。

怎么才能纯粹?

答案是Object.create(null),我们可以先验证一下:


没有那一串内置属性和方法了,干干净净的。而且完全不是继承Object得来的:

为什么是纯粹的?

那就要看下Object.create()是怎么实现的了... 这里是一段Object.create()的polyfill:

if (typeof Object.create != 'function') {
  // Production steps of ECMA-262, Edition 5, 15.2.3.5
  // Reference: http://es5.github.io/#x15.2.3.5
  Object.create = (function() {
    //为了节省内存,使用一个共享的构造器
    function Temp() {}

    // 使用 Object.prototype.hasOwnProperty 更安全的引用 
    var hasOwn = Object.prototype.hasOwnProperty;

    return function (O) {
      // 1. 如果 O 不是 Object 或 null,抛出一个 TypeError 异常。
      if (typeof O != 'object') {
        throw TypeError('Object prototype may only be an Object or null');
      }

      // 2. 使创建的一个新的对象为 obj ,就和通过
      //    new Object() 表达式创建一个新对象一样,
      //    Object是标准内置的构造器名
      // 3. 设置 obj 的内部属性 [[Prototype]] 为 O。
      Temp.prototype = O;
      var obj = new Temp();
      Temp.prototype = null; // 不要保持一个 O 的杂散引用(a stray reference)...

      // 4. 如果存在参数 Properties ,而不是 undefined ,
      //    那么就把参数的自身属性添加到 obj 上,就像调用
      //    携带obj ,Properties两个参数的标准内置函数
      //    Object.defineProperties() 一样。
      if (arguments.length > 1) {
        // Object.defineProperties does ToObject on its first argument.
        var Properties = Object(arguments[1]);
        for (var prop in Properties) {
          if (hasOwn.call(Properties, prop)) {
            obj[prop] = Properties[prop];
          }
        }
      }

      // 5. 返回 obj
      return obj;
    };
  })();
}

从代码里很明显能看到create的操作过程:
判断,然后把O本身的属性(并没有Object里面内置的属性)一个个赋值给用临时构造器Temp生成的obj上,作为obj的属性。所以如果O是null的话,O没有属性,obj也就什么都没有。

纯粹了又能怎样

噢那纯粹了的话好处可多了。
如果拿不纯粹的空对象做计算的话,totally懵逼的好嘛!
({} + 1).length === 16 //true !!


当然啦,如果你弄得清楚是因为Object.valueOf()Object.toString()在背后搞的鬼也算还好,但这种东西看到了真的只想说“扎心了老铁”。

那如果拿纯粹的对象做计算的话,sorry,I'm pure and I do not have the 'valueOf' and the 'toString' to help me calculating ...


用一句别人的话来说“「纯粹」的对象适合用于存储键值对数据,而且没有隐式的类型转换,更加直观。”

当然了,除了继承了Object.prototype这点,Object.create(null){}之间没有别的区别了,在操作对象这一点上完全一致,存取的性能没差啦。但如果并不care自己的空对象继承了Object的话,宝宝们还是使用{}来声明吧,因为在创建性能上{}Object.create(null) 快了20倍呢!!!

推荐阅读更多精彩内容