当前位置: 代码迷 >> JavaScript >> 如何克隆jQuery库(按值复制) 先前的答案: 旧版/ Lodash:
  详细解决方案

如何克隆jQuery库(按值复制) 先前的答案: 旧版/ Lodash:

热度:45   发布时间:2023-06-05 10:31:30.0

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

目的是通过给我使用库的客户提供jQuery的副本,而不是提供引用,因为我不想让他们弄乱我自己的jQuery(库是沙盒的),因此他们不必注入另一个脚本,但只调用我提供的一个功能即可获得可以使用的jQuery。

既然您提到您的代码本身就是一个插件,并且您不想“弄乱” <head> ,那么我假设您也绝不能在任何时候修改原始的$ / jQuery ,而是加载jQuery实例直接转换为新变量

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

首先,使用XHR获取jQuery代码。
接下来,通过遍历window所有属性并为函数添加包装器以及为属性添加getter / setter来构造proxy变量。
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(); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> 

现在,我认为 proxy可以像jQuery期望的那样100%工作,但是我不能保证
在生产中使用此产品之前,应进行详尽的测试。

但是“实际”克隆呢?

我非常确定没有办法再次加载jQuery。
导出的$ / jQuery函数可以访问许多闭包,而任何“局外人” JS代码都无法克隆甚至访问。
“克隆jQuery”的唯一方法是再次调用匿名函数,该函数在其中定义/导出,但该函数不可用。
$.toString()也没有返回任何用处,因为它涉及许多闭包,并且在eval时只会抛出大量异常。


先前的答案:

您可以将$jQuery的引用存储在变量中,删除window.$window.jQuery ,然后将另一个<script>标记附加到document.head ,并将src设置为jQuery文件。
您最终还将获得jQuery的两个副本:

 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); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> 

甚至提出这个建议都有点痛...但是,当然可以使用XHR + eval来完成...虽然不说应该这样做。

 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(); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> 


旧版/ Lodash:

看起来Lodash 无法做到这一点!

Lodash 2.4.2(可能是更低版本)将仅引用任何函数:

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

Lodash 3.0.0(以及更高版本,可能是可假定的)乍一看似乎可行,但是直到您意识到函数不会保留函数为止:

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

  相关解决方案