如何克隆jQuery库(按值复制)

时间:2015-07-30 12:58:33

标签: javascript jquery

我想知道如何克隆完整的jQuery对象。我尝试使用_.clone()_.cloneDeep()(下划线或lodash),但它不仅仅是一个对象,它还是一个功能。

目的是为我的客户提供jQuery,通过提供它的副本,而不是参考,因为我不希望他们弄乱我自己的jQuery(lib是沙箱)所以他们不必注入另一个脚本,只需调用我提供的一个函数来获取他们可以使用的jQuery。

1 个答案:

答案 0 :(得分:1)

由于您提到您的代码本身就是一个插件,而您并不想要&#34;搞砸&#34; <head>,我假设您也不能随时修改原始$ / jQuery,而是将您的jQuery实例直接加载到新变量中。

我想我完全做到了。
以下代码的工作原理如下:

首先,使用XHR获取jQuery代码 接下来,通过迭代proxy的所有属性并添加函数的包装器和属性的getter / setter来构造window变量。
try / catch是静默跳过可能导致错误的属性所必需的,例如:

Uncaught SecurityError: Failed to read the 'caches' property from 'Window': Cache storage is disabled because the context is sandboxed and lacks the 'allow-same-origin' flag.

另请注意,明确排除了$jQuery

为了让jQuery不覆盖window.$window.jQuery,我们需要更改为window点,因为jQuery明确设置了window.$window.jQuery
但我们无法更改window,因为它是只读的 但是,我们可以做的是命名函数参数window

~function(window)
{
    /* in here, window == proxy */
}(proxy);

最后,使用proxy作为参数调用匿名函数,该函数在该函数内转向window,最终评估jQuery代码。

&#13;
&#13;
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js');
xhr.addEventListener('load', function(e)
{
    var proxy = {};
    for(var key in window)
    {
        if(key !== '$' && key !== 'jQuery')
        {
            ~function(k)
            {
                try
                {
                    if(typeof window[k] === 'function')
                    {
                        proxy[k] = function()
                        {
                            window[k].apply(window, arguments);
                        };
                    }
                    else
                    {
                        Object.defineProperty(proxy, k,
                        {
                            get: function()
                            {
                                return window[k];
                            },
                            set: function(val)
                            {
                                window[k] = val;
                            }
                        });
                    }
                }
                catch(error){}
            }(key);
        }
    }
    ~function(window)
    {
        eval(e.target.responseText);
    }(proxy);
    $.test = 'meow';
    document.write($.test + '<br>');
    document.write(proxy.$.test + '<br>');
    document.write(JSON.stringify(Object.keys($('body'))) + '<br>');
    document.write(JSON.stringify(Object.keys(proxy.$('body'))) + '<br>');
});
xhr.send();
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
&#13;
&#13;
&#13;

现在,我认为 proxy 100%像jQuery一样工作,但我无法保证。 在生产中使用之前,您应该进行详尽的测试。

但是&#34;实际&#34;克隆吗

我非常肯定第二次无法加载jQuery 导出的$ / jQuery函数可以访问许多闭包,其中没有任何&#34;局外人&#34; JS代码可以克隆,甚至访问 克隆jQuery&#34;的唯一方法将再次调用匿名函数,在该函数中定义/导出它,但该函数不可用 $.toString()也没有任何用处,因为它引用了许多闭包,只会在eval时出现大量异常。

上一个答案:

您可以在变量中存储$jQuery的引用,删除window.$window.jQuery,只需将另一个<script>标记附加到{{ 1}},document.head设置为jQuery文件 你最终还得到了两个jQuery副本:

&#13;
&#13;
src
&#13;
var myQuery = jQuery;
delete window.jQuery;
delete window.$;
var script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js';
script.addEventListener('load', function()
{
    jQuery.test = 'meow';
    document.write($.test + '<br>');
    document.write(myQuery.test + '<br>');
    document.write(JSON.stringify(Object.keys($('body'))) + '<br>');
    document.write(JSON.stringify(Object.keys(myQuery('body'))) + '<br>');
});
document.head.appendChild(script);
&#13;
&#13;
&#13;

甚至建议这样做有点伤害......但可以也可以用XHR + eval来完成,当然......不是说应该,虽然。

&#13;
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
&#13;
var myQuery = jQuery;
delete window.jQuery;
delete window.$;
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js');
xhr.addEventListener('load', function(e)
{
    eval(e.target.responseText);
    jQuery.test = 'meow';
    document.write($.test + '<br>');
    document.write(myQuery.test + '<br>');
    document.write(JSON.stringify(Object.keys($('body'))) + '<br>');
    document.write(JSON.stringify(Object.keys(myQuery('body'))) + '<br>');
});
xhr.send();
&#13;
&#13;
&#13;

旧/ Lodash:

看起来Lodash 能够做到这一点!

Lodash 2.4.2(可能更低)只会引用任何功能:

&#13;
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
&#13;
var a = function(){};
document.write('a.a before setting b.a: ' + a.a + ' (expected: undefined)<br>');
var b = _.cloneDeep(a);
b.a = 'a';
document.write('a.a after setting b.a: ' + a.a + ' (expected: undefined)<br>');
document.write('type of a: ' + (typeof a) + ' (expected: function)<br>');
document.write('type of b: ' + (typeof b) + ' (expected: function)<br>');
&#13;
&#13;
&#13;

Lodash 3.0.0(以及更高,可能)最初似乎可行,但只有在你意识到功能不能保持功能之前:

&#13;
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.2/lodash.min.js"></script>
&#13;
var a = function(){};
document.write('a.a before setting b.a: ' + a.a + ' (expected: undefined)<br>');
var b = _.cloneDeep(a);
b.a = 'a';
document.write('a.a after setting b.a: ' + a.a + ' (expected: undefined)<br>');
document.write('type of a: ' + (typeof a) + ' (expected: function)<br>');
document.write('type of b: ' + (typeof b) + ' (expected: function)<br>');
&#13;
&#13;
&#13;