为JS对象分配setter / getter

4
我尝试为我的JavaScript“类”分配一个setter:
function testing(){
    this.value = "content";
    set a(b){
        this.value = b;
    };
}
var test1 = new testing();
test1.a = "nope";

但是它在set a(b){这一行抛出了SyntaxError: missing ; before statement错误,请问正确的语法是什么?


1
尝试使用 Object.defineProperty - Daniel A. White
2个回答

14

有几种方法可以实现这个目标。

构造函数和Object.defineProperty

如果你想在构造函数中实现这个目标,你可以使用Object.defineProperty或者Object.defineProperties。例如:

function Testing(){
    this.value = "content";
    Object.defineProperty(this, "a", {
        set: function(b){
            this.value = b;
        }
    });
}

现场示例:

function Testing() {
  this.value = "content";
  Object.defineProperty(this, "a", {
    set: function(b) {
      this.value = b;
    }
  });
}
var t = new Testing();
snippet.log("t.value before: " + t.value);
t.a = "new content";
snippet.log("t.value after: " + t.value);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

(注意:我将Testing中的第一个t大写,因为这是JavaScript构造函数的普遍惯例。)

构造函数属性和使用原型链的Object.defineProperty

或者您可以在原型上定义setter:

function Testing(){
    this.value = "content";
}
Object.defineProperty(Testing.prototype, "a", {
    set: function(b){
        this.value = b;
    }
});

实时示例:

function Testing(){
    this.value = "content";
}
Object.defineProperty(Testing.prototype, "a", {
    set: function(b){
        this.value = b;
    }
});
var t1 = new Testing();
snippet.log("t1.value before: " + t1.value);
t1.a = "new content";
snippet.log("t1.value after: " + t1.value);
var t2 = new Testing();
snippet.log("t2.value before: " + t2.value);
t2.a = "new content";
snippet.log("t2.value after: " + t2.value);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

构造函数和原型对象的对象初始化器

您尝试使用的语法适用于对象初始化器,而不是构造函数。我们可以使用对象初始化器来替换Testing.prototype,如下所示:

function Testing(){
    this.value = "content";
}
Testing.prototype = {
    constructor: Testing, // The old object had this, so let's maintain it
    set a(b){
        this.value = b;
    }
};

实时示例:

function Testing(){
    this.value = "content";
}
Testing.prototype = {
    constructor: Testing, // The old object had this, so let's maintain it
    set a(b){
        this.value = b;
    }
};
var t1 = new Testing();
snippet.log("t1.value before: " + t1.value);
t1.a = "new content";
snippet.log("t1.value after: " + t1.value);
var t2 = new Testing();
snippet.log("t2.value before: " + t2.value);
t2.a = "new content";
snippet.log("t2.value after: " + t2.value);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

一个一次性对象的对象初始化器

这只是创建一个一次性对象,而不是一个可以用来构建多个这些对象的函数:

var t = {
  value: "content",
  set a(b) {
    this.value = b;
  }
};

实时示例:

var t = {
  value: "content",
  set a(b) {
    this.value = b;
  }
};
snippet.log("t.value before: " + t.value);
t.a = "new content";
snippet.log("t.value after: " + t.value);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

用于原型的构建函数和Object.create

构造函数(使用 new 的函数)不是创建带有原型的对象的唯一方法。如果你愿意,你也可以使用构建函数通过 Object.create 创建这样的对象:

var testingPrototype = {
    set a(b){
        this.value = b;
    }
};
function testing(){
    var obj = Object.create(testingPrototype);
    obj.value = "content";
    return obj;
}

这些对象自己创建,因此不需要使用new

示例代码

var testingPrototype = {
    set a(b){
        this.value = b;
    }
};
function testing(){
    var obj = Object.create(testingPrototype);
    obj.value = "content";
    return obj;
}
var t1 = testing();
snippet.log("t1.value before: " + t1.value);
t1.a = "new content";
snippet.log("t1.value after: " + t1.value);
var t2 = testing();
snippet.log("t2.value before: " + t2.value);
t2.a = "new content";
snippet.log("t2.value after: " + t2.value);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

一个构造函数,没有原型

最后,您可以使用一个构造函数而不使用原型:

function testing() {
    return {
        value: "content",
        set a(b){
            this.value = b;
        }
    };
}

这些也不需要使用new

实例

function testing(){
    return {
        value: "content",
        set a(b){
            this.value = b;
        }
    };
}
var t1 = testing();
snippet.log("t1.value before: " + t1.value);
t1.a = "new content";
snippet.log("t1.value after: " + t1.value);
var t2 = testing();
snippet.log("t2.value before: " + t2.value);
t2.a = "new content";
snippet.log("t2.value after: " + t2.value);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>


感谢您和@garryp的回复!它们都有效,但哪一种方法更好呢? - Feirell
@Feirell:两种方法都可以有效使用JavaScript,没有更好的一种。需要注意的是,像garryp所展示的那样的builder函数不使用new关键字(他似乎不愿意更正他的回答,我已经放弃了)。 garryp回答中的一点微小的缺点是您无法为对象分配一个原型(即作为基础并具有公共功能的对象),这通常非常方便。您可以使用构造函数或Object.create来实现这一点,但不能使用他展示的模式。 - T.J. Crowder
@Feirell:没错,使用 garryp 的模式的正确方法只是 var test1 = testing();(不需要 new)。我的最后一个例子是用于创建一次性对象。如果您想创建一堆这些对象(例如它们的“类”),那么您将需要使用我前三个示例中的任何一个(如果您想要使用构造函数和 new),或者我马上要添加的第五个新示例。 :-) - T.J. Crowder
1
你很棒,我非常感谢你的努力。如果我没记错的话,你曾经帮过我解决一些其他的问题,每次都让自己很麻烦,我认为这不是一件正常的事情,所以我想说声谢谢!小问题:为什么在.defineProperty前要使用Object?如果我像你在第一个例子中使用的那种符号表示法,会有问题吗?这样做是不好或不常见的风格吗? - Feirell
@Feirell:很高兴能帮忙。我在上面添加了第五和第六个选项;第六个是gerryp向您展示的,但我觉得我应该完整一些。JavaScript给你很多选择。 :-) 祝你愉快! - T.J. Crowder
显示剩余2条评论

1
在像这样的示例中,集合需要是对象的一部分:
一种实现方式是这样的:
function testing(){
    var value = "content";
    return {
        set a(b){
            value = b;
        },
        get a() {
            return value;
        }
    };
}
var test1 = new testing();
test1.a = "nope";

http://jsfiddle.net/GarryPas/1s7v0rdn/


在非构造函数功能中使用new是没有意义的。 - T.J. Crowder
new 是来自于原始问题的。 - garryp
是的,但是原帖中的函数是一个构造函数,而你的函数不是。 - T.J. Crowder
是的,但OP最初的问题是关于getter和setter的;-) - garryp
@garryp 我非常感谢任何帮助,虽然这有点超出范围,但我很感激 :) - Feirell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接