JS对象设置属性setter和getter

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");

输出结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45467083/article/details/105691862
今日推荐