NodeJS 的深度扩展(如 jQuery)

发布于 2025-01-07 22:15:35 字数 211 浏览 2 评论 0原文

我正在努力处理 NodeJS 中对象的深层副本。我自己的扩展很糟糕。下划线的延伸是平坦的。 stackexchange 上有相当简单的扩展变体,但没有一个接近 jQuery.extend(true, {}, obj, obj, obj) .. (大多数实际上都很糟糕,并且破坏了 asnyc 代码的好处。)

因此,我的问题是:NodeJS 是否有一个好的深拷贝?有人移植过 jQuery 吗?

I am struggling with deep copies of objects in nodeJS. my own extend is crap. underscore's extend is flat. there are rather simple extend variants here on stackexchange, but none are even close to jQuery.extend(true, {}, obj, obj, obj) ..
(most are actually terrible and screw up the benefits of asnyc code.)

hence, my question: is there a good deep copy for NodeJS? Has anybody ported jQuery's ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

演多会厌 2025-01-14 22:15:35

已经移植了。 node-extend

注意该项目没有测试,也没有太多人气,所以使用风险由您自行承担。

如前所述,您可能不需要深层副本。尝试改变你的数据结构,这样你就只需要浅拷贝。

几个月后,

我编写了一个较小的模块,建议您使用 xtend。它没有包含 jQuery 包袱的实现,也没有像 node-extend 那样的错误。

It's already been ported. node-extend

Note the project doesn't have tests and doesn't have much popularity, so use at your own risk.

As mentioned you probably don't need deep copies. Try to change your data structures so you only need shallow copies.

Few months later

I wrote a smaller module instead, recommend you use xtend. It's not got an implementation containing jQuery baggage nor does it have bugs like node-extend does.

硪扪都還晓 2025-01-14 22:15:35

你想要 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

You want jQuery's, so just use it:

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;
    }

and a small test to show that it does deep copies

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

But remember to provide attribution: https://github.com/jquery/jquery/blob/master/src/core.js

辞旧 2025-01-14 22:15:35

对于深拷贝的一个快速而肮脏的答案就是用一点 JSON 来作弊。它不是性能最好的,但它确实非常好地完成这项工作。

function clone(a) {
   return JSON.parse(JSON.stringify(a));
}

A quick and dirty answer to deep copies is just to cheat with a little JSON. It's not the most performant, but it does do the job extremely well.

function clone(a) {
   return JSON.parse(JSON.stringify(a));
}
无力看清 2025-01-14 22:15:35

请使用内置的util模块:

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

var merged = extend(obj1, obj2);

Please use the built-in util module:

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

var merged = extend(obj1, obj2);
心清如水 2025-01-14 22:15:35

我知道这是一个老问题,但我只想将 lodash 的合并 作为一个好的解决方案。对于一般的实用函数,我推荐 lodash :)

I know this is an old question, but I'd just like to throw lodash's merge into the mix as a good solution. I'd recommend lodash for utility functions in general :)

难如初 2025-01-14 22:15:35

这适用于深层对象扩展...请注意,它替换数组而不是它们的值,但显然可以按照您的喜好进行更新。它应该保持枚举功能以及您可能希望它执行的所有其他操作

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);
        }
    });
}

This works for deep object extension... be warned that it replaces arrays rather than their values but that can obviously be updated how you like. It should maintain enumeration capabilities and all the other stuff you probably want it to do

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);
        }
    });
}
药祭#氼 2025-01-14 22:15:35

在 Node.js 中,您可以使用 Extendify 创建支持嵌套对象扩展的 _.extend 函数(深度扩展)并且对其参数也是不可变的(因此是深度克隆)。

_.extend = extendify({
    inPlace: false,
    isDeep: true
});

In Node.js, You can use Extendify to create an _.extend function that supports nested objects extension (deep extend) and is also immutable to it's params (hence deep clone).

_.extend = extendify({
    inPlace: false,
    isDeep: true
});
隱形的亼 2025-01-14 22:15:35

node.extend 做得很深入并且具有熟悉的 jQuery 语法

node.extend does it deep and has familiar jQuery syntax

流殇 2025-01-14 22:15:35

只需安装扩展即可。
文档:
节点扩展包
安装:

npm install extend

然后享受它:

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

深度是可选的。默认为 false。如果切换为 true 它将递归地合并你的对象。

just install extend.
docs:
node extend package
install:

npm install extend

then enjoy it:

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

deep is optional. default is false. if switch to true it will recursively merge your objects.

中二柚 2025-01-14 22:15:35

锐化版本称为 whet.extend

我用 CoffeeScript 重写 node-extend 并添加 travis-ci 测试套件,因为我需要深度为自己处理 Node ,所以现在它就在这里。

是的,我认为在某些情况下使用深度合并是绝对正确的,例如,当我们需要将默认分支和用户分支合并在一起时,我在配置工作中使用它。

Sharped version called whet.extend.

I re-write node-extend with CoffeeScript and add travis-ci test suite, because I need deep coping in Node for myself, so now it is here.

And yes, I think in some case its absolutely correctly to use deep merge, for example I use it at config works, when we are need to merge default and user branches together.

养猫人 2025-01-14 22:15:35

您也可以使用我的扩展插件版本
https://github.com/maxmara/dextend

You also can use my version of extend plugin
https://github.com/maxmara/dextend

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文