js原型詳解

js中的原型毫無疑問一個難點,學習若是不深刻很容易就暈了!

任何一個js知識點,好比事件流,閉包,繼承等,都有許許多多的說法,對於這些知識點咱們都應該先熟練的使用,而後本身整理一套屬於本身的理解說辭,纔不會忘

原型(對象屬性)

Javascript規定,每個函數都有一個prototype對象屬性,指向另外一個對象(原型鏈上面的)。
prototype(對象屬性)的全部屬性和方法,都會被構造函數的實例繼承。這意味着,咱們能夠把那些不變(公用)的屬性和方法,直接定義在prototype對象屬性上。閉包

prototype就是調用構造函數所建立的那個實例對象的原型(proto)。框架

prototype可讓全部對象實例共享它所包含的屬性和方法。也就是說,沒必要在構造函數中定義對象信息,而是能夠直接將這些信息添加到原型中。函數

原型鏈 (JS原型與原型鏈繼承)

實例對象與原型之間的鏈接,叫作原型鏈。proto( 隱式鏈接 )
JS在建立對象的時候,都有一個叫作proto的內置屬性,用於指向建立它的函數對象的原型對象prototype。
內部原型(proto)和構造器的原型(prototype)
一、每一個對象都有一個proto屬性,原型鏈上的對象正是依靠這個屬性連結在一塊兒
二、做爲一個對象,當你訪問其中的一個屬性或方法的時候,若是這個對象中沒有這個 方法或屬性,那麼Javascript引擎將會訪問這個對象的proto屬性所指向上一個對 象,並在那個對象中查找指定的方法或屬性,若是不能找到,那就會繼續經過那個對象 的proto屬性指向的對象進行向上查找,直到這個鏈表結束。學習

實際開發中,有這樣一種寫法,面向對象,這種寫法就是經過構造函數以及原型來運用的(混合模式開發面向對象)

每個函數都有一個原型屬性prototype(對象屬性),裏面放置的是共有、公有的屬性或者方法。(通常狀況屬性是私有的)。注意,只有函數纔有prototyoe屬性,this

    function Person() {
       
    }
    var p = new Person()
    console.log(Person.prototype); // Object{} 
    console.log(p.prototype); //undefined

這個例子能夠發現,函數是存在prototype屬性的prototype

任何對象都是默認存在構造器的,此時咱們的Person()只是普通函數,它實際上是js內置方法Function()構造出來的,而p此時是Person() new出來的,只有new 過了,才叫構造函數

淺談constructor

在 Javascript 語言中,constructor 屬性是專門爲 function 而設計的,它存在於每個 function 的prototype 屬性中。這個 constructor 保存了指向 function 的一個引用。設計

上代碼更容易理解

    function Person() {
       
    }
    var p = new Person()
    console.log(Person.prototype); // Object{} 
    console.log(p.prototype); // undifined
    console.log(p.constructor); //function Person(){}    
    此處的p是經過 Person函數構造出來的,因此p的constructor屬性指向Person
    console.log(Person.constructor); //function Function(){}
    以前提過,每一個函數實際上是經過new Function()構造的
    console.log({}.constructor); // function Object(){}
    每一個對象都是經過new Object()構造的
    console.log(Object.constructor); // function Function() {}
    Object也是一個函數,它是Function()構造的
    console.log([].constructor);  //function Array(){}

我想你們此時對於prototype屬性有了必定的瞭解

   console.log(Object.constructor); // function Function() {}

可能你們對於這個有些不理解,畢竟咱們實際開發中哪見過這玩意code

    console.log(Function instanceof Object); // true
    console.log(Object instanceof Function); // true

這樣你們是否是就明白了呢 函數是對象構造的 對象也是函數構造的,倆者便是函數也是對象,因此爲何構造函數它是一個函數卻返回一個對象,倆者是互相繼承的關係對象

    var o1 = new f1();
    typeof o1 //"object"  

重點講解一下原型prototype的用法,最主要的方法就是將屬性暴露成公用的,上代碼

    function Person(name,age){
        this.name = name;
        this.age = age;
        this.sayHello = function(){
            console.log(this.name + "say hello");
        }
    }
    var girl = new Person("bella",23);
    var boy = new Person("alex",23);
    console.log(girl.name);  //bella
    console.log(boy.name);   //alex
    console.log(girl.sayHello === boy.sayHello);  //false

再看下面的代碼blog

   function Person(name,age){
        this.name = name;
        this.age = age;
        
    }
    Person.prototype.sayHello=function(){
        console.log(this.name + "say hello");
    }
    var girl = new Person("bella",23);
    var boy = new Person("alex",23);
    console.log(girl.name);  //bella
    console.log(boy.name);   //alex
    console.log(girl.sayHello === boy.sayHello);  //true 

咱們給函數Person的原型中聲明瞭sayHello方法,當咱們的構造實例對象去訪問的時候訪問的方法是同一個,這就是prototype原型最大的做用,共享屬性和方法

那麼prototype與proto有什麼關係,先看這麼一串代碼

    var obj = {}
     此處等價於 var obj = new Object()
    console.log(obj.__proto__ === Object.prototype)//true  

JS 在建立對象(不管是普通對象仍是函數對象)的時候,都有一個叫作 __proto__ 的內置屬性,用於指向建立它的構造函數的原型對象。

根據前面的例子咱們很清楚,obj是經過new Object 構造出來的一個對象,那咱們Object的原型對象就是Object.prototype,在Object下面構造出來的全部對象,都有一個__proto__ 指向它的原型,咱們稱這個爲原型鏈

    var obj = []
    console.log(obj.__proto__ === Array.prototype)//true

這個也是同樣的道理

此處要理解,就是原型對象是誰構造的,是誰構造的咱們看構造器

   console.log(Array.prototype.constructor)//Array{}

原型對象確定是它自己構造的,接着看以前的構造函數代碼

   function Person(name,age){
    this.name = name;
    this.age = age;
    
    }
    Person.prototype.sayHello=function(){
        console.log(this.name + "say hello");
    }
    var girl = new Person("bella",23);
    var boy = new Person("alex",23);
    console.log(Person.prototype.constructor);  //Person
    console.log(girl.__proto__==Person.prototype);   //true
    console.log(girl.constructor==Person);  //true 

如今看是否是特別簡單 注意這裏是兩個下劃線__proto__ 叫 槓槓proto槓槓

接下來給一串代碼

  function Person(){

  }
  var person1=new Person()    

快速回答
1.person1.__proto__==

2.person1.constructor==

3.Person.__proto__==

4.Person.prototype.constructor==

5.person1.prototype.constructor==

6.Person.prototype==

你們能夠測測輸入的答案打印是否是爲true 若是你很快打出,說明你理解的已經很透徹了

接下來我找幾道題一塊兒分析一下,深刻了解

              function A(){
                }
                function B(a){
                  this.a = a;
                }
                function C(a){

                  if(a){
                    this.a = a;
                  }
                }
                A.prototype.a = 1;

                B.prototype.a = 1;

                C.prototype.a = 1;


                console.log(new A().a);  //1

                console.log(new B().a);//undefined

                console.log(new C(2).a);//2

咱們先觀察第一個
new A() 很明顯它是A()構造的實例對象,在下面A函數prototype共享了一個屬性a=1,那麼實例對象也能夠經過這個屬性訪問到他的值==1

第一個比較簡單,咱們看第二個
第二個實際上是個坑,首先B()函數它聲明的時候設置了一個參數,注意裏面的方法this,此時this指向的是window,咱們都知道,然而在構造函數以後this指向了new B(),然而此時B 沒有傳入參數,也就是說此時的參數a==undefined,
所以new B()下的屬性a==this.a==undefined (不知道這麼說能不能理解 ̄□ ̄||)

若是咱們給B 傳入一個數(能夠是a,但a必定要先聲明)

                console.log(new B(3).a); //3
                console.log(new B(5).a); //5

這樣應該就好理解了,總不能咱們本身設置的屬性還覆蓋不來爸爸給你的屬性吧

第三個很好理解,從第二個的角度分析,若是傳入參數,輸出參數,若是沒有 輸出1

這道題沒什麼拐彎,比較簡單,咱們再看一題

    function Fun(){
        var getName = function(){
            console.log(1);
        }
        return this;
    }
    Fun.getName = function(){
        console.log(2);
    }
    Fun.prototype.getName = function(){
        console.log(3);
    }
    var getName = function(){
        console.log(4);
    }
    function getName(){
        console.log(5);
    }
            
    Fun().getName(); //4
    getName(); //4
    new Fun().getName();//3
    new new Fun().getName();//3

作題必定要一步步來,先看第一個 Fun().getName();
很明顯此時是Fun()調用getName(),咱們看看Fun(),注意,函數的返回值永遠是return,此處return返回了this,在函數中這裏的this指向window,也就是說第一步Fun( )返回的是window,轉換一下就是window.getName(),
咱們在什麼找一下全局的getName,最終輸出4

第二個其實很簡單,我感受就是來迷惑咱們的,前面省略了window,很明顯仍是4

第三個也太簡單了,只要你理解了我上面寫的內容,一看就知道輸出3

第四個,兩個new? 不要慌 咱們來分析一下

new後面跟的確定是函數,用來構造實例對象,因此new Fun()這是不能拆的,
很明顯此時new Fun()是一個構造函數,雖然稱之爲函數,但其實它是一個對象,由於函數是方法,而方法是不能調用屬性的,可是對象能夠,既然是對象,何來new 構造呢,因此此處分析能夠獲得new Fun ().getName纔是一體連着的,
那很明顯就是原型下的方法咯,因此輸出3

隨着框架應用的愈來愈普遍,不少用法咱們可能並非那麼熟悉,仍是但願你們秉着學習之心,多多複習。

轉載於:https://www.jianshu.com/p/72156bc03ac1

相關文章
相關標籤/搜索