js建立對象方法與過程+ES6的class

js建立對象有不少方法,如下是常見方法整理。java

ES5建立對象

工廠模式

function person (name, age, sex) {
    var O = new Object();
    O.name = name;
    O.age = age;
    O.sex = sex;
    O.sayName =function(){
        console.log(this.name);
    }
    return O;
}
var per = person("per",10,"male"); //不須要用new,由於有return,就是個普通函數,很好理解
console.log(per instanceof person); //false

構造函數模式

function Person (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.sayName =function(){
        console.log(this.name);
    }
}
var per =new Person("per",10,"male"); 
console.log(per instanceof Person); //true

分析建立過程,函數

var per =new Person("per",10,"male");

在這行代碼執行時,四個步驟:
①出現了一個空的對象
②this指向這個對象
③執行構造函數的代碼
④把這個對象取個名字是per,per的指針就指向這個對象,因而能夠經過per操做這個對象this

工廠模式定義出的對象,instanceof識別不出是"person類"。
構造函數模式,每次new一個對象,裏面的函數都會建立一次,就這個sayName函數,明明共有同一個就能夠了。
解決這個問題,出現了原型模式:spa

原型模式

function Person () {
    Person.prototype.name = "p1";
    Person.prototype.age = 10;
    Person.prototype.sex = "female";
    Person.prototype.sayName =function(){
        console.log(this.name);
    }
}

那麼,這些代碼幹了什麼呢?
①當你建立Person()函數後,就會有一個prototype屬性隨之而來
咱們能夠看看,這個prototype是什麼,執行如下代碼:prototype

console.log(Person.prototype);

clipboard.png

_proto_保存繼承自Object的方法。裏面只有一個constructor屬性指向Person()函數自身。
②固然咱們是要用這個函數的,執行如下代碼:3d

var per1 =new Person();
var per2 =new Person();
console.log(Person.prototype);

clipboard.png

在建立實際對象時候,就會運行構造函數中的代碼,並且per一、per2兩個對象,就會執行兩次構造函數的代碼,但並不會多建立一個Person的prototype屬性,只是從新賦值裏面的name、age、sex和sayName變量。
③per1和per2有各自的prototype屬性,指向Person的prototype屬性。能夠簡單理解爲per一、per2各自的"指針"指向同一個"對象"。指針

這個原型模式啊,就真的好像單例模式了,每一個建立的對象都在操做同一個對象。code

最優:動態原型模式

function Person (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    if(typeof this.sayName != "function"){  
        Person.prototype.sayName = function(){
            console.log(this.name);
        }
        Person.prototype.sayAge = function(){
            console.log(this.age);
        }
    }
}
var per = new Person("wlq", 19, "man");

這樣的代碼,使得每一個對象的name、age、sex都是各自的(不共有),而後函數寫在原型上,就又是共享的,很不錯。還有個地方,if語句的判斷,使得第二次建立對象時候,不會從新給Person.prototype.sayName和Person.prototype.sayAge重賦值。對象


原型重寫的問題

function Person (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    if(typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            console.log(this.name);
        }
    }
}
function WPerson (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    if(typeof this.sayName != "function"){
        WPerson.prototype = {   //這裏進行了原型的重寫
            constructor: WPerson,
            sayName: function(){
                console.log(this.name);
            }
        }
    }
}
var per1 = new Person("w", 19, "man");
var per2 = new WPerson("q", 18, "man");
var per3 = new WPerson("q", 18, "man");
per1.sayName();  //輸出w
per2.sayName();  //報錯,說沒有sayName這個方法
per3.sayName();  //輸出q
console.log(per2.name);  //輸出q

緣由

重寫原型的發生是在建立對象以後的,per2指向的WPerson的原型上面只有name、age、sex,再建立完per2後,才執行WPerson原型的重寫,per3甚至之後建立的WPerson類型對象就都會有sayName函數了。blog

改進方法

方法一(經過先執行一次WPerson的原型重寫):

function WPerson (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;       
}
WPerson.prototype = {  //寫在建立對象以前
    constructor:WPerson,
    sayName: function(){
        console.log(this.name);
    }
}
var per = new WPerson("q", 18, "man");
per.sayName();  //輸出q

方法二(提早先執行一次new):

function WPerson (name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;  
        if(typeof this.sayName != "function"){
            WPerson.prototype = {  
                constructor:WPerson,
                sayName: function(){
                    console.log(this.name);
                }
            };
            return new WPerson(name,age,sex);  //初次運行時,多調用一次new
           }
    }     
    var per = new WPerson("q", 18, "man");
    per.sayName();  //輸出q

ES6中的class

class Point{
  constructor(x, y) {    //至關於java中的構造函數,若是不寫默認爲空
    this.x = x;          //x,y定義在對象自身上面
    this.y = y;
  }
  add() {                //該方法定義在Point.prototype上
    console.log(this.x + this.y);
  }
}
var p = new Point(2, 3);
p.add();  //輸出5

能夠說,class用法就是ES5中動態原型模式。

相關文章
相關標籤/搜索