從這篇博客開始,我們就來說下,在前面就提到過的可響應對象,這個東西特別的重要。
那什麼叫做可響應對象呢?
用人話來說就是,它的屬性是可以被監聽的。
說白了就是,平常一個屬性放在那,就放在那了,不管你做了啥操作,這事直接就過去了。
而如果你用了可響應對象,你的屬性是可以被監聽起來的,你這邊做了任何的操作,我這邊都可以有一些反應。
那麼,爲什麼要這麼做?
就一個原因,爲了方便。
在這會給大家介紹三種方法:
1,accessor,訪問器。有的人也管它叫 get / set。
2,defineProperty。
實際上來說,看它名字,你就知道它是幹什麼的,define 定義,property 屬性,就是定義一個屬性。
所以它的作用,其實就在於,幫助你一個已有的對象,去添加一個特殊的屬性。
爲什麼呢?
比如我這裏有一個 json ,我給它加個 a:json.a = 12,這樣一點特殊的地方都沒有。
而如果我用了 defineProperty 之後,它的作用,就幫助我來添加一個可以被監聽的屬性,這個就不一樣的了。
當然這個東西它有一些的缺陷,所以我們最終用到的,是另外一個東西,叫做 Proxy。
3,proxy。
proxy,它應該來說是 defineProperty 的一個後續的版本。
說白了,它的功能非常的強大,它不但可以監聽的範圍比 defineProperty 廣的多,而且 defineProperty 的一些問題,它還沒有。
所以 proxy 很重要,也是非常好用的一個東西。
這篇博客講解的就是訪問器,那麼現在我們就正式開始。
首先我們就來看一個最簡單的例子,就是我怎麼樣才能讓一個東西,讓一個屬性,能夠響應我的操作。
比如,我有一個類,裏面有一個屬性 count,我們讓這個 count++
實際上來說,在這個時候,想都不用去想,沒有任何反應。
任何代碼都不會被執行,只是很單純的那個 count 會變:
但是,現在我就換一個寫法。
首先,有一個東西叫做 get,然後我在來一個 set:
這兩個東西就構成了一個對 count 的訪問器。
當然,在我這個對象的內部,我也得保存一個真正的數據。
我們前面也提到過,對於面向對象來說,有一個特別重要的概念,就是我希望能夠把它內部的這個成員,尤其是屬性,給它隱藏起來,不讓它被外面直接的操作。
所以這時候,我在這就放一個 _count:
注意,這個 count 是用下劃線來表示的。
下劃線在我們的成員當中,一般代表的是私有的,因爲我們的 js 到目前爲止,還不具備真正意義的私有成員。
像 ts,java 都有,一個 private 直接搞定,但 js 沒有真正的私有成員,所以我們就通過命名的方式,來對它做一定的標記。
所以以後你看到別人的類裏面有某個東西是下劃線開頭的,你千萬不要去用它,說明別人是刻意的把這個東西藏起來了,如果你去用了的話,那不定會出什麼事。
然後現在,說白了,這個 get 也好,set 也好,它們真正操作的其實是 this._count。
然後現在我們來看看 get,假設現在什麼都不寫的話,就沒有 return,也就是沒有值,那麼肯定是一個 undefined。
那麼現在我們來打印一個 a.count:
注意,儘管在這我用的是 a.count,是以一個屬性的方式在使用它,但是其實它背後會變成一個函數調用,來調 get count,這個就是訪問器它本身的一個作用。
先不管別的,我們先看看效果:
那麼在這個時候,你可以明確的看到,它就是一個 undefined。
爲什麼?因爲 a.count 對應的就是 get count,而我們的 get count 並沒有返回值,沒有 return,它就會默認的 return undefined。
比如,我們隨便返回一個值:
那麼你可以看到,是不是它打印出來的 a.count 就是在 get count 裏面 return 的那個值。
這個 count 可以跟 _count 有關聯,也可以沒關聯,這個完全是我自己說了算。
但是按照正常的情況,我們一般都是會返回它背後真實的數據:
然後現在這時候你可以看到,打印出來就是 12 了。
在接下來,當我們需要對這個 count 進行設置的時候,比如:
然後我們來看看 a.count:
你會發現賦值了也沒變。
原因很簡單,因爲賦值的時候,它背後會偷偷的調用 set count,而我們在 set count 裏面啥都沒做。
所以這時候,我們應該把這個東西存進去,這樣它才能夠有所變化:
說白了,我們現在所做的事,算是對這個 count 加了一道防火牆,什麼意思呢?
就是說,你進去也好,出來也好,不能直接進,也不能直接出,你需要先經過我的 get / set 函數。
當然,到目前爲止,我們都是簡單的給他設置,什麼都沒幹,那麼我們可以做一些其他的事情。
比如,這個 count 只能接收數字:
可以看到,當我們賦值 666666 的時候,是沒問題的。
如果我們賦值的是一個字符串,這時候就報錯了。
所以,我們可以看到,這個 count 它是被保護起來的。
並且,它還是 666666,亂七八糟的值是沒有進去的:
現在這個時候我們就看到了這個 count 的作用,或者說訪問器它的一個作用。
可以說很簡單,它就一個 get,一個 set,多了沒有,就這兩個東西。
那麼可能有人會問 get,set 在這裏是什麼?
這個 get 和 set 是我們 js 裏面一個特殊的語法,它所定義的這個方法,不是通常意義上的方法。
通常意義上的方法, 是供我們調用的,而這 2 個加完之後,它會變成所謂的訪問器方法。
所謂訪問器方法,說白了就是說,你把我當做一個變量來用就可以。
然後你在讀取或者設置的時候,我會自動的去調用它背後的 get 或者 set 函數,你不用管,我來做。
所以,它就是幹這個事用的,爲了方便。
當然,順便一提,有人可能也會問,那我的這個屬性和方法重名行不行?
比如,我們把 _count 都改成 count:
我們先不說訪問器,就說平常,你一個屬性跟一個方法重名,這事本身靠譜嗎?本身就已經不靠譜了。
所以我們這麼寫,你可以看到,頁面上是會出現問題的。
爲什麼會報錯?
因爲我們在外面讀取 a.count 的時候,首先它會來到 get count,然後它會試圖 return this.count。
注意,當我們執行到 return this.count 的時候,這是不是又是一個讀取的操作?
去哪讀?又來到 get count 這讀,然後它會再 return this.count,這就無限死循環了。
所以這個時候,我們的真實數據,跟你的訪問器,名字要岔開,不然的話肯定是會出事的,這事不用想。
所以,訪問器這個東西,它的優點就是特別的簡單,隨手拿來就能用。
還記不記得我們之前博客裏面做過的熱門主播 HotList(js 進階三和四)。
我們當初是這麼來實現的:我們給 title,專門的配了一個 setTitle 和 getTitle,當時也是可以滿足我們的要求的。
比如,當我們 setTitle 之後,標題肯定是會變的:
但是說句特別實在的話,這事不方便,我希望的是這樣:
但我們知道這麼寫是不行的,因爲這個 title,它其實是一個普普通通的屬性,你對它進行賦值,不會有任何的操作。
所以,我們能不能把這個東西用訪問器來搞的更加的方便一點呢?當然是可以的。
首先,我們把 title 改成 _title:
爲什麼?
因爲我要把自己給隱藏起來,我不能隨便讓人去改。
接下來,我們要做的事,就來了:
首先,我們這邊就不希望在搞成 getTitle 和 setTitle 了,我們換成 get 和 set:
那麼有了這樣的一個東西之後,我們的事情就會變的非常的方便。
可以看到,現在的 list.title 是熱門主播,當我們進行 list.title = 'xxx' 賦值的時候:
可以看到,也是跟着變的,就像你在用一個變量一樣,非常的簡單,非常的方便。
說句實話,這個就和我們原先的 list.setTitle('xxx') 效果一樣,只不過現在這個更方便一些。
所以訪問器沒別的,就是爲了方便。
所以,就像我們最開始說的,這個訪問器特別的簡單,隨手就用,隨手就寫。
並且它的寫法也非常的簡單,就像普通的一個方法一樣來用,只不過前面有個關鍵字叫 get,set。
以及沒人規定說,必須 get 跟 set 配着來,你可以只有get,我這個屬性只讀的,我不提供修改操作,也是可以的。