14

1. 背景

在es6中,我们可以用class关键字来定义类,语法如下

class Person {
    // 构造函数
    constructor (name) {
        // 属性初始化
        this.name = name;
    }

    // 成员方法
    sayName () {
        console.log(this.name);
    }
    
    // 静态方法
    static sayHi () {
        console.log("Hi~");
    }
}

其实本质还是基于javascript原型链机制开发的语法糖,其中,本人对setter/getter进行一番研究,发现了不少坑。

2. 深入setter/getter

2.1 setter/getter的调用执行时机

class Person {
    constructor (name, age) {
        this.name = name;
        this.age = age;
    }
    set name (name) {
        console.log("setter");
        this.name = name;
    }
    get name () {
        console.log("getter");
        return this.name;
    }
}

var p = new Person("zhang", 25);

很快,我们就会发现代码报错了

setter-getter.png

这是因为,在构造函数中执行this.name=name的时候,就会去调用set name,在set name方法中,我们又执行this.name = name,进行无限递归,最后导致栈溢出(RangeError)。

我们稍作修改,让这个代码可以正常执行,达到我们想要的效果。

class Person {
    constructor (name, age) {
        this.name = name;
        this.age = age;
    }
    set name (name) {
        console.log("setter");
        this._name = name;
    }
    get name () {
        console.log("getter");
        return this._name;
    }

    // 加一个成员方法
    sayName () {
        console.log(this.name);
    }
}

var p = new Person("zhang", 25); 
p.sayName();

执行结果为

图片描述

到这里就可以明白了,原来只要this.name中的属性名和set name/get name后面的name一致,对this.name就会调用setter/getter,也就是说setter/getter是hook函数,而真实的存储变量是_name,我们可以在代码中直接获取它。

class Person {
    constructor (name, age) {
        this.name = name;
        this.age = age;
    }
    set name (name) {
        console.log("setter");
        this._name = name;
    }
    get name () {
        console.log("getter");
        return this._name;
    }

    // 加一个成员方法
    sayName () {
        console.log(this.name);
    }
}

var p = new Person("zhang", 25); 
console.log(p._name); // "zhang"

执行结果为

图片描述

注意到结果并没有执行getter,因为我们直接访问了p._name,而不是p.name

2.2 只有getter定义只读属性

当一个属性只有getter没有setter的时候,我们是无法进行赋值操作的(第一次初始化也不行),这一点也是相当地。例如

class Person {
    constructor (name) {
        this.name = name;
    }
    // 只有getter
    get name () {
        console.log("getter");
        return this.name;
    }
}

var p = new Person("zhang");

执行结果为

图片描述

当没有getter和setter时,就可以正常读写属性


zhangguixu
1.2k 声望83 粉丝

千里之行,始于足下