原型與新版的類-class

首先來理解原型
原型 === 共用屬性
可以先看看方姐的幾篇文章:
什么是JS原型鏈
JS 中 proto 和 prototype 存在的意義是什么?
JS 的 new 到底是干什么的?

var obj = {}
obj.toString = ???  // 按常規(guī)邏輯來看,應該是undefined
//然而 打印結(jié)果是 "[object Object]"
//所以
obj.toString() = window.Object.prototype.toString()

這樣,就做到了代碼復用
再來看一個問題

var arr = [1,2,3]
arr.toString() = "1,2,3"

如果說每次調(diào)用toString()都相當于是調(diào)用window.Object.prototype那為什么不同的對象調(diào)用同一個toString()的時候打印出來的值不一樣呢?
是不是可以這樣假設:toString()知道是誰調(diào)用了它

實際上

obj.toString = obj.toString.call(obj);
obj被傳給toString()了

可以來證明一下

var arr = [1,2,3]
var arr2 = [4,5,6]
arr2.toString() 
//打印出 "1,2,3" 這沒有問題
//那么
arr2.toString.call(arr) 
"1,2,3"
//這樣就很明顯了

原型的用法?

按照上面的邏輯
obj.hi() === 共用屬性.hi.call(obj)
那么來改寫一下代碼

var 共用屬性 = {
    hi(a){
        console.log(a)
    }
};
var obj = { name : "我是obj"};
obj.__proto__ = 共用屬性
obj.hi()  // === 共用屬性.hi.call(obj)
能否打印出{ name : "我是obj"}?

結(jié)果卻是 undefined

???? 什么鬼????
這就要說到js的一個坑了,實際上obj確實傳給了共用屬性,但是 用別的形參無法獲取到,只能用this
相當于:

var 共用屬性 = {
    hi(this,a){
        console.log(a)
    }
};
這里obj實際上是傳給了this,但是js默認隱藏了

所以把代碼改成:

var 共用屬性 = {
    hi(){
        console.log(this)
    }
};
obj.hi();
{name : "我是obj"}

好,到這我們再來深入探究一下
obj.__proto__已經(jīng)等于了共用屬性,也就是說
obj.__proto__ != window.Object.prototype,那么obj.toString()會是undefined嗎?
答案是 no。
實際上,當你調(diào)用obj.toString()的時候,首先會在自身上看有沒有這個屬性,如果沒有,就會去你的原型上找,前面已經(jīng)設置了obj的原型等于共用屬性,所以,接著會在共用屬性上找有沒有toSring,還是沒有,然后會繼續(xù)去共用屬性的原型window.Object.prototype上找,找到了之后,調(diào)用window.Object.prototype.toString.call(obj)
當然,如果在window.Object.prototype上也沒有找到,會接著去它的原型上找....直到找到或者找到null為止

可以打印出來看看
window.Object.prototype.__proto__ 
null

所以,每當你聲明一個對象的時候,JS會默認給你執(zhí)行

新聲明的對象.__proto__=window.Object.prototype
或者
新聲明的對象.__proto__=window.Array.prototype

什么是類?

var obj1 = {
    name : '張三',
    age : 18
};
var obj2 = {
    name : '李四',
    age : 20
};

很明顯 obj1obj2很相似,可以把它們歸為一,所以可以把 obj1obj2叫做同一類對象
那如果有不同的對象呢?

var obj3 =  {
    aaa = 1,
    bbb = 2
};

明顯跟上面的不能算一類
如果同一類對象分為一類,那么我們怎么用代碼表示它呢?
方法有兩種:

  • 寫一個文檔,在文檔中寫清楚
  • 提供一個函數(shù)來創(chuàng)建這一類的對象

function createPerson(name='',age=18){
    var obj = {}
    obj.name = name
    obj.age = age
    return obj
};
//開始創(chuàng)建對象
createPerson()
{name : "",age:18}
createPerson("王二狗",16)
{name : "王二狗",age:16}

類是擁有共同特征的對象
再看上面的代碼,每個對象的name、age都不一樣,怎么在創(chuàng)建它們的時候給它們添加共有屬性呢?
當然是用原型
所以代碼可以改成

var 共有屬性 = {
    attr1(){console.log("我們是同類")},
    attr2: '同一類'
}
function createPerson(name='',age=18){
    var obj = {}
    obj.name = name
    obj.age = age
    obj.__proto__ = 共有屬性
    return obj
};

開始創(chuàng)建對象


構(gòu)造函數(shù):創(chuàng)建某個類的對象的函數(shù)
類是擁有相同屬性的對象
自有屬性:對象自身的屬性
共有屬性:對象原型里的屬性

class

每一個class都有一個constructor(構(gòu)造函數(shù)),用來構(gòu)造自有屬性


那么共有屬性放在哪里呢?
很簡單,放在constructor外面就可以了

目前 共有屬性只能是函數(shù)

再來看看復雜一點的
extends 繼承

注意:在要繼承的對象的構(gòu)造函數(shù)里一定要執(zhí)行super()
所以繼承extends的意思是:
如果一個類繼承了另一個類,那么這個類的對象就有被繼承的類的屬性
那么super()的作用是什么呢?
還是看代碼


p1居然具有了Animal的constructor里的屬性
所以
super()的作用就是:執(zhí)行你繼承的類的constructor
被繼承的類可以叫做 基類 或者 超類
所以super()執(zhí)行一下超類的構(gòu)造函數(shù)
super()必須放在constructor的第一行

再來看看 get
我們知道想要調(diào)用一個對象里的某個函數(shù),就得用對象名.函數(shù)名稱()這種方式,
如果在函數(shù)前面加一個get,就可以直接用對象名.函數(shù)的方法來調(diào)用了

當然這個對象并不是具有這個函數(shù)返回值的屬性

但是有一個很嚴重的問題,如果前面寫錯了,后期除了更改源代碼以外,沒有辦法再修改get函數(shù)里面的內(nèi)容

所以js又給了我們一個方法, set
具體用法如下


實際上class是有些麻煩的 沒有原型靈活
但是還是有一些優(yōu)點的,比如某個對象的一個屬性,我們想讓它是只讀的,不允許修改,就可以這樣
用this._隱藏屬性,然后在get中return出去,沒有set就無法修改

然后用set來控制寫入
在set里設置規(guī)則來控制寫入

靜態(tài)方法 static
靜態(tài)方法就是只能通過類名.方法名來訪問的方法,new出來的對象都不能訪問

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容