OPY-bbt / OPY-bbt.github.io

my webpage
https://opy-bbt.github.io/
0 stars 0 forks source link

Spread Properties 与Object.assign的区别 #27

Open OPY-bbt opened 4 years ago

OPY-bbt commented 4 years ago

Object.assign 将所有可枚举属性的值从一个或多个源对象复制到目标对象

OPY-bbt commented 4 years ago
Object.defineProperty(Object, "assign", {
    value: function assign(target, varArgs) { // .length of function is 2
      'use strict';
      if (target == null) { // TypeError if undefined or null
        throw new TypeError('Cannot convert undefined or null to object');
      }

      let to = Object(target);

      for (var index = 1; index < arguments.length; index++) {
        var nextSource = arguments[index];

        if (nextSource != null) { // Skip over if undefined or null
          for (let nextKey in nextSource) {
            // Avoid bugs when hasOwnProperty is shadowed
            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
      return to;
    },
    writable: true,
    configurable: true
  });
OPY-bbt commented 4 years ago

Object.assign 会使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。所以无法将setter和getter复制到目标对象中。

例如

const obj = {
  foo: 1,
  get bar() {
    return 2;
  }
};

var copy = Object.assign({}, obj); 
console.log(copy); // { foo: 1, bar: 2 } copy.bar的值来自obj.bar的getter函数的返回值
OPY-bbt commented 4 years ago

看一下Spread经过babel编译之后的结果

      "use strict";

      function ownKeys(object, enumerableOnly) {
        var keys = Object.keys(object);
        if (Object.getOwnPropertySymbols) {
          var symbols = Object.getOwnPropertySymbols(object);
          if (enumerableOnly)
            symbols = symbols.filter(function(sym) {
              return Object.getOwnPropertyDescriptor(object, sym).enumerable;
            });
          keys.push.apply(keys, symbols);
        }
        return keys;
      }

      function _objectSpread(target) {
        for (var i = 1; i < arguments.length; i++) {
          var source = arguments[i] != null ? arguments[i] : {};
          if (i % 2) {
            ownKeys(Object(source), true).forEach(function(key) {
              _defineProperty(target, key, source[key]);
            });
          } else if (Object.getOwnPropertyDescriptors) {
            Object.defineProperties(
              target,
              Object.getOwnPropertyDescriptors(source)
            );
          } else {
            ownKeys(Object(source)).forEach(function(key) {
              Object.defineProperty(
                target,
                key,
                Object.getOwnPropertyDescriptor(source, key)
              );
            });
          }
        }
        return target;
      }

      function _defineProperty(obj, key, value) {
        if (key in obj) {
          Object.defineProperty(obj, key, {
            value: value,
            enumerable: true,
            configurable: true,
            writable: true
          });
        } else {
          obj[key] = value;
        }
        return obj;
      }
OPY-bbt commented 4 years ago

例子:

const obj = {a: 10};
const obj2 = {b: 10};
console.log({...obj, ...obj2 });

结果:

var obj = { a: 10 };
var obj2 = {b: 10};
console.log(_objectSpread({}, obj, {}, obj2));
OPY-bbt commented 4 years ago

下面看一个综合的例子

Object.defineProperty(Object.prototype, 'a', {
  set(value) {
    console.log('set called!');
  }
});

const obj = {a: 10};

console.log({...obj});    
// → {a: 10}

console.log(Object.assign({}, obj));    
// → set called!
// → {}

从例子中可以看出使用spread操作符,不会调用到目标对象的setter方法,而是覆盖了