作用于自身以使用另一个对象扩展自身的 JavaScript 函数

chr*_*ixm 0 javascript

我确信我正在尝试做的事情有一个名称,并且我确信以前有人问过这个问题,但我正在努力寻找现有的答案 - 可能是因为我没有在寻找正确的术语。我有一个 JavaScript 函数被调用extend(),它类似于Object.assign()将对象合并在一起 -Object.assign在我当前的实现中我无权访问。

function extend(target) {
  for (var i = 1; i < arguments.length; ++i) {
    if (typeof arguments[i] !== 'object') {
      continue;
    }
    for (var j in arguments[i]) {
      if (arguments[i].hasOwnProperty(j)) {
        if (typeof arguments[i][j] === 'object') {
          target[j] = extend({}, target[j], arguments[i][j]);
        }
        else if (!target.hasOwnProperty(j)) {
          target[j] = arguments[i][j];
        }
      }
    }
  }
  return target;
}
Run Code Online (Sandbox Code Playgroud)

如果我调用它 using extend(target, defaults)which 将合并defaultsinto的内容target而不覆盖任何现有的键,这很好用target(除非它们是对象,然后它们被合并)。

我正在寻找一种方法来实际调用它 using target.extend(defaults),因此第一个target参数extend实际上隐含为this. 我试图通过更换重写功能targetthis,但它不具有所期望的结果(我想我已经改变了递归的方法是错误的)。

target.extend = function() {
   ...
   this[j] = this.extend(this[j], arguments[i][j]);
   ...
   return this;
};
Run Code Online (Sandbox Code Playgroud)

任何指针(或对现有答案的引用)将不胜感激。

Cer*_*nce 5

您可以分配函数以Object.prototype实现您正在寻找的功能:

Object.defineProperty(
  Object.prototype,
  'extend',
  {
    enumerable: false,
    value: function() {
      const target = this;
      for (var i = 0; i < arguments.length; ++i) {
        if (typeof arguments[i] !== 'object') {
          continue;
        }
        for (var j in arguments[i]) {
          if (arguments[i].hasOwnProperty(j)) {
            if (typeof arguments[i][j] === 'object') {
              target[j] = extend({}, target[j], arguments[i][j]);
            }
            else if (!target.hasOwnProperty(j)) {
              target[j] = arguments[i][j];
            }
          }
        }
      }
      return target;
    }
  }
);


const obj = { foo: 'foo' };
obj.extend({ bar: 'bar' });
console.log(obj);
Run Code Online (Sandbox Code Playgroud)

或者,清理一堆代码:

Object.defineProperty(
  Object.prototype,
  'extend',
  {
    enumerable: false,
    value: function(...args) {
      const target = this;
      for (const arg of args) {
        for (const [key, val] of Object.entries(arg)) {
          if (typeof val === 'object') extend(target[key], val);
          else target[key] = val;
        }
      }
    }
  }
);


const obj = { foo: 'foo' };
obj.extend({ bar: 'bar' });
console.log(obj);
Run Code Online (Sandbox Code Playgroud)

但这是一个坏主意,因为它会导致名称冲突和混淆代码。如果有一个像

const obj = { extend: true };
Run Code Online (Sandbox Code Playgroud)

obj.extend做什么呢?(它会引用自己的属性,但这不是脚本编写者应该担心的事情。最好有一个独立的功能。)

这与为什么许多 Object 辅助方法存在于Object 构造函数中而不是Object.prototype. 例如,您调用Object.assign, or Object.defineProperty, not obj.assign or obj.defineProperty

如果您只想在某些对象上使用此功能,则可以通过调用Object.defineProperty这些对象来避免原型污染:

const obj = { extend: true };
Run Code Online (Sandbox Code Playgroud)

或者,如果你有创建对象,其中在控制,您可以使用Object.create,这样extend是从原型继承的方法:

const addExtend = obj => {
  Object.defineProperty(
    obj,
    'extend',
    {
      enumerable: false,
      value: function(...args) {
        const target = this;
        for (const arg of args) {
          for (const [key, val] of Object.entries(arg)) {
            if (typeof val === 'object') extend(target[key], val);
            else target[key] = val;
          }
        }
      }
    }
  );
};

const obj = { foo: 'foo' };
addExtend(obj);
obj.extend({ bar: 'bar' });
console.log(obj);
Run Code Online (Sandbox Code Playgroud)