【问题标题】:Javascript dynamically created functions in an objectJavascript 在对象中动态创建函数
【发布时间】:2014-10-10 06:19:34
【问题描述】:

我只是在学习 javascript,但遇到了与范围界定相关的问题。

这是代码

function User (properties) {
    for (var i in properties) {
        (function ()  {
            this ['get' + i] = function () {
                return properties [i];
            };
        }) ();
    }
}

var me = new User ({
    Id : 54,
    Name : 'ohyou'
});

console.log (me.getName ());
console.log (me.getId ());

我希望它如何工作:它应该创建两个函数 getNamegetId 属于 me 对象。

它是如何工作的:它创建了两个我想要的函数,但它们属于window

我尝试了什么:

  • 我尝试删除第 3 行的函数。它执行我想要的操作,但现在它返回 name "ohyou" 两次,而不是返回 idname

  • 我尝试使用 window 范围内的函数,但前一种情况的问题仍然存在 - 它两次返回 name

问题:我做错了什么以及如何让它按我的意愿工作?

附:使用电话发布此帖子,对于可能的拼写错误或格式问题,我们深表歉意。另外,请原谅我的英语水平。

【问题讨论】:

  • 这可能是某处重复的副本。最佳解决方案 IMO 是放弃循环,并使用Object.keys(properties).forEach
  • 可以处理this也可以处理thatstackoverflow.com/questions/4886632/…
  • 已将循环更改为您建议的功能,但显然它不起作用。

标签: javascript


【解决方案1】:

尝试了解以下代码为何有效:

function User(properties) {
    for (var i in properties) {
        with ({ i: i, self: this, props: properties }) {
            self["get" + i] = function () {
                return props[i];
            };
        }
    }
}

var me = new User({
    Id: 54,
    Name: "ohyou"
});

alert(me.getName());
alert(me.getId());

这是with 语句的合法用途之一的示例。

我发现with 语句比其他人建议的使用立即调用函数表达式 (IIFE) 更简洁。

编辑: with 关键字如果使用得当的话还不错。 with 有一些合法用途:

http://webreflection.blogspot.in/2009/12/with-worlds-most-misunderstood.html


您的代码不起作用的原因是每个函数都有自己的值this。因此,当您立即在for 循环中调用函数表达式时,函数内this 的值不再是您的新对象。它是window。要解决该问题,您可以执行以下操作:

(function (i, self, props) {
    self["get" + i] = function () {
        return props[i];
    };
}(i, this, properties))

但是,使用with 语句既干净又快速。它更快,因为您没有调用函数。

【讨论】:

  • 嘿 Aadit - 我个人喜欢这里使用 'with',但我读过的文档避开了它 - 尽管我相信你在这里的用法很好。
  • @jamesemanon with 声明还不错。请参阅以下问题:stackoverflow.com/q/1931186/783743
  • 非常感谢。即使只使用{i: i},它也能完美运行,但我不明白为什么。而且我也不明白为什么它在我的情况下不起作用。
  • @ohyou 我添加了关于为什么您的代码无法按预期工作的解释。
  • 哦,现在我明白为什么了。感谢您的详细回答。
【解决方案2】:
function User (properties) {
    var that = this;
    for (var i in properties) {
        (function (i)  {

            that ['get' + i] = function () {
                return properties [i];
            };

        }) (i);
    }
}

var me = new User ({
    Id : 54,
    Name : 'ohyou'
});

【讨论】:

    【解决方案3】:

    如果你使用Object.keys 然后forEach,你可以避免所有这些闭包和其他事情,这已经引入了一个新的范围。然后你必须传递this 值,这是第二个参数:

    function User(properties) {
      Object.keys(properties).forEach(function(k) {
        this['get'+ k] = function() {
          return properties[k]
        }
      },this)
    }
    

    【讨论】:

    • 虽然这非常慢。首先遍历所有属性以获取键名。然后再次循环它们,每次都运行回调函数。
    • 没什么好担心的,引擎速度很快。如果我想要可读的代码和更好的抽象,我会远离 for 循环。
    • 我想每个人都有自己的风格。我也喜欢编写函数式代码,但不喜欢用 JavaScript。无论如何,+1。
    【解决方案4】:

    你必须记住,任何不属于任何对象的函数,将永远属于窗口对象

    例如,如果我们修改你的对象并添加一个新方法,

    me.doSomeWork = function(){
       this.myLuckyNumber = 10;
       var that = this;
       function doubleMyLuckyNumber(){
          console.log(this); //window
          that.myLuckyNumber = that.myLuckyNumber * 2;     
       } 
    
      doubleMyLuckyNumber();  
    };
    
    me.doSomeWork();
    console.log(me.myLuckyNumber) //outputs 20
    

    所以总是保存对 var 的引用以在内部方法中使用它。您可以使用其他人建议的任何方式,但我更喜欢 James emanon 的方法。

    【讨论】:

    • 我知道了,谢谢提醒。我只是对没有将数据传递到的内部范围感到困惑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-24
    • 2021-07-30
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多