一、為什么會有get和set的出現
在程序語言中,對象(Object)有以下幾個特點:
1. 對象具有唯一標識性:即使完全相同的兩個對象,也並非同一個對象。(eg:console.log({a: 1} == {a: 1}); >>>false)
2. 對象具有狀態: 同一對象有不同的狀態(c++中的成員變量,Java中的屬性)
3. 對象具有行為: 對象的狀態可能會有變化(c++中的成員函數,Java中的方法)
在JavaScript中,狀態和行為被統一抽象為“屬性”,這是因為在js中方法(function)也是以object的形式存在的,可以以屬性的方式來進行抽象。
var a = { b: 1, c: function(){ return 3 } }
js允許在運行時向對象添加狀態,並且可以添加行為。為了提高抽象能力,js的屬性被設計成了更加復雜的形式,它提提供了兩類屬性getter/setter,作為其數據屬性和訪問器屬性。也可以簡單的理解為,getter 是一種獲得屬性值的方法,setter是一種設置屬性值的方法。
- getter負責查詢值,它不帶任何參數,setter則負責設置鍵值,值是以參數的形式傳遞,在他的函數體中,一切的return都是無效的
- get/set訪問器不是對象的屬性,而是屬性的特性,特性只有內部才用,因此在javaScript中不能直接訪問他們,為了表示特性是內部值用兩隊中括號括起來表示如[[Value]]
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; } }
上面的例子中,get方法用來獲取name的值,get方法用來改變name的值。
有人到這里會疑惑,獲取值、改變值,只要直接person.name和person.name = "其他人"不就行了么?引入get和set方法不是多此一舉?
可是在上面案例中,通過函數來獲取對象屬性、改變對象屬性,是可以console.log到屬性的行為的,也就是,通過函數是可以監聽到屬性的變化的,而直接通過“.”來獲取改變屬性,僅僅是實施了行為卻無法進行行為的監聽。
通過set和get監聽屬性的變化,這恰恰就是Vue中雙向綁定的思路基礎。
二、VUE中的get、set與雙向綁定
在Vue項目中,我們console.log()一個對象的屬性,可以在控制台看到以下結果:
發現每個對象屬性里都有以下定義在其原型鏈上的以下方法(__proto__):
可以看到,原型鏈上定義的方法有ES5中的__defineGetter__和__defineSetter__,以及ES6中引入的get和set關鍵字。在使用對象初始化過程來定義Getter和Setter方法時唯一要做的事情就是在getter方法前面加上“get”,在setter方法前面加上“set”。 還有一點要注意的就是getter方法沒有參數,setter方法必須有一個參數,也就是要設置的屬性的新值。
var person = { val: '名字',
get name() {return this.val;},
set name(name) {this.val = name;}
}
而ES5的對象原型的屬性__defineGetter__和__defineSetter__,用來給對象已經定義之后,給對象綁定新的get和set方法:
var person = {
val: '名字'
}
person.__defineGetter__('name',function(){return this.val;});
person.__defineSetter__('name',function(name){this.val = name;})
console.log(person.name); >>> 名字 person.name = '新名字'; console.log(person.name); >>> 新名字