【问题标题】:Privileged Methods - how to get values of properties that are passed to the function?特权方法 - 如何获取传递给函数的属性值?
【发布时间】:2014-01-22 16:23:11
【问题描述】:

(示例来自书中,但我似乎不明白)

    function User (properties){
       for( var i in properties){
           (function(){
               this["get"+i] = function () { return properties[i];};
               this["set"+i] = function (valueOne) { properties[i] = valueOne; }; 
           }) ();
        }// END for
    }// END User

var userOne = new User ({ name: "Billy", age: 35 });
userOne.getname(); 

当我运行它时,用户没有getname 方法。如何使特权方法有效?

【问题讨论】:

  • 也许他们稍后会解释这有什么问题以及需要改变什么。

标签: javascript privileged-functions


【解决方案1】:

您需要在闭包中同时捕获 thisi

function User (properties){
   for( var i in properties){
       (function(t, i){
           t["get"+i] = function () { return properties[i];};
           t["set"+i] = function (valueOne) { properties[i] = valueOne; }; 
       }) (this, i);
    }// END for
}// END User

【讨论】:

    【解决方案2】:

    this 不是你想的那样。由于您在任何情况下都调用了 IIFE,this 将是全局范围,因此窗口将获取方法 getname 等,这不是您所期望的。

    要修复它,如果你想保留 IIFE,你需要在正确的上下文中调用它:

    function User (properties){
           for( var i in properties){
               (function(key){
                   this["get"+key] = function () { return properties[key];};
                   this["set"+key] = function (valueOne) { properties[key] = valueOne; }; 
               }).call(this, i);
            }// END for
        }// END User
    
    var userOne = new User ({ name: "Billy", age: 35 });
    userOne.getname(); 
    

    请注意,您还忘记将 i 参数传递给函数并将其解释为参数。否则所有函数都将绑定到同一个键,因此userOne.getname 将返回 35。

    【讨论】:

      【解决方案3】:

      这是因为您使用了立即调用的函数

          for( var i in properties){
             (function(){  //<--- This
                 this["get"+i] = function () { return properties[i];};
                 this["set"+i] = function (valueOne) { properties[i] = valueOne; }; 
             }) ();
          }
      

      删除它,它仍然不起作用,但你的方法会在那里。为了让它充分发挥作用,你应该保留i

          for( var i in properties){
             (function(i){  //<--- This
                 this["get"+i] = function () { return properties[i];};
                 this["set"+i] = function (valueOne) { properties[i] = valueOne; }; 
             }) (i); //<--- and this
          }
      

      后一个问题不像第一个问题那么有趣(尽管与之相关)。

      Javascript 仅具有所谓的“函数范围”,这意味着唯一限制函数范围的是……嗯……一个函数。因此,一种常见的模式是在 for 循环内或在您不希望变量泄漏的许多地方使用这样的 IIFE。

      但是,javascript 中的this 参数很奇怪。了解以下内容,它将为您省去 的麻烦:this 在 javascript 中与任何其他参数没有什么不同

      让我解释一下。

      在 javascript 中有四种调用函数的方法。

      myFn.call("this param", "param 1", "param 2"); //this is "this param"
      myFn.apply("this param", ["param 1", "param 2"]); //this is "this param"
      myFn("param 1", "param 2"); 
      //javascript takes a guess at what `this` should be - 
      //usually it is set to the global `window`.
      new myFn("param 1", "param 2"); 
      //`this` is a new function with its' prototype set to myFn.prototype
      

      如果您总是使用.call 形式,所有歧义都将消失,您可以看到this 与其他所有参数完全相同。然而,这是额外的语法,人们更喜欢使用更简单的形式,这意味着您必须考虑“this”的规则。

      因此,您在示例中所做的是在全局 window 对象上放置 getter 和 setter。

      我要在这里声明,你的书可能不同意,但我从多年学习、使用和教授 javascript 中总结出来:

      不要使用 newthis 关键字。

      这两个关键字在 JS 中引入了大量的概念,这些概念令人困惑,而且真的 - 除非你在做一些非常性能敏感的东西(你不是,我知道你认为你是,但是你'不是) - 没有必要。而是像这样创建新对象:

      var user = { name: "Billy", age: 35 };
      

      如果您绝对必须拥有 getter 和 setter,这将做到:

      function createObjectWithProps (properties){
         var obj = {};
         var state = {}[
         for( var k in properties){
             (function(key) {
                 obj["get"+key] = function () { return state[key];};
                 obj["set"+key] = function (valueOne) { state[key] = valueOne; }; 
              })(k)
          }
          return obj;
      }
      
      var userOne = createObjectWithProps ({ name: "Billy", age: 35 });
      userOne.getname(); 
      

      尽管我会进一步说明 getter 和 setter 在 js 中并不是非常有用,当你使用它们时,遵循类似于 knockout 所做的模式是标准的。

      【讨论】:

      • 这不会将函数内部的i绑定到最后一个i吗?
      • @rid 它不会,因为在您调用它时i 是“当前”值,然后它会迭代。
      • 你可以测试看看结果。 setname 会存在,但会返回 35
      • 谢谢,乔治!我试图理解 JavaScript 中的特权方法,这本书建议使用 (function(){},)();并说它会更强大。我想我必须经常来这里学习 javaScript。作为 Web 开发人员,您能推荐任何好的 javaScript 资源吗?
      • 好点@rid,你是对的,问题是i 在这些函数中被使用,这就是为什么它在那个时候显示最后一个值。
      【解决方案4】:

      问题出在“this”关键字上。

      因为您在立即调用的函数中使用它,所以它指向全局范围。

      试试这个:

      function User (properties){
      
         for( var i in properties){
             (function(self,i){
                 self["get"+i] = function () { return properties[i];};
                 self["set"+i] = function (valueOne) { properties[i] = valueOne; }; 
             }) (this,i);
          }// END for
      }// END User
      

      【讨论】:

      • 应该注意,您也可以使用.call(this, i) 而不是(this, i) 并保留this["get"+.... 的东西。不过,我也更喜欢你写它的方式。
      猜你喜欢
      • 2014-03-22
      • 2015-01-23
      • 2013-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多