存储对象/变量中的函数引用

Ben*_*rey 5 javascript jquery function object

我一直在寻找这个,但到目前为止还没有找到重复,我可能使用错误的关键字...

我试图暂时更改存储在对象中的函数,但是无法将其设置回原来的状态.

考虑一下:

// Set the options object
var options = {
    success: function(){
        console.log('Original Function Called');
    }
}

// Save the options
$('#foo').data('bar',options);
Run Code Online (Sandbox Code Playgroud)

然后在另一个功能:

// 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);
Run Code Online (Sandbox Code Playgroud)

我本来希望只显示Temporary Function Called一次,但它似乎完全用success临时回调替换旧的回调.

任何人都可以告诉我为什么以及如何解决这个问题?

UPDATE

我认为这样extend可以解决这个问题,但似乎问题可能会更深一些.我这次决定发布我的实际代码片段.阅读前请注意以下事项:

  1. SM几乎只是别名jQuery,请忽略它.
  2. 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);
Run Code Online (Sandbox Code Playgroud)

Mic*_*ary 9

当您运行此代码时:

var old_options = options;
Run Code Online (Sandbox Code Playgroud)

您没有制作可以在以后恢复的整个对象的副本options.您只是保存对同一对象引用.换句话说,是非常相同的对象,所以当你分配一个新值,你改变它在这两个 -因为它们是同一个对象.old_optionsoptionsoptions.successoptions old_options

要解决此问题,您可以使用对象克隆功能制作对象的副本,然后可以稍后恢复该对象.由于您使用的是jQuery,因此可以将上面的行更改为:

var old_options = $.extend( true, {}, options );
Run Code Online (Sandbox Code Playgroud)

现在,当你改变时options.success,你只是在options对象中改变它.old_options不受影响,因此您以后的通话将成功恢复:

$('#foo').data('bar',old_options);
Run Code Online (Sandbox Code Playgroud)

有趣的是,即使options.success是异步回调(这可能来自名称),这仍然可以正常工作.这是因为无论以后代码调用该.success()方法,它们仍应保持对修改后的options对象的引用- 即使您在此期间已将旧对象恢复为元素的数据.至少有一个人希望这样; 如果其他代码挖回$().data()找到了.success回调,那么你就会有麻烦.

$.extend()上面的调用执行对象的"深度"(递归)副本options.也就是说,如果其中一个属性options本身就是一个对象,它也会克隆该对象,而不是仅复制对它的引用.

如果省略true参数,$.extend()则执行浅复制:

var old_options = $.extend( {}, options );
Run Code Online (Sandbox Code Playgroud)

这仍然会创建一个新对象并复制现有对象的所有属性,但如果其中一个属性本身就是一个对象,则它不会克隆该对象,它只是复制一个引用.如果它与您正在使用的对象的结构一起使用,则效率更高,否则您可以使用深层复制.

如果需要保存和恢复的属性/方法是主对象的直接子项,则浅层副本就足够了.这是一个你肯定需要深层复制的情况:

{
    url: 'test',
    events: {
        success: function( data ) {
            // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我们有一个带有events属性的对象,该属性本身就是一个对象,它有自己的一些属性/方法(在这个例子中是一个events.success()方法.如果你做这个对象的浅拷贝,原始和副本将共享一个共同的events对象.所以如果你做了这样的事情:

options.events.success = function(...) {...};
Run Code Online (Sandbox Code Playgroud)

你会实际上是更新,在这两个optionsold_options.不好.这就是需要深层复制的地方.