Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/474.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在对象/变量中存储对函数的引用_Javascript_Jquery_Function_Object - Fatal编程技术网

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
    函数