ES5構(gòu)造函數(shù)與ES6類

ES5

es5并沒有類class,我們只能用構(gòu)造函數(shù)來模擬類.

構(gòu)造函數(shù)

構(gòu)造函數(shù)用new操作符一起使用.new具體做了以下事情.
1.new在內(nèi)存中創(chuàng)建了一個新的空對象.
2.讓this指向了這個對象.
3.執(zhí)行構(gòu)造函數(shù)里的代碼打掘,給這個新的對象增加屬性和方法.
4.返回這個新對象揭绑,隱式return.

//構(gòu)造函數(shù)
function Animal(){
    this.name='動物' //實例屬性 
}
//每個創(chuàng)建出的實例身上都帶有name屬性,this指向這個實例創(chuàng)建的對象.
let animal=new Animal();  
animal.name='動物1'
let animal1=new Animal();
console.log(animal1.name) //動物

//如果手動返回一個引用類型this就會指向這個引用類型
function Animal(){
   this.name='動物'
   //this指向返回這個對象
   return {
       a:2
   }
}

let animal=new Animal(); //{a:2}
console.log(animal.name) //undefined

靜態(tài)屬性

function Animal(){
}
//靜態(tài)屬性
Animal.attr='12'
//靜態(tài)方法
Animal.say=function(){
   return 11111
}
console.log(Animal.attr)  //12
console.log(Animal.say()) //11111

原型prototype(每個類都有prototype,是一個對象)

function Animal(){
}
//公共方法 每個實例上都會帶有這方法
Animal.prototype.say=function(){
   return 'say'
}
Animal.prototype.attr='attr'

let animal=new Animal();
let animal1=new Animal();
console.log(animal.say===animal1.say) //true 所有的實例都指向這個地址
console.log(animal.say()) //say
console.log(Animal.prototype) //Animal { say: [Function], attr: 'attr' }

_ _proto _ _ (實例 _ _ proto _ _ 指向所屬類的原型,用來查找屬性和方法)

console.log('123'.__proto__)
console.log({}.__proto__)
let num=123
console.log(num.__proto__)
let bol=true;
console.log(bol.__proto__)
//結(jié)果
//[String: '']
//{}
//[Number: 0]
//[Boolean: false]
//null undefined error
function Animal(){

}

Animal.prototype.say=function(){
   return 'say'
}
Animal.prototype.attr='attr'

let animal=new Animal();
console.log(animal.__proto__);// Animal { say: [Function], attr: 'attr' }  指向?qū)嵗鶎兕惖脑蛯ο?// 查找順序先找自身 自身沒有再去查找所屬類的原型對象
console.log(animal.__proto__===Animal.prototype); //true

構(gòu)造函數(shù)constructor(prototype里包含一個constructor屬性)

function Animal(){

}
let animal=new Animal()
console.log(animal.__proto__.constructor)//[Function: Animal]
console.log(Animal.prototype.constructor) //[Function: Animal]

原理

無標(biāo)題.png

Object.prototype

無標(biāo)題.png
class Animal{
  
}
let animal=new Animal()
console.log(Animal.prototype.__proto__===animal.__proto__.__proto__) //true
console.log(Animal.prototype.__proto__===Object.prototype) //true
console.log(animal.__proto__.__proto__===Object.prototype) //true
console.log(Function.prototype.__proto__===Object.prototype) //true
console.log(Array.prototype.__proto__===Object.prototype) //true
console.log(Function.__proto__===Object.__proto__) //true
console.log(Object.prototype.__proto__) //null Object已經(jīng)是頂層了

繼承

1.實例屬性繼承

function Animal(name){
    this.name=name
}

function Tiger(){
    //this指向Tiger實例
    Animal.call(this,'老虎')
}

let tiger=new Tiger();
console.log(tiger.name)  //老虎

2.原型繼承

function Animal(name){
    this.name=name
}
Animal.prototype.say=function(){
    return 'say'
}
function Tiger(){
    //this指向Tiger實例
    Animal.call(this,'老虎')
}
//這種方式不可采 把Tiget的指向Animal.prototype會造成子類和父類同引用一個內(nèi)存地址 子類原型改變會影響父類
Tiger.prototype=Animal.prototype 

//這樣不會改變子類的原型 先從子類查找 子類查找不到再去父類原型查找 不會污染父類 可以在自己子類原型增加方法
Tiger.prototype.__proto__=Animal.prototype

let tiger=new Tiger();
console.log(tiger.__proto__) //Tiger {}
console.log(tiger.say()) //say

2.1 object.create繼承

function Animal(name){
    this.name=name
}
Animal.prototype.say=function(){
    return 'say'
}
function Tiger(){
    //this指向Tiger實例
    Animal.call(this,'老虎')
}
//tiger.constructor指向的是父類
Tiger.prototype=Object.create(Animal.prototype)
//設(shè)置constructor tiger.constructor指向自己
Tiger.prototype=Object.create(Animal.prototype,{constructor:{value:Tiger}})
let tiger=new Tiger();
console.log(tiger.__proto__.constructor)
console.log(tiger.say())

2.2 模擬object.create

function Animal(name){
    this.name=name
}
Animal.prototype.say=function(){
    return 'say'
}
function Tiger(){
    //this指向Tiger實例
    Animal.call(this,'老虎')
}
function create(prototypes,constr){
    function Fn(){

    }
    Fn.prototype=prototypes;
    if(constr&&constr.constructor.value){
       Fn.prototype.constructor=constr.constructor.value
    }
    return new Fn()
}

Tiger.prototype=create(Animal.prototype,{constructor:{value:Tiger}});
Tiger.prototype.say=function(){
    return 'Tiger say'
}
let tiger=new Tiger();
console.log(tiger.__proto__.constructor) //[Function: Tiger]
console.log(tiger.say()) // Tiger say
console.log(Animal.prototype.say()) //say

object.create實現(xiàn)原理

無標(biāo)題.png

es6類(class)

class Animal{

}
let animal=new Animal();
console.log(animal)

靜態(tài)屬性(通過類自身調(diào)用)

class Animal{
   static attrs='attrs'
   static say(){
       return 'say'
   }
}
console.log(Animal.attrs) //attrs
console.log(Animal.say()) //say
class Animal{
    static attrs='attrs'
    constructor(){}
    say(){
        return 'say'
    }
    
}
class Tiger extends Animal{
   constructor(){

   }
}

console.log(Tiger.attrs) //attrs

實例屬性

//沒有寫contructor情況下 增加屬性 會默認(rèn)執(zhí)行constructor把屬性添加到實例上
class Animal{
    attrs='attrs'   // 注意!!這里定義的不是在prototype上的屬性,而是給實例初始化的 實例屬性
}

let animal=new Animal();
console.log(animal.attrs)


class Animal{
   constructor(){
       this.attrs='attrs'  //實例屬性
   }
}

let animal=new Animal();
console.log(animal.attrs)

prototype(定義在類里 es6的原型是不可枚舉的)

class Animal{
    constructor(){}
    say(){
        return 'say'
    }
    
}
let animal=new Animal();
console.log(Animal.prototype.say) //[Function: say]

私有屬性(ES2020實驗草案中晰甚,增加定義私有類字段功能福扬,使用# ,私有屬性無法在類的外部調(diào)用)

//私有屬性
class Animal{
     #privateValue="私有"
}

//私有方法
class Animal{
     #privateValue(){
        return 'private'
     }
}
//私有靜態(tài)屬性
class Animal{
    statci  #privateValue="私有"
}
//可以在類的內(nèi)部使用脯倒,無法在類的外部使用

calss Animal{
    #attrs='11111'
    #bac(){
        Animal.#attrs="22222"
    }
}

console.log(Animal.#bac) //error

繼承(extexds)

//子類不寫constructor會默認(rèn)執(zhí)行父類的constructor
class Animal{
    constructor(attrs){
       this.attrs=attrs
    }
    say(){
        return 'say'
    }
}

class Tiger extends Animal{

}

let tiger=new Tiger('tiger attrs'); //Tiger { attrs: 'tiger attrs' }
console.log(tiger.__proto__.say) //[Function: say]
//子類寫constructor,默認(rèn)走子類的構(gòu)造函數(shù)
class Animal{
    constructor(attrs){
       this.attrs=attrs
    }
    say(){
        return 'say'
    }
}

class Tiger extends Animal{
   constructor(attrs){
      super(attrs)  //等同于 Animal.call(this,attrs) 不調(diào)用super會報錯
   }
}

let tiger=new Tiger('tiger attrs');
console.log(tiger) //Animal { attrs: 'tiger attrs' }
console.log(tiger.__proto__.say) //[Function: say]
//子類和父類定義相同的方法愿吹,會先執(zhí)行子類 子類沒有才會向類查找
class Animal{
    constructor(attrs){
       this.attrs=attrs
    }
    say(){
        return 'say'
    }
}

class Tiger extends Animal{
   constructor(attrs){
      super(attrs)  //等同于 Animal.call(this,attrs)
   }
   say(){
       return 'tiger say'
   }
}

let tiger=new Tiger('tiger attrs'); //Tiger { attrs: 'tiger attrs' }
console.log(tiger.say()) // tiger say
//子類調(diào)用父類方法
class Animal{
    constructor(attrs){
       this.attrs=attrs
    }
    say(){
        return 'say'
    }
}

class Tiger extends Animal{
   constructor(attrs){
      super(attrs)  //等同于 Animal.call(this,attrs)
   }
   say(){
       return super.say()  //等用于 Animal.prototype.say()  //super===Animal.prototype
   }
}

let tiger=new Tiger('tiger attrs'); //Tiger { attrs: 'tiger attrs' }
console.log(tiger.say()) //say
//靜態(tài)方法調(diào)用
class Animal{
    constructor(attrs){
       this.attrs=attrs
    }
    static say(){
        return 'say'
    }
}

class Tiger extends Animal{
   constructor(attrs){
      super(attrs)  //等同于 Animal.call(this,attrs)
   }
   static say(){
       return super.say()  //super等用于Animal類  //super===Animal
   }
}

console.log(Tiger.say()) //say

抽象類(只可繼承金踪,不可被實例化new)

1.new.target實現(xiàn)抽象類

class Animal{
    constructor(){
        //執(zhí)行兩次 1.new.target=[Function: Animal] 2.new.target[Function: Tiger]
        if(new.target===Animal){
            throw new Error('not new')
        }
    }
}

class Tiger extends Animal{

}
new Animal()  //Error: not new
let tiger=new Tiger();

es5構(gòu)造函數(shù)模擬實現(xiàn)es6(原型屬性不可枚舉)

function handleConstructor(Constructor,protoProperties){
    for(let i=0;i<protoProperties.length;i++){
        let property=protoProperties[i]
        Object.defineProperty(Constructor,property.key,{
             //是否可以刪除
             configurable:true,
             //是否可以枚舉
             enumerable:false,
             ...property
        })
    }
}

// console.log(Eat.prototype) //不可枚舉
function definePrototype(Constructor,protoProperties,staticPorto){
    if(Array.isArray(protoProperties)){
       handleConstructor(Constructor.prototype,protoProperties)
    }
    if(Array.isArray(staticPorto)){
        handleConstructor(Constructor,staticPorto)
    }
}


//es5的類 模擬es6的類 不可枚舉 Object.definprototype
let Animate=(function(){
    function Animate(){
         if(!(this instanceof Animate)){
             throw new Error('not new')
         }
    }
    //改變原型不可枚舉  babel編譯出es6的類就是這樣寫的
    definePrototype(Animate,[
        {
            key:'say',value:function(){
                console.log('say')
            }
        }
    ],[
        //靜態(tài)屬性
       {
            key:'eat',value:function(){
               return 'eat'
            }
        }
    ])
    return Animate
})()

console.log(Animate) //[Function: Animate]
console.log(Animate.prototype) //Animate {}
console.log(Animate.eat()) //eat

instanceof

instanceof運算符是用來判斷一個構(gòu)造函數(shù)的prototype屬性所指向的對象是否存在另外一個要檢測對象的原型鏈上.

//obj instanceof Object 檢測Object.prototype是否存在與參數(shù)obj的原型鏈上.
function Person(){}
let p=new Person();
//p.__proto__==Person.prototype
console.log(p instanceof Person) //true

hasOwnProperty()操作符

hasOwnProperty檢查一個屬性是否是實例屬性.

//實例屬性
function Animal(){
    this.name='name'
}

let animal=new Animal();
console.log(animal.hasOwnProperty('name')) //true
//不查看原型屬性,只看實例屬性
function Animal(){
    
}
Animal.prototype.name='123'

let animal=new Animal();
console.log(animal.hasOwnProperty('name')) //false

in操作符

有兩種方法能使用in操作符:單獨使用for-in循環(huán)使用.在單獨使用時牵敷,in操作符會通過對象能夠訪問給定屬性返回true,無論屬性存在(實例)還是(原型中).

function Animal(){
    this.name='name'
}

let animal=new Animal();
console.log('name' in  animal) //true
function Animal(){
    
}
Animal.prototype.name='123'

let animal=new Animal();
console.log('name' in  animal) //true
function Animal(){
    
}
let animal=new Animal();
console.log('name' in  animal) //false
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胡岔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子劣领,更是在濱河造成了極大的恐慌姐军,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尖淘,死亡現(xiàn)場離奇詭異,居然都是意外死亡著觉,警方通過查閱死者的電腦和手機村生,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饼丘,“玉大人趁桃,你說我怎么就攤上這事∫薷耄” “怎么了卫病?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長典徘。 經(jīng)常有香客問我蟀苛,道長,這世上最難降的妖魔是什么逮诲? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任帜平,我火速辦了婚禮,結(jié)果婚禮上梅鹦,老公的妹妹穿的比我還像新娘裆甩。我一直安慰自己,他們只是感情好齐唆,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布嗤栓。 她就那樣靜靜地躺著,像睡著了一般箍邮。 火紅的嫁衣襯著肌膚如雪茉帅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天媒殉,我揣著相機與錄音担敌,去河邊找鬼。 笑死廷蓉,一個胖子當(dāng)著我的面吹牛全封,可吹牛的內(nèi)容都是我干的马昙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼刹悴,長吁一口氣:“原來是場噩夢啊……” “哼行楞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起土匀,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤子房,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后就轧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體证杭,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年妒御,在試婚紗的時候發(fā)現(xiàn)自己被綠了解愤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡乎莉,死狀恐怖送讲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情惋啃,我是刑警寧澤哼鬓,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站边灭,受9級特大地震影響异希,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜存筏,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一宠互、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧椭坚,春花似錦予跌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至垂涯,卻和暖如春烁焙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背耕赘。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工骄蝇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人操骡。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓九火,卻偏偏與公主長得像赚窃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子岔激,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355