摘要:把方法移動(dòng)到構(gòu)造函數(shù)外部把方法移至外面,這樣每次實(shí)例化內(nèi)部的只是全局的引用,這樣避免了重復(fù)。構(gòu)造函數(shù)什么體內(nèi)什么都沒(méi)有,如果有叫做實(shí)例方法,實(shí)力屬性缺點(diǎn)重復(fù)敲,造成大量的重復(fù)輸入。
從對(duì)象聲明開(kāi)始一步步介紹
1.普通對(duì)象聲明首先創(chuàng)建自定義對(duì)象的最簡(jiǎn)單方式就是創(chuàng)建一個(gè)Object的實(shí)例,然后在為他們添加屬性和方法,如下所示:
var person = new Object(); //創(chuàng)建對(duì)象 person.name = "Nicholas"; //添加屬性 person.age = 29; person.job = "teacher"; person.sayName = function(){ //添加方法 return this.name };
this的含義:
this表示當(dāng)前作用域下的對(duì)象;
this表示new Object()實(shí)例化出來(lái)的那個(gè)對(duì)象;
this要放在一個(gè)作用域下,比如person.sayName()是person下的方法,可用this表示方法本身。
缺點(diǎn):要?jiǎng)?chuàng)建一個(gè)類似的對(duì)象會(huì)產(chǎn)生大量的代碼。
為了解決多個(gè)類似聲明的問(wèn)題,用一種工廠模式,這種方法是為了解決實(shí)例化對(duì)象產(chǎn)生大量重復(fù)的代碼。
2.工廠模式用函數(shù)來(lái)封裝以特定接口創(chuàng)建對(duì)象的細(xì)節(jié)。
function createPerson(name,age,job){ //創(chuàng)建對(duì)象 var obj = new Object(); //添加屬性 obj.name = name; obj.age = age; obj.job = job; obj.sayName = function(){ //添加方法 return this.name }; return obj; //返回對(duì)象引用 } var person1 = createPerson("Zhangsan",29,"Teacher"); //實(shí)例化第一個(gè)對(duì)象 var person2 = createPerson("Lisi",34,"Doctor"); //實(shí)例化第二個(gè)對(duì)象 console.log(person2 instanceof Object) //true
this的含義:
1.this是new Object(),實(shí)例化出來(lái)的那個(gè)對(duì)象;
2.this要放在一個(gè)作用域下,比如obj.sayName(){},這是obj作用域下的的方法,可以用this來(lái)表示obj本身。
缺點(diǎn):集中實(shí)例化函數(shù),解決了大量重復(fù)的代碼;從上面例子我們可以看出sayName是共有屬性,而我們每實(shí)例化一個(gè)函數(shù)都會(huì)創(chuàng)建sayName,這也造成了重復(fù)。
3.構(gòu)造函數(shù)模式構(gòu)造函數(shù)可用來(lái)創(chuàng)建特定類型的對(duì)象,類似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,因?yàn)檫@里person1是從屬于Person alert(person1.sayName() == person2.sayName()); //true,構(gòu)造函數(shù)的方法的值是想等的 alert(person1.sayName == person2.sayName); //false,比較的是引用地址
我們使用new操作符,到底是在做什么
不用創(chuàng)建臨時(shí)對(duì)象,因?yàn)?new 會(huì)幫你做(你使用「this」就可以訪問(wèn)到臨時(shí)對(duì)象);
不用綁定原型,因?yàn)?new 會(huì)幫你做(new為了知道原型在哪,所以指定原型的名字為 prototype);
不用 return 臨時(shí)對(duì)象,因?yàn)?new 會(huì)幫你做;
不要給原型想名字了,因?yàn)?new 指定名字為 prototype。
persen1 和 person2 的 constructor 屬性都指向 Person
缺點(diǎn):每次實(shí)例化 Person,共有屬性 sayName 都會(huì)重復(fù)創(chuàng)建,和工廠模式問(wèn)題一樣。
3.1把方法移動(dòng)到構(gòu)造函數(shù)外部把 sayName 方法移至 Person 外面,這樣每次實(shí)例化 Person 內(nèi)部的 sayName 只是全局 sayName 的引用,這樣避免了重復(fù)。
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ //把構(gòu)造函數(shù)內(nèi)部的方法通過(guò)全局來(lái)實(shí)現(xiàn),引用地址一致 return this.name } var person1 = new Person("Zhangsan",29,"Teacher"); var person2 = new Person("Lisi",34,"Doctor");
缺點(diǎn):
全局 sayName 函數(shù)和 Person 之間聯(lián)系不緊密,如果它們中間有很多代碼,sayName 就不知道是干嘛用的了;
如果方法很多,每個(gè)都是全局函數(shù),就沒(méi)封裝可言了;
用全局函數(shù)很容易覆蓋全局變量。
4.原型模式使用原型對(duì)象的好處是可以讓所有對(duì)象實(shí)例共享它所包含的屬性和方法。
如果是實(shí)例方法,不同的實(shí)例化,它們的方法和地址是不一樣的,是唯一的;
如果是原型方法,那它們的地址是共享的,大家都一樣。
function Person(){} //構(gòu)造函數(shù)什么體內(nèi)什么都沒(méi)有,如果有叫做實(shí)例方法,實(shí)力屬性 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
缺點(diǎn):重復(fù)敲Person.prototype,造成大量的重復(fù)輸入。
4.1字面量方式創(chuàng)建原型function Person(){}//使用字面量的方式創(chuàng)建原型對(duì)象,這里的`{}`就是對(duì)象,是`Object`,`new Object`相當(dāng)于`{}` Person.prototype = { constructor:Person, //強(qiáng)行指向?qū)嵗? name: "Zhangsan", age: 29, job: "Teacher", sayName: function(){ return this.name } }; var person = new Person();
注意:
實(shí)例化后重寫(xiě)原型對(duì)象,會(huì)切斷現(xiàn)有實(shí)例和新原型之間的聯(lián)系
不能重寫(xiě)原型中的屬性,如 person.name = "Lisi",它會(huì)變成 person 的實(shí)例屬性。
缺點(diǎn):constructor不在指向?qū)嵗?,而?huì)指向Object。新對(duì)象的constructor重寫(xiě)Person原來(lái)的constructor,因此會(huì)指向新對(duì)象。
解決方法:在原型內(nèi)部,可以設(shè)置constructor強(qiáng)行執(zhí)行實(shí)例。
構(gòu)造函數(shù)模式用于定義實(shí)力屬性,原型模式用于定義方法和共享屬性
function Person(name,age,job){ //保持獨(dú)立的使用構(gòu)造函數(shù) 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",引用類型沒(méi)有使用原型,所以沒(méi)有共享 alert(person1.friends == person2.friends); //false alert(person1.sayName == person2.sayName); //true
注意:實(shí)例化的私有屬性是自有的
5.動(dòng)態(tài)原型模式動(dòng)態(tài)原型模式,把所有信息都封裝在了構(gòu)造函數(shù)中。
function Person(name,age,job){ //保持獨(dú)立的使用構(gòu)造函數(shù) this.name = name; this.age = age; this.job = job; this.friends = ["Xiaoming","Fangfang"]; if(typeof this.sayName != "function"){ //僅在第一次時(shí)初始化 Person.prototype.sayName = function(){ console.log(this.name); }; } }
原型的初始化,只要第1次初始化,就可以了,沒(méi)必要每次構(gòu)造函數(shù)實(shí)例化的時(shí)候都初始化,可以將原型封裝在函數(shù)里。
注意:使用動(dòng)態(tài)原型模式時(shí),不能使用對(duì)象字面量重寫(xiě)原型。如果在已經(jīng)創(chuàng)建了實(shí)例的情況下重寫(xiě)原型,那么就會(huì)切斷現(xiàn)有實(shí)例與新原型之間的聯(lián)系。
__proto__:是實(shí)例化后的原型屬性
prototype:是 JS 內(nèi)部提供的原型屬性
上面例子中
person1.__proto__ === Person.prototype
person1.__proto__.__proto__ === Object.prototype
之前寫(xiě)過(guò)一篇文章闡述它們之間的不同:前端學(xué)習(xí)筆記之原型——一張圖說(shuō)明prototype和__proto__的區(qū)別
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94546.html
摘要:當(dāng)構(gòu)造函數(shù)沒(méi)有顯式地返回一個(gè)值的時(shí)候,對(duì)其執(zhí)行操作之后,會(huì)返回這個(gè)構(gòu)造函數(shù)實(shí)例化之后的對(duì)象。 JavaScript里實(shí)例化一個(gè)對(duì)象的時(shí)候,我們常用的方法就是使用new操作符。 var Foo = function(x, y) { this.x = x this.y = y } var foo = new Foo(1, 2) // Foo?{x: 1, y: 2} 那么...
摘要:既然構(gòu)造函數(shù)有屬于自己的原型對(duì)象,那么我們應(yīng)該能讓另一個(gè)構(gòu)造函數(shù)來(lái)繼承他的原型對(duì)象咯我們?cè)跇?gòu)造函數(shù)內(nèi)部執(zhí)行了函數(shù)并改變了函數(shù)內(nèi)部的指向其實(shí)這個(gè)指向的是實(shí)例化之后的對(duì)象。 我們?cè)谟懀╩ian)論(shi)JavaScript這門(mén)語(yǔ)言時(shí),總是繞不過(guò)的一個(gè)話題就是繼承與原型鏈。那么繼承與原型鏈到底是什么呢? 我很喜歡的一個(gè)聊天模式是:我不能說(shuō)XX是什么,我只能說(shuō)XX像什么。也就是說(shuō)我不直接跟...
摘要:直到內(nèi)部的全部循環(huán)結(jié)束為止,才進(jìn)入下一個(gè)元素,當(dāng)循環(huán)結(jié)束時(shí),內(nèi)部的節(jié)點(diǎn)都已經(jīng)生成好了。 自己實(shí)現(xiàn)虛擬 DOM 從 HTML 中提煉數(shù)據(jù)結(jié)構(gòu) 先來(lái)看下我們的 HTML 傅雷家書(shū) 讀家書(shū),想付雷 從 HTML 中我們可以抽離出它的數(shù)據(jù)結(jié)構(gòu): 首先頁(yè)面中只需要一個(gè)根節(jié)點(diǎn)root,定義為:nodesDate數(shù)組 root內(nèi)有兩個(gè)子元素h1和span,數(shù)組有兩項(xiàng),每項(xiàng)為內(nèi)...
閱讀 723·2021-10-14 09:42
閱讀 1976·2021-09-22 15:04
閱讀 1585·2019-08-30 12:44
閱讀 2146·2019-08-29 13:29
閱讀 2739·2019-08-29 12:51
閱讀 556·2019-08-26 18:18
閱讀 707·2019-08-26 13:43
閱讀 2818·2019-08-26 13:38