JavaScript variable inside class is always undefin

2019-09-08 07:53发布

I have a JavaScript class like this:

Dog = (function() {
    var name;

    function setName(_name) {
        name = _name;
    }

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

When I run:

Dog.setName('Hero');

Dog.name is always undefined.

I am certainly missing something about JS scoping, but what?

6条回答
够拽才男人
2楼-- · 2019-09-08 08:20

You are returning an object where name property has a value of name at that point in time (which is undefined). The name property of the returned object is not somehow dynamically updated when the name variable inside the IIFE is updated.

There are many ways to handle what you appear to be wanting to do. Here's one:

Dog = (function() {
    var name;

    function setName(_name) {
        name = _name;
    }

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

})();

This keeps name as a private variable, which can only be set via setName, but provides a getter property for obtaining its value.

The alternative proposed in another answer is equivalent, just a different way of writing it:

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

Minor point, but in this particular context you don't need parentheses around your IIFE:

Dog = function() { }();

will work fine.

查看更多
我命由我不由天
3楼-- · 2019-09-08 08:20

Use the 'this' keyword.

Dog = (function() {
    var name;

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

    return {
        setName: setName,
        name: name
    };
})();
Dog.setName('Hero');
alert(Dog.name);
查看更多
地球回转人心会变
4楼-- · 2019-09-08 08:24

This happens because you assume that setting name in the object retains a reference to the original name variable. Instead, you want to assign it to the current object (which, you might as well ignore the private variable altogether).

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

However, if you want to keep name private then you create a getter for it instead.

var Dog = (function() {
  var name;

  return {
    setName: function(n) {
      name = n;
    },
    get name: function() {
      return name;
    }
  };
})();
查看更多
你好瞎i
5楼-- · 2019-09-08 08:32

Sounds like you want to make a constructor... Check this sample:

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);

you can try it here: http://jsfiddle.net/leojavier/ahs16jos/

I hope this helps man...

查看更多
老娘就宠你
6楼-- · 2019-09-08 08:35

The easy way to fix this is:

Dog = (function() {

var dog = {
    setName: setName,
    name: name
};

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

return dog;
}

In your code, you were setting the wrong name variable.

var name;

function setName(_name) {
    name = _name;
}

In this function, setName is setting the internal variable name and not the property name. In JavaScript, strings are immutable, so when you change it, it creates a new string, and doesn't update the existing one.

查看更多
走好不送
7楼-- · 2019-09-08 08:38

This might be a better pattern for you. You're using the very old ES3 style constructor.

(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"

You might want to look into ES6 classes too

class Dog {
  constructor(name) {
    this.name = name;
  }
}

let d = new Dog('Hero'); 
console.log(d.name); // "Hero"
查看更多
登录 后发表回答