类中的JavaScript变量始终未定义

类中的JavaScript变量始终未定义,javascript,javascript-objects,Javascript,Javascript Objects,我有这样一个JavaScript类: Dog = (function() { var name; function setName(_name) { name = _name; } return { setName: setName, name: name }; })(); 当我跑步时: Dog.setName('Hero'); Dog.name始终未定义 我当然遗漏了一些关于JS作用域的内容,但是什

我有这样一个JavaScript类:

Dog = (function() {
    var name;

    function setName(_name) {
        name = _name;
    }

    return {
        setName: setName,
        name: name
    };
})();
当我跑步时:

Dog.setName('Hero');
Dog.name
始终未定义


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

这可能是一种更好的模式。您正在使用非常旧的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"

您正在返回一个对象,其中
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; }
};
次要的一点,但在这种特殊情况下,你的生活不需要括号:

Dog = function() { }();

会很好的

使用“this”关键字

Dog = (function() {
    var name;

    function setName(_name) {
        this.name = _name;
    }

    return {
        setName: setName,
        name: name
    };
})();
Dog.setName('Hero');
alert(Dog.name);

这是因为您假定对象中的设置
name
保留了对原始
name
变量的引用。相反,您希望将其分配给当前对象(您也可以完全忽略私有变量)

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

var Dog = (function() {
  var name;

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

解决此问题的简单方法是:

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中,字符串是不可变的,因此当您更改它时,它会创建一个新的字符串,而不会更新现有的字符串。

听起来像是要创建一个构造函数。。。检查此示例:

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);
您可以在这里尝试:


我希望这有助于人类……

如何定义
Dog.setName
更不用说函数了?如果不抛出
类型错误
,该如何执行?对,我更改了一些函数名,等等,但忘了将其添加到返回块中。更新了答案。谢谢。对downvoter:你能解释一下这个问题的错误吗?这样我就可以从错误中吸取教训了?有没有办法使用Singleton?所以我在整个应用程序中都有一个Dog对象,没有创建“new”。这应该是你最初的问题。你可以找到无数关于如何使用JavaScript实现单例的例子。当然,但从他编写的
setName
函数来看,他似乎对保持
name
私有感兴趣。我也认为这就是问题所在。但是我对JS的了解还不足以解决这个问题。谢谢,这非常有效。你能多告诉我一点我的课吗?走这条路对吗?有没有更好的方法用闭包和私有变量实现类?是的,有。然而,当我调试脚本时,我可以清楚地看到setName在运行后设置了正确的“name”变量。我可以看出狗的“名字”设置正确。但我不能让它超出它的范围。那不是提升,那是关闭。提升是指在函数中声明的变量,它们都在函数级别具有作用域。你的函数是函数内部的函数,内部函数可以引用外部函数的变量。是的,你说内部函数可以引用外部函数的变量,但在回答中你说内部函数正在设置内部变量名。那么内部函数如何引用外部函数的变量呢?(关于我的班级)。我还认为你所描述的问题是起重问题。谢谢。对不起,不行。它无法设置此。名称,抛出一个错误。在测试的每个浏览器中对我都有效。更新了完整示例的答案。
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);