get关键字特性
get关键字可在对象内部使用,可为此对象创造一个伪属性。先看下面一个例子:
let obj = {
get name(){
let a =10;
return a;
}
}
console.log(obj.name); //10
当我们去调用obj对象的name属性时,会执行此对象的name()方法,此方法返回一个数10.
在我们调用这个方法时,可以像访问对象的属性一样,不用加括号,就可以执行此方法,而这个方法会返回一个数,所以我们可以用get关键字为此对象创造一个伪属性。并且这个伪属性只可读,不可写,如下:
let obj = {
get name(){
let a = 10;
return a;
}
}
obj.name = 100;
console.log(obj.name); //10
如果我们想像这样给它赋值,将不会起作用,obj.name仍然是10.
注意: 当obj已经拥有了name属性时,而且对象内部再使用get关键字声明name方法时,此时再访问obj.name,则会调用这个name方法,而不会去访问真正的name属性,因为name这个属性已经被覆盖了,变成了一个方法,如下:
let obj = {
name:11,
get name(){
return 10;
}
}
console.log(obj.name);//10
知道了这个,就可以很好的理解下面这个容易碰到的问题:
let obj = {
name:11,
get name(){
return this.name;
}
}
console.log(obj.name);//Uncaught RangeError: Maximum call stack size exceeded
如果我们在这个name方法里,用到了this.name,此时this当然指的是obj对象,就相当于访问了obj.name,而此时访问到却的不是name属性,而是它自身(这个被重写的name),如此一来,这就成了一个自身调用自身的递归函数,并且没有出口,所以,造成了调用堆栈溢出,报了如上的错。 当然如果改成这样:
let obj = {
get name(){
return this.name+1;
},
name:11,
}
console.log(obj.name);//11
我们再访问obj.name时,就会访问到其真实的name属性,而那个name()方法,因为被重写将访问不到。
set关键字特性:
set关键字与get关键字的区别是,用set时,必须有且仅能有一个参数,而用get时,不能有参数。否则将会报错。并且,用set时,只能赋值,而不能取值(我的理解是用set+伪属性名声明的函数,其返回值无法获取,而用get时可以)。如下:
let obj = {
_name:10,
set name(a){
this._name = a;
return this._name;
}
}
obj.name = "傻强";
console.log(obj.name);//undefined
console.log(obj._name);//傻强
其余,set和get的特性基本一致,都可以完成对属性的操作。
用set和get关键字完成ES6类的自定义存取值
看例子:
class Animal {
constructor(name, age) {
this._name = name;
this._age = age;
}
say() {
console.log(`我叫 ${this._name},我今年${this.age}岁了!`);
}
walk() {
console.log(`我正在走路!`);
}
set name(value) {
this._name = value;
return this._name;
}
get name() {
return this._name
}
set age(value) {
if (value < 0 || value > 1000) {
console.log("年龄不合法");
return this._age = 0;
}
this._age = value;
return this._age;
}
get age() {
return this._age;
}
}
let dog = new Animal("狗","3");
console.log(dog.name,dog.age); //狗 3
dog.age = -1;
console.log(dog.age); //0
dog.name = "哈士奇";
console.log(dog.name); //哈士奇
通过get和set配合,对同一属性操作,就可以完成对实例对象赋值的权限的控制。由set,get关键字的特性可知,只有set,get同时用,才可以对同一属性进行存取。例如上例,如果对年龄赋予不合理的值时(小于0或者大于1000),其dog._age的值就会成为0,同理我们也可以让某个属性值不可变。
注意: 属性前加下划线_代表此属性尽量不要通过 obj._属性名 来存取,要通过 obj.属性名 来存取,这是为了保证程序的稳定和减少不必要的bug,虽然不是什么规定,但是却是我们应该知道的一种规范。