js建立對象有不少方法,如下是常見方法整理。java
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);
_proto_保存繼承自Object的方法。裏面只有一個constructor屬性指向Person()函數自身。
②固然咱們是要用這個函數的,執行如下代碼:3d
var per1 =new Person(); var per2 =new Person(); console.log(Person.prototype);
在建立實際對象時候,就會運行構造函數中的代碼,並且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
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中動態原型模式。