глубокое расширение (как в jQuery) для nodeJS - PullRequest
42 голосов
/ 22 февраля 2012

Я борюсь с глубокими копиями объектов в nodeJS.мое собственное расширение это дерьмо.Удлинение подчеркивания плоское.Здесь есть довольно простые варианты расширений на stackexchange, но ни один из них даже не близок к jQuery.extend (true, {}, obj, obj, obj) .. (большинство из них на самом деле ужасны и испортят преимущества asnyc-кода.)

Отсюда мой вопрос: есть ли хорошая глубокая копия для NodeJS?Кто-нибудь портировал jQuery's?

Ответы [ 11 ]

27 голосов
/ 22 февраля 2012

Уже портировано. узел-простираться

Обратите внимание, что проект не имеет тестов и не пользуется большой популярностью, поэтому используйте его на свой страх и риск.

Как уже упоминалось, вам, вероятно, не нужны глубокие копии. Попробуйте изменить свои структуры данных так, чтобы вам требовались только мелкие копии.

Несколько месяцев спустя

Вместо этого я написал меньший модуль, рекомендую использовать xtend . У него нет реализации, содержащей багаж jQuery, и нет ошибок, как это делает node-extend.

14 голосов
/ 22 февраля 2012

Вам нужны jQuery, поэтому просто используйте его:

function extend() {
    var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {},
        i = 1,
        length = arguments.length,
        deep = false,
        toString = Object.prototype.toString,
        hasOwn = Object.prototype.hasOwnProperty,
        push = Array.prototype.push,
        slice = Array.prototype.slice,
        trim = String.prototype.trim,
        indexOf = Array.prototype.indexOf,
        class2type = {
          "[object Boolean]": "boolean",
          "[object Number]": "number",
          "[object String]": "string",
          "[object Function]": "function",
          "[object Array]": "array",
          "[object Date]": "date",
          "[object RegExp]": "regexp",
          "[object Object]": "object"
        },
        jQuery = {
          isFunction: function (obj) {
            return jQuery.type(obj) === "function"
          },
          isArray: Array.isArray ||
          function (obj) {
            return jQuery.type(obj) === "array"
          },
          isWindow: function (obj) {
            return obj != null && obj == obj.window
          },
          isNumeric: function (obj) {
            return !isNaN(parseFloat(obj)) && isFinite(obj)
          },
          type: function (obj) {
            return obj == null ? String(obj) : class2type[toString.call(obj)] || "object"
          },
          isPlainObject: function (obj) {
            if (!obj || jQuery.type(obj) !== "object" || obj.nodeType) {
              return false
            }
            try {
              if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
                return false
              }
            } catch (e) {
              return false
            }
            var key;
            for (key in obj) {}
            return key === undefined || hasOwn.call(obj, key)
          }
        };
      if (typeof target === "boolean") {
        deep = target;
        target = arguments[1] || {};
        i = 2;
      }
      if (typeof target !== "object" && !jQuery.isFunction(target)) {
        target = {}
      }
      if (length === i) {
        target = this;
        --i;
      }
      for (i; i < length; i++) {
        if ((options = arguments[i]) != null) {
          for (name in options) {
            src = target[name];
            copy = options[name];
            if (target === copy) {
              continue
            }
            if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
              if (copyIsArray) {
                copyIsArray = false;
                clone = src && jQuery.isArray(src) ? src : []
              } else {
                clone = src && jQuery.isPlainObject(src) ? src : {};
              }
              // WARNING: RECURSION
              target[name] = extend(deep, clone, copy);
            } else if (copy !== undefined) {
              target[name] = copy;
            }
          }
        }
      }
      return target;
    }

и небольшой тест, чтобы показать, что он делает глубокие копии

extend(true, 
    {
        "name": "value"
    }, 
    {
        "object": "value",
        "other": "thing",
        "inception": {
            "deeper": "deeper",
            "inception": {
                "deeper": "deeper",
                "inception": {
                    "deeper": "deeper"
                }
            }
        }
    }
)

Но не забудьте указать атрибуцию: https://github.com/jquery/jquery/blob/master/src/core.js

11 голосов
/ 28 января 2015

Пожалуйста, используйте встроенный модуль утилит:

var extend = require('util')._extend;

var merged = extend(obj1, obj2);
11 голосов
/ 10 октября 2012

Быстрый и грязный ответ на глубокие копии - просто обмануть с помощью небольшого JSON. Он не самый эффективный, но он отлично справляется со своей работой.

function clone(a) {
   return JSON.parse(JSON.stringify(a));
}
8 голосов
/ 19 февраля 2014

Я знаю, что это старый вопрос, но я просто хотел бы добавить слияние Лодаша в смесь как хорошее решение. Я бы порекомендовал lodash для служебных функций в целом:)

1 голос
/ 25 апреля 2017

просто установите расширение. документы: узел расширения пакета установить:

npm install extend

тогда наслаждайся:

extend ( [deep], target, object1, [objectN] )

глубина не обязательна. по умолчанию ложь. если переключиться в true, он рекурсивно объединит ваши объекты.

1 голос
/ 07 февраля 2017

node.extend делает это глубоко и имеет знакомый синтаксис jQuery

1 голос
/ 05 июля 2014

В Node.js вы можете использовать Extendify , чтобы создать функцию _.extend, которая поддерживает расширение вложенных объектов (глубокое расширение) и также неизменна для его параметров (следовательно, глубокое клонирование).

_.extend = extendify({
    inPlace: false,
    isDeep: true
});
1 голос
/ 16 ноября 2012

Это работает для глубокого расширения объекта ... имейте в виду, что оно заменяет массивы, а не их значения, но это, очевидно, может быть обновлено, как вам нравится.Он должен поддерживать возможности перечисления и все остальные вещи, которые вы, вероятно, хотите, чтобы он делал

function extend(dest, from) {
    var props = Object.getOwnPropertyNames(from), destination;

    props.forEach(function (name) {
        if (typeof from[name] === 'object') {
            if (typeof dest[name] !== 'object') {
                dest[name] = {}
            }
            extend(dest[name],from[name]);
        } else {
            destination = Object.getOwnPropertyDescriptor(from, name);
            Object.defineProperty(dest, name, destination);
        }
    });
}
0 голосов
/ 20 апреля 2013

Вы также можете использовать мою версию плагина расширения https://github.com/maxmara/dextend

...