ES6类的属性自定义存取值——getter、setter访问器理解

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,虽然不是什么规定,但是却是我们应该知道的一种规范。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端小端长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值