简体   繁体   English

jQuery.extend使用自引用引发堆栈溢出异常

[英]jQuery.extend throws stack overflow exception with self references

I was working on a JavaScript application when I noticed that: using jQuery.extend function has a special behaviour when used with object that have a reference to them self. 我注意到一个JavaScript应用程序时:使用jQuery.extend函数与具有自身引用的对象一起使用时,具有特殊的行为。

If you run this script: 如果运行脚本:

var x = new (function(){ this.self = this });
var y = {}; y.self = y;

console.log($.extend(true, {}, x))
console.log($.extend(true, {}, y))

You will notice that the extending with 'x' works fine, while extending with 'y' throws a stack overflow exception. 您会注意到,用'x'扩展可以正常工作,而用'y'扩展可以引发堆栈溢出异常。

Can you explain this behaviour? 您能解释一下这种行为吗?

The difference is whether the object is a plain object or not. 区别在于对象是否为普通对象。 x had a constructor; x有一个构造函数; so when extend comes to the value of self , I suppose jQuery doesn't want to deep copy it, since it doesn't know that it can recreate it properly, and ends up with just a plain, non-deep copy for that attribute. 因此,当extend涉及self的值时,我想jQuery不想对其进行深度复制,因为它不知道它可以正确地重新创建它,并且最终仅对该属性进行了普通的非深度复制。

y , on the other hand, checks out as a POJO, and extend thinks it's okay to deep-copy it, which results in the infinite recursion. 另一方面, y作为POJO签出,并且extend认为可以对其进行深复制,从而导致无限递归。

Look at extend code , where it says " // Recurse if we're merging plain objects or arrays " 看一下extend代码 ,它上面写着“ // Recurse if we're merging plain objects or arrays ,则// Recurse if we're merging plain objects or arrays

jQuery's .extend() does a deep copy of plain objects and arrays, but not a deep copy of function objects. jQuery的.extend()可以对普通对象和数组进行深层复制,而不能对函数对象进行深层复制。

Since x is a function object, it doesn't do a deep copy of that. 由于x是函数对象,因此不会对其进行深层复制。

But since y is a plain object, it does try to do a deep copy and runs into the infinite loop. 但是由于y是一个普通对象,因此它确实尝试进行深层复制并遇到无限循环。

From the jQuery .extend() source: 从jQuery .extend()源:

// Recurse if we're merging plain objects or arrays
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 : {};
    }

    // Never move original objects, clone them
    target[ name ] = jQuery.extend( deep, clone, copy );

// Don't bring in undefined values
} else if ( copy !== undefined ) {
    target[ name ] = copy;
}

You can see that it is checking to see if the property is a plain object or an array. 您可以看到它正在检查该属性是纯对象还是数组。 A function object will not be either. 功能对象也不是。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM