QQ群招募中:646258285(招募中,没几个人说话),
需要交流的朋友可以直接加我微信( DntBeliv )或QQ( 1121864253 )
准确地说,JavaScript并没有类的概念,也因此我们没有办法像java那样设置private、public后再设置getter和setter,但我们可以使用JavaScript的原生的属性,通过对对象属性进行限制,从而实现getter和setter。这就用到了Object.defineProperty()函数。该函数有三个参数,依次是“属性所在的对象”、“属性的名字”和“一个描述符对象”。这里就不仔细介绍了,我们直接看使用方法。
var book = {
_year: 2004,
edition: 1
}
Object.defineProperty(book, "year", {
get: function () {
return this._year;
},
set: function (newValue) {
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
console.log("使用book._year访问:");
console.log(book._year + "." + book.edition);
book._year = 1900;
console.log(book._year + "." + book.edition);
console.log("使用book.year访问:");
book.year = 2005;
console.log(book.year + "." + book.edition);
console.log("end");
输出结果是:
我们可以看到,getter和setter生效了。但是需要注意的是,book对象的原属性并不是year,而是_year,一般来说,我们使用属性前加下划线表示只需要用函数读写(注意是表示,换句话说,我们从上面的例子里面也看到了,_year仍然是可以被读写的)。
可能有人会问,直接最开始就命名为year不就行了,为什么还要加下划线?那我们现在就来试试。
var book = {
year: 2004,
edition: 1
}
Object.defineProperty(book, "year", {
get: function () {
return this.year;
},
set: function (newValue) {
this.year = newValue;
}
});
book.year = 2005;
console.log(book.year + "." + book.edition);
console.log("end");
运行结果:
可以看到报错栈溢出了。为什么会这样呢?实际上是因为在setter内调用setter,出现了死循环。因为这个原因,我们最初才需要使用_year,而不是year。
那么如何让别人不能直接写入_year呢?实际上并没有什么十分好的办法。不过我们可以尝试这样,看下面的例子。
var book = {
_year: 2004,
edition: 1
}
Object.defineProperty(book, "_year", {
writable: false
});
Object.defineProperty(book, "year", {
get: function () {
return this._year;
},
set: function (newValue) {
Object.defineProperty(book, "_year", {
writable: true
});
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
Object.defineProperty(book, "_year", {
writable: false
});
}
});
console.log("使用book._year访问:");
console.log(book._year + "." + book.edition);
book._year = 1900;
console.log(book.year + "." + book.edition);
console.log("使用book.year访问:");
book.year = 2005;
console.log(book.year + "." + book.edition);
console.log("end");
看结果。
在这里我们使用了writable属性,如果不进行设置,writable默认为true,因此是可读写的。我们不想让别人修改这个变量,只需要把这个变量的writable设置为false就行了。但既然我们可以设置writable,那么别人也可以,这样的唯一好处只是避免手误罢了,因此还不如使用下划线规约方便。
我们也可以对代码进行缩减,同时设置多个属性。
function getBookObj() {
var book0 = {
_year: 2014,
edition: 10
};
//写成var book0 = {}不行,不知道为什么
Object.defineProperties(book0, {
"_year": {
value: 2004
},
"edition": {
value: 1
},
"year": {
"get": function () {
return this._year;
},
"set": function (newValue) {
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});
return book0;
}
book = getBookObj();
console.log("使用book._year访问:");
console.log(book._year + "." + book.edition);
book._year = 1900;
console.log(book._year + "." + book.edition);
console.log("使用book.year访问:");
book.year = 2005;
console.log(book.year + "." + book.edition);
console.log("end");
输出结果: