Javascript 在对象/变量中存储对函数的引用
我已经搜索过了,但到目前为止还没有找到一个重复的,我可能是使用了错误的关键字 我试图临时更改存储在对象中的函数,但无法将其设置回以前的状态 考虑这一点:Javascript 在对象/变量中存储对函数的引用,javascript,jquery,function,object,Javascript,Jquery,Function,Object,我已经搜索过了,但到目前为止还没有找到一个重复的,我可能是使用了错误的关键字 我试图临时更改存储在对象中的函数,但无法将其设置回以前的状态 考虑这一点: // Set the options object var options = { success: function(){ console.log('Original Function Called'); } } // Save the options $('#foo').data('bar',options
// Set the options object
var options = {
success: function(){
console.log('Original Function Called');
}
}
// Save the options
$('#foo').data('bar',options);
然后在另一个函数中:
// Get the options
var options = $('#foo').data('bar');
// Store the old options
var old_options = options;
// Temporarily change the success function
options.success = function(){
console.log('Temporary Function Called');
}
// Save the options
// This allows the other functions to access the temporary function
$('#foo').data('bar',options);
// Do stuff here that uses the new options
// Reset the options to include the original success function
$('#foo').data('bar',old_options);
我本来希望只显示一次调用的临时函数
,但是,它似乎将旧的success
回调完全替换为临时回调
有人能告诉我为什么,我怎样才能避开这个问题吗
更新
我原以为extend
可以解决这个问题,但问题似乎更深了一点。我决定这次发布一段我的实际代码。阅读前请注意以下事项:
SM
几乎只是jQuery
的别名,请忽略它success
和error
是提供给函数的参数// Get the properties
var properties = $(form).data('autosave');
switch(parameter){
case 'save':
var old_properties = $.extend({},properties);
// Set the new callbacks if they have been supplied
properties.options.success = typeof success!=='undefined' ? success : old_properties.options.success;
properties.options.error = typeof error!=='undefined' ? error : old_properties.options.error;
// Save the properties
$(form).data('autosave',properties);
// Call the save method before setting the interval
SM(form)._as_save();
properties = $.extend({},old_properties);
// Save the old properties
$(form).data('autosave',properties);
// Clear the current interval
clearInterval(properties.interval);
// Call the save method periodically
properties.interval = setInterval(function(){
SM(form)._as_save();
},properties.options.interval);
break;
}
// Save the properties
$(form).data('autosave',properties);
运行此代码时:
var old_options = options;
您没有制作整个选项
对象的副本,以后可以恢复该对象。您只是保存对同一对象的引用。换句话说,old_options
与options
是同一个对象,因此当您将新值赋给options.success
时,您将在options
和old_options
中更改它,因为它们是同一个对象
要解决此问题,可以使用对象克隆功能制作对象的副本,然后在以后还原。由于您使用的是jQuery,因此可以将上面的行更改为:
var old_options = $.extend( true, {}, options );
现在,当您更改options.success
时,您只在options
对象中更改它<代码>旧选项不受影响,因此您稍后的通话将成功恢复:
$('#foo').data('bar',old_options);
有趣的是,即使options.success
是一个异步回调(听起来很像是名字),这仍然可以正常工作。这是因为无论代码稍后如何调用该.success()
方法,它们都应该保留对修改后的选项
对象的引用,即使您同时已将旧对象恢复到元素的数据中。至少有人可以这样希望;如果另一个代码挖掘回$().data()
以找到.success
回调,那么您将遇到麻烦
上面的$.extend()
调用执行选项
对象的“深层”(递归)副本。也就是说,如果options
中的一个属性本身就是一个对象,它也会克隆该对象,而不仅仅是复制对该对象的引用
如果省略true
参数,$.extend()
将执行浅层复制:
var old_options = $.extend( {}, options );
这仍然会创建一个新对象,并从现有对象复制所有属性,但如果其中一个属性本身是对象,则它不会克隆该对象,而是复制一个引用。如果它与您正在使用的对象的结构配合使用,则效率更高,否则您可以使用深度副本
如果需要保存和恢复的属性/方法是主对象的直接子对象,则浅拷贝就足够了。在这种情况下,您肯定需要深度拷贝:
{
url: 'test',
events: {
success: function( data ) {
// ...
}
}
}
在这里,我们有一个具有events
属性的对象,该属性本身就是一个具有自己的一些属性/方法的对象(在本例中为events.success()
方法。如果对该对象进行浅层复制,则原始对象和副本将共享一个公共的事件
对象。因此,如果执行类似操作:
options.events.success = function(...) {...};
实际上,您需要在
选项和旧选项中更新它。这不好。这就是需要深度副本的地方。您的问题是您正在处理对象。您正在传递对对象的引用。基础对象是相同的,您所做的只是添加一个指向相同地址的变量
你必须克隆这个对象。例如,创建一个具有相同属性的新对象,并将它们复制过来
这可能对您有用。问题在于选项
具有引用语义:
// Store the old options
var old_options = options;
此注释是错误的。您没有旧选项的副本;相反,您有对同一选项对象的另一个引用(您可以引用它的另一个名称)
因此,当您覆盖选项.success
时,此更改在旧的\u选项上也可见。使用.data
存储和还原选项值的代码是多余的
您需要做的唯一一件事是:
var old_success = options.success;
options.success = function() { /* whatever */ };
// code that uses the new success callback
options.success = old_success; // restore original value
当你这样做的时候,var old_options=options
你不是在复制options
值,而是在它上面复制一个引用。从现在开始,old_options
和options
指向同一个内存点,它们中任何一个的更改都会影响到这两个。你是说,$('foo')。数据('bar',old_options)
您仍然看到名为
的临时函数?下面有一些很好的答案。我有点困惑-这个新的更新,是在我们讨论了浅拷贝和深拷贝之后的吗?我看到您的成功
方法实际上是一个选项。成功()
方法(对于错误
也是如此).这正是需要深度复制的情况。那么,东西还是坏了,还是深度复制起了作用?@MichaelGeary不,这是以前的:-)深度修复了它!你让我担心。现在,查看更新中的代码是有意义的:浅层副本可以与原始问题中的代码一起使用,其中success
回调是主选项对象的一级属性。但是更新中的实际代码有点不同:它有一个properties.options.success
函数