js 原型對象

構(gòu)造函數(shù)的缺點

  • js 通過構(gòu)造函數(shù)生成新對象
    function OutFun (name,gender){
          this.name=name
          this.gender=gender
      }
    
      var fun = new OutFun('小明','女')
      console.log(fun.name)
    
  • OutFun函數(shù)是一個構(gòu)造函數(shù),OutFun函數(shù)內(nèi)部定義了name屬性和gender屬性。實例對象上都會有這兩個屬性,
  • 屬性定義到實例上,但有一個缺點。就是同一個構(gòu)造函數(shù)的多個實例之間是無法共享屬性。造成資源的浪費
    function OutFun (name,gender){ this.name=name this.gender=gender this.innerFun = function (){ console.log('this') } } var fun = new OutFun('小明','女') var fun1 = new OutFun('小明','女') console.log(fun.innerFun===fun1.innerFun)//false
  • 可以看出fun和fun1雖然是同一個構(gòu)造函數(shù)但其實是兩個實例。他們實例上都有innerFun 。我們每實例化的時候就創(chuàng)建一個新的innerFun。那怎么共享innerFun?那么就用到下面的原型對象prototype了

原型對象prototype

  • js繼承,就是原型對象中的所有屬性和方法,都能被實例對象共享。js中每一個函數(shù)都有prototype,prototype其實就是一個object。
      console.log(typeof OutFun.prototype)//object
    
    • 對于普通函數(shù),prototype沒有太大作用。但對于構(gòu)造函數(shù),生成實例的時候該屬性會自動成為實例對象的原型。

       function OutFun(){
          this.age='33'
        }
        OutFun.prototype.name='小明'
        OutFun.prototype.age='44'
        var fun=new OutFun()
        console.log(fun.name)//小明
        console.log(fun.gender)//undefined
        console.log(fun.age)//33
      
    • 我們在訪問name屬性的時候。實例對象上沒有該屬性或方法,它就回去原型對象去找該屬性或方法.若實例對象上有則不去原型對象上找。若原型對象上也沒有該屬性和方法。那么就去原型的原型找,還找不到就去原型的原型的原型找,直到找到Object.prototype還沒有,就返回undefined
      注意,要找某個屬性會一級級向上,對性能也是有影響的。這就意味著,如果這個屬性根本不存在,那么我們就得再整條原型鏈里查找一邊。對性能的開銷也越大。

    • 原型對象:定義實例對象共享的屬性和方法。

原型鏈

  • 原型鏈:js中所有對象都有自己的原型對象(prototype)。任何對象都可以充當(dāng)其他對象的原型。原型本身也是對象,所以它也有自己的原型。那么就形成了---原型鏈(對象,對象的原型,對象原型的原型……)
    對象的原型最終到Object.prototype(null)。所有對象都可以繼承原型(prototype)上的屬性

       Object.getPrototypeOf(Object.prototype)//null
    

    Object.getPrototypeOf方法返回參數(shù)對象的原型

image.png

eg:讓構(gòu)造函數(shù)中原型對象指向一個數(shù)組,這就意味著我們這個實例對象就可以使用數(shù)組的方法

      function OutFun(){}
      OutFun.prototype=new Array()
      var fun = new OutFun()
      fun.push(1,2,3)
      console.log(fun.length)//3
      console.log(fun instanceof Array)//true--------------------instanceof 判斷一個對象是否為某個構(gòu)造函數(shù)的實例

instanceof運算符

  • 判斷一個對象是否為某個構(gòu)造函數(shù)的實例
  • X instanceof S -----------------------X對象,S構(gòu)造函數(shù)。instanceof 檢查右邊S構(gòu)造函數(shù)的原型對象(prototype),是否在左邊對象的原型鏈上。
    于S.prototype.isPrototypeOf(X)一樣。
        function OutFun(){}
        var fun=new OutFun()
        console.log(fun instanceof OutFun)//true----表示該fun實例對象是OutFun構(gòu)造函數(shù)的實例
  • instanceof檢查整條原型鏈,同一個實例對象,可能會對多個構(gòu)造函數(shù)都返回true。
        var arr=new Array()
        console.log(arr instanceof Array)//true
        console.log(arr instanceof Object)//true
  • 任意對象(null除外)都是Object的實例,所以instanceof運算符可以判斷是否為非null
        var obj = { name: 'xiaoming' };
        var arr = new Array()
        console.log(obj instanceof Object)// true
        console.log(null instanceof Object)// false
        console.log(arr instanceof Object)// true
  • instanceof運算符只能用于對象,不適用基本數(shù)據(jù)類型的值
        var num = 2342;
        console.log(num instanceof Number) // false

        var str = '2342';
        console.log(str instanceof Number) // false

        var isTrue = true
        console.log(isTrue instanceof Number) // false

        var und = undefined
        console.log(und instanceof Number) // false
  • 利用instanceof運算符,解決調(diào)用構(gòu)造函數(shù)時,忘了加new命令的問題。
    function Fubar (foo, bar) {
            if (this instanceof Fubar) {//this是否是構(gòu)造函數(shù)的實例,如果不是則沒有new
                this._foo = foo;
                this._bar = bar;
            } else {
                return new Fubar(foo, bar);
            }
        }

constructor 屬性

  • prototype對象有一個constructor屬性,默認(rèn)指向prototype對象所在的構(gòu)造函數(shù)。
        function OutFun(){}
        //默認(rèn)指向prototype所在的構(gòu)造函數(shù)--可知道我們要想知道這個實例對象是那個構(gòu)造函數(shù)產(chǎn)生的
        console.log(OutFun.prototype.constructor===OutFun)//true
        //改變OutFun的原型對象,那么constructor的指向也跟著改變了---constructor屬性表示原型對象與構(gòu)造函數(shù)之間的關(guān)聯(lián)關(guān)系,如果修改了原型對象,會同時修改constructor屬性,防止引用的時候出錯。
        OutFun.prototype=new Array()
        console.log(OutFun.prototype.constructor===OutFun)//false
        //手動改變constructor
        OutFun.prototype.contructor=OutFun
        console.log(OutFun.prototype.constructor===OutFun)//false
  • 既然constructor是prototype的屬性,那么表示constructor可以被所有實例對象繼承
  • 我們可以從constructor調(diào)用構(gòu)造函數(shù)。相當(dāng)于調(diào)用自身的構(gòu)造函數(shù)。
        function OutFun(){}
        var fun=new OutFun()
        var funCon = new fun.constructor()
        console.log(funCon instanceof OutFun)//true
  • 通過name屬性,從實例得到構(gòu)造函數(shù)的名稱。
        function OutFun(){}
        var fun=new OutFun()
        console.log(fun.constructor.name)//OutFun

構(gòu)造函數(shù)的繼承

  • 子類是整體繼承父類
  1. 第一步是在子類的構(gòu)造函數(shù)中,調(diào)用父類的構(gòu)造函數(shù)。
  2. 第二步,是讓子類的原型指向父類的原型,這樣子類就可以繼承父類原型。
  //首先我們先定義父類
        function Parent(){
            this.num = 0
        }
        Parent.prototype.sum = function(num){
            this.num +=num
        }
        //子構(gòu)造函數(shù)
        function Son(){
            Parent.call(this)//調(diào)用父類構(gòu)造函數(shù)
        }
        Son.prototype = Object.create(Parent.prototype)//子類繼承父類的原型
        Son.prototype.constructor = Son
        var son = new Son()
        son.sum(3)
        son.sum(5)
        console.log(son.num)
  • 子繼承父類的單個方法
    //定義父類
        function Parent(){
            this.num = 0
        }
        Parent.prototype.sum = function(num){
            console.log(num,'num')
            this.num += num
        }
        //子構(gòu)造函數(shù)
        function Son(){
            Parent.call(this)//調(diào)用父類構(gòu)造函數(shù)
        }
        Son.prototype.sum=function(){
            Parent.prototype.sum.call(this,3)
        }
        var son = new Son()
        son.sum()
        son.sum()
        console.log(son)//6
        console.log(son instanceof Son)//false
        console.log(son instanceof Parent)//false
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 1、理解Object和Function Object和Function都是引用類型,是一種數(shù)據(jù)結(jié)構(gòu),封裝數(shù)據(jù)和功能...
    小笨郎閱讀 657評論 0 1
  • 每當(dāng)創(chuàng)建一個新函數(shù),都會依據(jù)一些規(guī)則為其創(chuàng)建一個prototype屬性,該屬性指向函數(shù)的原型對象。原型對象默認(rèn)有一...
    晴天的晴q閱讀 369評論 0 1
  • 為什么要寫原型對象? 原型,其實已經(jīng)是前端知識中老生常談的內(nèi)容了。很多初學(xué)者和工作者其實都覺得這個概念其實跟你使用...
    古朋閱讀 569評論 1 7
  • 首先我們要先了解幾個概念,js萬物皆對象,所有類型(對象,函數(shù),數(shù)組...)都有一個屬性 proto,只有函數(shù)才有...
    李柏成_Burc閱讀 233評論 0 0
  • 原型對象:每創(chuàng)建一個函數(shù),該函數(shù)就會自動帶有一個 prototype 屬性。該屬性是個指針,指向了一個對象,我們稱...
    Shi_wen閱讀 110評論 0 0

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