摘要:把方法移動到構造函數外部把方法移至外面,這樣每次實例化內部的只是全局的引用,這樣避免了重復。構造函數什么體內什么都沒有,如果有叫做實例方法,實力屬性缺點重復敲,造成大量的重復輸入。
從對象聲明開始一步步介紹
1.普通對象聲明首先創建自定義對象的最簡單方式就是創建一個Object的實例,然后在為他們添加屬性和方法,如下所示:
var person = new Object(); //創建對象 person.name = "Nicholas"; //添加屬性 person.age = 29; person.job = "teacher"; person.sayName = function(){ //添加方法 return this.name };
this的含義:
this表示當前作用域下的對象;
this表示new Object()實例化出來的那個對象;
this要放在一個作用域下,比如person.sayName()是person下的方法,可用this表示方法本身。
缺點:要創建一個類似的對象會產生大量的代碼。
為了解決多個類似聲明的問題,用一種工廠模式,這種方法是為了解決實例化對象產生大量重復的代碼。
2.工廠模式用函數來封裝以特定接口創建對象的細節。
function createPerson(name,age,job){ //創建對象 var obj = new Object(); //添加屬性 obj.name = name; obj.age = age; obj.job = job; obj.sayName = function(){ //添加方法 return this.name }; return obj; //返回對象引用 } var person1 = createPerson("Zhangsan",29,"Teacher"); //實例化第一個對象 var person2 = createPerson("Lisi",34,"Doctor"); //實例化第二個對象 console.log(person2 instanceof Object) //true
this的含義:
1.this是new Object(),實例化出來的那個對象;
2.this要放在一個作用域下,比如obj.sayName(){},這是obj作用域下的的方法,可以用this來表示obj本身。
缺點:集中實例化函數,解決了大量重復的代碼;從上面例子我們可以看出sayName是共有屬性,而我們每實例化一個函數都會創建sayName,這也造成了重復。
3.構造函數模式構造函數可用來創建特定類型的對象,類似Object類型。
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ return this.name }; } function Person2(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ return this.name }; } var person1 = new Person("Zhangsan",29,"Teacher"); var person2 = new Person("Lisi",34,"Doctor"); var person3 = new Person2("Wangwu",34,"Police"); alert(person1 instanceof Person); //true,person1從屬于Person alert(person2 instanceof Person); //true,person2從屬于Person alert(person3 instanceof Person2); //true,person3從屬于Person2 alert(person1 instanceof Person2); //false,因為這里person1是從屬于Person alert(person1.sayName() == person2.sayName()); //true,構造函數的方法的值是想等的 alert(person1.sayName == person2.sayName); //false,比較的是引用地址
我們使用new操作符,到底是在做什么
不用創建臨時對象,因為 new 會幫你做(你使用「this」就可以訪問到臨時對象);
不用綁定原型,因為 new 會幫你做(new為了知道原型在哪,所以指定原型的名字為 prototype);
不用 return 臨時對象,因為 new 會幫你做;
不要給原型想名字了,因為 new 指定名字為 prototype。
persen1 和 person2 的 constructor 屬性都指向 Person
缺點:每次實例化 Person,共有屬性 sayName 都會重復創建,和工廠模式問題一樣。
3.1把方法移動到構造函數外部把 sayName 方法移至 Person 外面,這樣每次實例化 Person 內部的 sayName 只是全局 sayName 的引用,這樣避免了重復。
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ //把構造函數內部的方法通過全局來實現,引用地址一致 return this.name } var person1 = new Person("Zhangsan",29,"Teacher"); var person2 = new Person("Lisi",34,"Doctor");
缺點:
全局 sayName 函數和 Person 之間聯系不緊密,如果它們中間有很多代碼,sayName 就不知道是干嘛用的了;
如果方法很多,每個都是全局函數,就沒封裝可言了;
用全局函數很容易覆蓋全局變量。
4.原型模式使用原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法。
如果是實例方法,不同的實例化,它們的方法和地址是不一樣的,是唯一的;
如果是原型方法,那它們的地址是共享的,大家都一樣。
function Person(){} //構造函數什么體內什么都沒有,如果有叫做實例方法,實力屬性 Person.prototype.name = "Zhangsan"; Person.prototype.age = 29; Person.prototype.job = "Teacher"; Person.prototype.sayName = function(){ return this.name }; var person1 = new Person(); person.sayName() //Zhangsan var person2 = new Person(); person.sayName() //Zhangsan alert(person1.sayName === person2.sayName); //true
缺點:重復敲Person.prototype,造成大量的重復輸入。
4.1字面量方式創建原型function Person(){}//使用字面量的方式創建原型對象,這里的`{}`就是對象,是`Object`,`new Object`相當于`{}` Person.prototype = { constructor:Person, //強行指向實例 name: "Zhangsan", age: 29, job: "Teacher", sayName: function(){ return this.name } }; var person = new Person();
注意:
實例化后重寫原型對象,會切斷現有實例和新原型之間的聯系
不能重寫原型中的屬性,如 person.name = "Lisi",它會變成 person 的實例屬性。
缺點:constructor不在指向實例,而會指向Object。新對象的constructor重寫Person原來的constructor,因此會指向新對象。
解決方法:在原型內部,可以設置constructor強行執行實例。
構造函數模式用于定義實力屬性,原型模式用于定義方法和共享屬性
function Person(name,age,job){ //保持獨立的使用構造函數 this.name = name; this.age = age; this.job = job; this.friends = ["Xiaoming","Fangfang"]; } Person.prototype = { //保存共享的使用原型 constructor: Person, sayName: function(){ return this.name } } var person1 = new Person("Zhangsan",29,"Teacher"); var person2 = new Person("Wangwu",34,"Doctor"); person1.friends.push("Xiaohong"); alert(person1.friends); //"Xiaoming,Fangfang,Xiaohong" alert(person2.friends); //"Xiaoming,Fangfang",引用類型沒有使用原型,所以沒有共享 alert(person1.friends == person2.friends); //false alert(person1.sayName == person2.sayName); //true
注意:實例化的私有屬性是自有的
5.動態原型模式動態原型模式,把所有信息都封裝在了構造函數中。
function Person(name,age,job){ //保持獨立的使用構造函數 this.name = name; this.age = age; this.job = job; this.friends = ["Xiaoming","Fangfang"]; if(typeof this.sayName != "function"){ //僅在第一次時初始化 Person.prototype.sayName = function(){ console.log(this.name); }; } }
原型的初始化,只要第1次初始化,就可以了,沒必要每次構造函數實例化的時候都初始化,可以將原型封裝在函數里。
注意:使用動態原型模式時,不能使用對象字面量重寫原型。如果在已經創建了實例的情況下重寫原型,那么就會切斷現有實例與新原型之間的聯系。
__proto__:是實例化后的原型屬性
prototype:是 JS 內部提供的原型屬性
上面例子中
person1.__proto__ === Person.prototype
person1.__proto__.__proto__ === Object.prototype
之前寫過一篇文章闡述它們之間的不同:前端學習筆記之原型——一張圖說明prototype和__proto__的區別
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94546.html
摘要:當構造函數沒有顯式地返回一個值的時候,對其執行操作之后,會返回這個構造函數實例化之后的對象。 JavaScript里實例化一個對象的時候,我們常用的方法就是使用new操作符。 var Foo = function(x, y) { this.x = x this.y = y } var foo = new Foo(1, 2) // Foo?{x: 1, y: 2} 那么...
摘要:直到內部的全部循環結束為止,才進入下一個元素,當循環結束時,內部的節點都已經生成好了。 自己實現虛擬 DOM 從 HTML 中提煉數據結構 先來看下我們的 HTML 傅雷家書 讀家書,想付雷 從 HTML 中我們可以抽離出它的數據結構: 首先頁面中只需要一個根節點root,定義為:nodesDate數組 root內有兩個子元素h1和span,數組有兩項,每項為內...
閱讀 712·2021-10-14 09:42
閱讀 1966·2021-09-22 15:04
閱讀 1571·2019-08-30 12:44
閱讀 2134·2019-08-29 13:29
閱讀 2730·2019-08-29 12:51
閱讀 542·2019-08-26 18:18
閱讀 698·2019-08-26 13:43
閱讀 2803·2019-08-26 13:38