【问题标题】:JavaScript variable inside class is always undefined类内的 JavaScript 变量始终未定义
【发布时间】:2015-08-27 19:48:43
【问题描述】:

我有一个这样的 JavaScript 类:

Dog = (function() {
    var name;

    function setName(_name) {
        name = _name;
    }

    return {
        setName: setName,
        name: name
    };
})();

当我跑步时:

Dog.setName('Hero');

Dog.name 始终未定义。

我当然遗漏了一些关于 JS 作用域的东西,但是什么?

【问题讨论】:

  • Dog.setName 是如何定义的,更不用说函数了?如果不抛出TypeError,它是如何执行的?
  • 对,我更改了一些函数名称等,我忘记将其添加到返回块。更新了答案。谢谢。
  • 致downvoter:您能否解释一下这个问题有什么问题,以便我可以从错误中吸取教训?

标签: javascript javascript-objects


【解决方案1】:

您正在返回一个对象,其中name 属性在那个时间点(未定义)的值为name。当 IIFE 中的 name 变量更新时,返回对象的 name 属性不会以某种方式动态更新。

有很多方法可以处理您似乎想做的事情。这是一个:

Dog = (function() {
    var name;

    function setName(_name) {
        name = _name;
    }

    return Object.defineProperties({}, {
      setName: { value: setName },
      name:    { get: function() { return name; } }
    });

})();

这将name保持为私有变量,只能通过setName设置,但提供了一个getter属性来获取其值。

另一个答案中提出的替代方案是等效的,只是写法不同:

return {
  setName:  function(n) { name = n; },
  get name: function() { return name; }
};

次要问题,但在这种特殊情况下,您的 IIFE 不需要括号:

Dog = function() { }();

会正常工作。

【讨论】:

  • 没错。我也是,以为是这个问题。但是我对 JS 的了解还不足以解决这个问题。
  • 谢谢,这很好用。你能告诉我更多关于我的课吗?这是正确的方法吗?有没有更好的方法来实现带有闭包和私有变量的类?
【解决方案2】:

发生这种情况是因为您假设在对象中设置 name 会保留对原始 name 变量的引用。相反,您希望将其分配给当前对象(您不妨完全忽略私有变量)。

Dog = {
  name: '',
  setName: function(n) {
    this.name = n;
  }
};

但是,如果您想保持 name 私有,那么您可以为它创建一个 getter。

var Dog = (function() {
  var name;

  return {
    setName: function(n) {
      name = n;
    },
    get name: function() {
      return name;
    }
  };
})();

【讨论】:

    【解决方案3】:

    解决这个问题的简单方法是:

    Dog = (function() {
    
    var dog = {
        setName: setName,
        name: name
    };
    
    function setName(_name) {
        dog.name = _name;
    }
    
    return dog;
    }
    

    在您的代码中,您设置了错误的 name 变量。

    变量名;

    function setName(_name) {
        name = _name;
    }
    

    在这个函数中,setName 设置的是内部变量name,而不是属性name。在 JavaScript 中,字符串是不可变的,因此当您更改它时,它会创建一个新字符串,并且不会更新现有字符串。

    【讨论】:

    • 是的,吊装。但是,当我调试脚本时,我可以清楚地看到 setName 在运行后设置了正确的“名称”变量。我可以看到狗的“名字”设置正确。但我无法得到超出其范围。
    • 那不是提升,那是关闭。提升是指在函数内部声明的变量,并且它们都具有函数级别的范围。你的是一个函数内的函数,内层函数可以引用外层函数的变量。
    • 是的,您说内部函数可以引用外部函数的变量,但在您的回答中,您声明内部函数正在设置内部变量名称。那么内部函数如何引用外部函数的变量呢? (关于我的课)。我也认为你描述的问题是吊装。谢谢。
    【解决方案4】:

    这对你来说可能是一个更好的模式。您正在使用非常古老的 ES3 风格的构造函数。

    (function(exports) {
    
      function Dog(name) {
        this.name = name;
      }
    
      Dog.prototype.speak = function() {
        return "woof";
      };
    
      // other functions ...
    
      exports.Dog = Dog;
    })(window);
    
    var d = new Dog('Hero');
    console.log(d.name); // "Hero"
    

    你可能也想看看 ES6 类

    class Dog {
      constructor(name) {
        this.name = name;
      }
    }
    
    let d = new Dog('Hero'); 
    console.log(d.name); // "Hero"
    

    【讨论】:

    • 有没有办法使用Singleton?所以我在整个应用程序中都有一个 Dog 对象,而无需创建“新”。
    • 这应该是你最初的问题。您可以找到无数关于如何使用 JavaScript 实现单例的示例。
    • 当然,但是从他写的setName函数来看,他似乎对保持name不公开感兴趣。
    【解决方案5】:

    听起来你想创建一个构造函数...检查这个示例:

    function Dog(prop) {
            this.name = prop.name;
            this.color = prop.color;
        }
        var myDog = new Dog({
            name:'Sam',
            color: 'brown'
        });
        alert()
        console.log('my dog\'s name is: '+myDog.name);
        console.log('my dog\'s color is: '+myDog.color);
    

    你可以在这里试试:http://jsfiddle.net/leojavier/ahs16jos/

    我希望这对人有所帮助......

    【讨论】:

      【解决方案6】:

      使用“this”关键字。

      Dog = (function() {
          var name;
      
          function setName(_name) {
              this.name = _name;
          }
      
          return {
              setName: setName,
              name: name
          };
      })();
      Dog.setName('Hero');
      alert(Dog.name);
      

      【讨论】:

      • 抱歉,没用。不能设置this.name,会报错。
      • 在每个经过测试的浏览器中都为我工作。更新了完整示例的答案。
      猜你喜欢
      • 1970-01-01
      • 2021-01-26
      • 2013-06-05
      • 2018-06-23
      • 1970-01-01
      • 1970-01-01
      • 2018-01-24
      • 2012-02-27
      • 2021-10-07
      相关资源
      最近更新 更多