理解闭包和作用域

3
由于我不太理解闭包,所以函数inResult总是返回false,导致循环没有执行。当然,我确信result包含了正确的属性。
    function hasId() {return $(this).prop('id');}
    function inResult(res) { return res.hasOwnProperty($(this).prop('id'));}

    $.ajax({
        url : opt.url,
        data : $.extend(true, opt.data, {ids: ids}),
        context : this, // A collection of elements
        type : 'POST',
        dataType : 'json',
        success : function(result) {

            // Filter elements with id and with a property in result named "id"
            this.filter(hasId).filter(inResult(result)).each(function() {
                console.log($(this).prop('id'));
            });

        }
    });

编辑:工作代码解决方案(感谢Šime Vidas指导我正确的方向):

// Use closures to change the context later
var hasId    = function() { return $(this).prop('id'); };
var inResult = function(res) { return res.hasOwnProperty($(this).prop('id')); };

$.ajax({
    url : opt.url,
    data : $.extend(true, opt.data, {ids: ids}),
    context : this, // A collection of elements
    type : 'POST',
    dataType : 'json',
    success : function(result) {

        // Filter elements with id and with a property in result named "id"
        var filtered = this.filter(function() {
            // Note the context switch and result parameter passing
            return hasId.call(this) && isBinded.call(this, result);
        });

        filtered.each(function() { console.log($(this).prop('id')); });

    }
});

2
this.id 工作正常。不需要使用 prop() - Šime Vidas
1
闭包不是仅限于jQuery,它们是JavaScript的一个特性。 - zizozu
@zizozu,你说得对,感谢编辑。 - gremo
1个回答

2

试试这个:

this.filter( hasId ).filter( function () {
    return inResult( result );
}).each( function () {
    console.log( this.id );
});

在您的代码中,您使用了.filter(inResult(result)),这样是无法工作的,因为您立即调用了inResult并将该调用(布尔值)的result传递给filter(),而filter()不适用于布尔值。
您也可以这样做:
var keys = Object.keys( result );

var filtered = this.filter( function () {
    return this.id && keys.indexOf( this.id ) > -1;
});

Object.keys( result ) 返回一个数组,其中包含 result 对象的所有自有属性名。


1
@Gremo 但是你没有将函数传递给 filter()。你向它传递了一个布尔值。filter( true ) 是不起作用的。你必须向它传递一个函数。 - Šime Vidas
@Gremo,有bind函数方法,所以.filter( inResult.bind( this, result ) )也应该可以工作。 (但是,在IE8和Safari中未实现bind,因此您必须将ES5-shim包含到您的网页中。) - Šime Vidas
然而,在inResult内部,关键字this仍将引用窗口对象... - gremo
@Gremo 是的,我不确定如何修复它。使用 bind 我们必须显式地设置函数的 this 值。 - Šime Vidas
使用类似 var inResult = function(res) { ... } 的“真正”闭包,可以在 filter 函数内部使用 inResult.call(this) 更改上下文。然而,当函数不是闭包时,我不知道如何更改上下文。 - gremo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接