我想知道如何克隆完整的jQuery对象。我尝试使用_.clone()
,_.cloneDeep()
(下划线或lodash),但它不仅仅是一个对象,它还是一个功能。
目的是为我的客户提供jQuery,通过提供它的副本,而不是参考,因为我不希望他们弄乱我自己的jQuery(lib是沙箱)所以他们不必注入另一个脚本,只需调用我提供的一个函数来获取他们可以使用的jQuery。
答案 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代码。
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;
现在,我认为 proxy
100%像jQuery一样工作,但我无法保证。
在生产中使用之前,您应该进行详尽的测试。
但是&#34;实际&#34;克隆吗
我非常肯定第二次无法加载jQuery
导出的$
/ jQuery
函数可以访问许多闭包,其中没有任何&#34;局外人&#34; JS代码可以克隆,甚至访问
克隆jQuery&#34;的唯一方法将再次调用匿名函数,在该函数中定义/导出它,但该函数不可用
$.toString()
也没有任何用处,因为它引用了许多闭包,只会在eval
时出现大量异常。
您可以在变量中存储$
或jQuery
的引用,删除window.$
和window.jQuery
,只需将另一个<script>
标记附加到{{ 1}},document.head
设置为jQuery文件
你最终还得到了两个jQuery副本:
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;
甚至建议这样做有点伤害......但可以也可以用XHR + eval来完成,当然......不是说应该,虽然。
<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;
看起来Lodash 不能够做到这一点!
Lodash 2.4.2(可能更低)只会引用任何功能:
<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;
Lodash 3.0.0(以及更高,可能)最初似乎可行,但只有在你意识到功能不能保持功能之前:
<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;