对于In与闭包和函数创建问题 [英] For In with closure and function creation issues

查看:81
本文介绍了对于In与闭包和函数创建问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试创建一个包装器函数,它接受一个对象(obj)的所有函数属性,并用另一个函数(p())包装它们。

I've been trying to create a wrapper function that takes all the function properties of an object (obj) and wraps them with another function ( p() ).

这段代码说明了我的意思。

This code illustrates what I mean.

//Setup code
function p(input){
    //do stuff
    return new_output;
}
obj = {
    prop1: function(){...},
    prop2: function(){...},
    prop3: function(){...}
 }

//Here's the wrapper function
r = new R(obj);

//Expected behaviour
r.prop1(a1,a2); //Just like saying p(obj.prop1(a1,a2))

这是我的尝试实现

function R (obj) {
    for (var member in obj) {
            //Mirrors obj's members
        this[member] = function (args) {
            var fn,inner_member = member;
                    //Convert to array for 'apply'
            args = Array.prototype.slice.call(args,0);

            fn = obj[member];

                    //Returns unexpected values, poo...
            console.log(inner_member);
            return p( fn.apply(fn,args) );
        }
    };

}

不幸的是,每当我运行r.prop1()时, console,通过console.log,返回错误的成员,prop3和obj [member]返回obj.prop3。一切都是错的。

Unfortunately, whenever I run r.prop1(), the console, via console.log, returns the wrong member, "prop3" and obj[member] returns "obj.prop3". Everything is wrong.

我认为这与闭包以及新创建的成员函数在其范围之外的看法有关。

I think this has to do with the closure and how the newly created member member functions are looking outside their scope.

如何解决这个问题?

编辑: David Flanagan的Javascript:The Definitive Guide非常直接地回答了这个问题在第8章第3节中。该部分是关于闭包的,最后一个例子反映了我上面写的内容。理解我的问题的关键是函数在定义的同一范围链中调用。函数是对象和相关的范围链。 AKA,一个闭包。

David Flanagan's Javascript: The Definitive Guide answers this question pretty much directly in Chapter 8, section 3. That section is on closures and the last example mirrors what I wrote above. The key to understanding my problem is that functions are invoked in the same scope chain as they're defined. A function is an object AND related scope chain. AKA, a closure.

推荐答案

函数引用的成员变量你在中为生成循环是相同的成员变量。

The member variable referenced by the functions you're generating in the for loop is the same member variable.

这是因为JavaScript 没有块范围,只有函数范围。这是一个常见问题。

This is because JavaScript does not have block scope, just function scope. It's a common issue.

一种解决方案是在循环中调用一个函数,传入成员,使其成为新变量范围的一部分。

One solution is to invoke a function in the loop, passing in member so that it becomes part of a new variable scope.

function R (obj) {

// --------v---- use var to declare variables in order to avoid implicit globals
    for (var member in obj) {      // ...thanks to @CMS for the reminder.
        createMember( member );
    }

    function createMember( mem ) {
            //Mirrors obj's members
        this[ mem ] = function (args) {
            var fn,inner_member = mem;
                    //Conver to array for 'apply'

   // Don't forget to use .call-----------v
            args = Array.prototype.slice.call(args,0);

            fn = obj[ mem ];

            console.log(inner_member);
            return p( fn.apply(fn,args) );
        };
    }
}

现在成员的价值循环中每次迭代中的作为参数传递给单独的函数调用,每次都会创建一个新的变量作用域。

Now the value of member in each iteration in the loop is pass as an argument into a separate function invocation, which creates a new variable scope each time.

因为每个新函数都是每个唯一变量范围的一部分,所以每个函数都引用一个不同的 mem 变量(或者参数)。

Because each new function is part of each unique variable scope, each one is referencing a different mem variable (or parameter).

同一概念还有其他变体:

There are other variations on the same concept:

function R (obj) {
    for (var member in obj) {
        this[ member ] = createMember( member );
    }

    function createMember( mem ) {
            //Mirrors obj's members
        return function (args) {
            var fn,inner_member = mem;
                    //Conver to array for 'apply'

   // Don't forget to use .call-----------v
            args = Array.prototype.slice.call(args,0);

            fn = obj[ mem ];

            console.log(inner_member);
            return p( fn.apply(fn,args) );
        };
    }
}

这是相同的,除了从调用返回一个函数,分配给这个[member] 。同样的原则。

This is the same, except that it returns a function from the invocation to be assigned to this[ member ]. Same principle though.

其他人更喜欢使用IIFE (立即调用函数表达式)而不是命名函数。

Other people prefer to use an IIFE (immediately invoked function expression) instead of a named function.

function R (obj) {
    for (var member in obj) {
        (function( mem ) {
                //Mirrors obj's members
            this[ mem ] =  function (args) {
                var fn,inner_member = mem;
                    //Conver to array for 'apply'

   // Don't forget to use .call----------------v
                args = Array.prototype.slice.call(args,0);

                fn = obj[ mem ];

                console.log(inner_member);
                return p( fn.apply(fn,args) );
            };
        })( member );
    }
}

...虽然我认为不太清楚,效率稍差。

...though I think it's less clear, and a little less efficient.

编辑:已添加 var 成员变量以避免隐式全局。感谢 @CMS

Added var to member variable to avoid implicit global. Thanks to @CMS.

编辑:已将 Array.prototype.slice(args,0)更改为 Array.prototype.slice.call(args,0)

编辑:

这与任何问题都没有关系,但如果你所做的就是在包装器调用原始函数时传递参数,你就可以摆脱它...

This isn't related to any issue, but if all you're doing is passing on the arguments when the wrapper invokes the original function, you can get rid of...

args = Array.prototype.slice.call(args,0);

并传递原始参数对象:

return p( fn.apply( fn,arguments ) );

无需将其转换为数组。

这篇关于对于In与闭包和函数创建问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆