摘要:原型對象的問題省略了為構(gòu)造函數(shù)傳遞參數(shù),導(dǎo)致了所有實例在默認情況下都取得相同的屬性值。即使有其他代碼會給這個對象添加方法或數(shù)據(jù)成員,但也不可能有別的方法訪問傳入到構(gòu)造函數(shù)中的原始數(shù)據(jù)。
創(chuàng)建對象 1.Object構(gòu)造函數(shù)
創(chuàng)建一個Object的實例,然為其添加屬性和方法(早期創(chuàng)建對象的模式)
var person = new Object(); person.name = "Nicholas"; person.age = 29; person.job = "Software Engineer"; person.sayName = function(){ alert(this.name); }2.對象字面量
var person = { name: "Nicholas"; age: 29; job: "Software Engineer"; sayName: function(){ alert(this.name); } }
前面提到了早期創(chuàng)建對象的兩種方法:Object構(gòu)造函數(shù)和對象字面量,但是這些方式有明顯的缺點:使用同一個接口創(chuàng)建很多對象,會產(chǎn)生大量的重復(fù)代碼。
3.工廠模式:function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); } return o; } var person1 = create("Nicholas", 29, "Software Engineer");
缺點:
工廠模式雖然解決了創(chuàng)建多個相似對象會有大量重復(fù)代碼的問題,但是卻沒有解決 對象識別 的問題(因為返回的都是Object類型)
4.構(gòu)造函數(shù)模式ECMAScript中的構(gòu)造函數(shù)可以用來創(chuàng)建特定類型的對象。
function Person(name, age, job){ this.name=name; this.age=age; this.job=job; this.sayName=function(){ alert(this.name); } } // 注意將Person當(dāng)做構(gòu)造函數(shù),需要使用new操作符來創(chuàng)建新對象 var person1 = new Person("xin",22,"Software Engineer"); var person2 = new Person("wu",22,"Software Engineer");
在上面的例子中,person1和person2分別保存著一個不同的實例,但是這兩個對象都有一個constructor(構(gòu)造函數(shù))屬性,該屬性執(zhí)行Person。
檢測對象類型:
利用constructor屬性:
alert(person1.constructor == Person); //true
利用instanceof操作符:
alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true
創(chuàng)建自定義的構(gòu)造函數(shù)意味著將來可以將它的事例標(biāo)識為一種特定的類型
缺點:
每個方法都要在每個實例上重新創(chuàng)建一遍(針對每個實例都會創(chuàng)建一組同樣新方法)。上例中,person1和person2中都有一個sayName的方法,但是兩個實例中的方法不是同一個Function的實例。因此不同實例上的同名函數(shù)是不相等的。
解決方法:把函數(shù)定義轉(zhuǎn)移到構(gòu)造函數(shù)外部。
function Person(name, age, job){ this.name=name; this.age=age; this.job=job; this.sayName=sayName;//sayName屬性設(shè)置為全局的sayName函數(shù) } function sayName(){ alert(this.name); } var person1 = new Person("xin",22,"Software Engineer"); var person2 = new Person("wu",22,"Software Engineer");
修改后,person1和person2對象共享了在全局作用域中定義的同一個sayName()函數(shù)。但是出現(xiàn)了新的問題:
在全局作用域中定義的函數(shù)(sayName)實際上只能被某個對象(person1 person2)調(diào)用,讓全局作用域“名不副實”;
如果對象需要定義很多方法,則需要在全局作用域中定義很多全局函數(shù),是得這個 自定義的引用類型(自定義的構(gòu)造函數(shù)) 無封裝性可言。
解決方法:原型模式
5.原型模式每個函數(shù)都有一個prototype(原型) 屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是 包含可以由特定類型的所有實例共享的屬性和方法 。
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.ptototype.sayName = function(){ alert(this.name); } var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName();//"Nicholas" //person1和person2的屬性和方法是所有實例共享的 alert(person1.sayName == person2.sayName); //true
理解原型對象
原型屬性[[Prototype]]的訪問
確定對象之間的關(guān)系 isPrototypeOf
alert(Person.prototype.isPrototypeOf(person1));//true
獲取原型對象 Object.getPrototypeOf()
alert(Object.getPrototypeOf(person1) == Person.prototype); //true alert(Object.getPrototypeOf(person1).name);//Nicholas
每當(dāng)代碼讀取某個對象的某個屬性時,都會執(zhí)行一次搜索,目標(biāo)是具有給定名字的屬性。搜索 首先從對象實例本身開始 。如果在實例中找到了具有給定名字的屬性,則返回該屬性的值。如果沒有找到,則繼續(xù)搜索指針指向的原型對象,在原型對象中查找具有給定名字的屬性。如果在原型對象中找到了額這個屬性,則返回該屬性的值。
雖然可以通過對象實例訪問保存在原型中的值,但卻不能通過對象重寫原型中的值。如果在實例中添加了一個屬性,且該屬性與實例原型中的一個屬性同名,則該屬性會屏蔽原型中的那個屬性。
可以使用hasOwnProperty()方法來檢測一個屬性是存在與實例中,還是存在與原型中。
`
person1.hasOwnProperty("name"); //false
`
原型與in操作符:多帶帶使用in操作符時,in操作符會在通過原型能夠訪問給定屬性時返回true,無論該屬性存在與實例中還是存在原型中。同時使用hasOwnProperty()方法和in操作符,就可以確定該屬性到底是存在與對象中,還是存在與原型中。
alert( !person1.hasOwnProperty(name) && name in person1); //true
更簡單的原型語法:
前面的例子中每添加一個屬性和方法就要敲一遍Person.prototype。為了減少不必要的輸入,更常見的方法是 用一個包含所有屬性和方法的對象字面量來重寫整個原型對象
function Person(){ } Person.prototype = { name: "Nicholas", age: 29, job: "Software Engineer", sayName: function(){ alert(this.name); } }
注意:
這里使用的語法,本質(zhì)上完全重寫了默認的prototype對象,因此constructor屬性也就變成了新對象的constructor屬性(指向Object構(gòu)造函數(shù)),不再指向Person函數(shù)。使用instanceof操作符還能返回正確的結(jié)果,但是通過constructor已經(jīng)無法確定對象的類型了。
var friend = new Person(); alert(friend.instanceof Person);//true alert(friend.constructor == Person);//false
如果constructor屬性很重要,可以將其設(shè)為適當(dāng)?shù)闹?/p>
//方法一,但是會使constructor屬性的[[Enumerable]]特性變?yōu)閠rue function Person(){ } Person.prototype = { constructor:Person, name:"Nicholas", age:29, job:"Software Engineer", sayName:function(){ alert(this.name); } }
function Person(){ } Person.prototype = { name:"Nicholas", job:"Software Engineer", age:29, sayName:function(){ alert(this.name); } } Object.defindProperty(Person.prototype, "constructor",{ enumerable: false, value: Person });
原生對象的原型:
所有原生類型(Object,Array,String,等等)都在其構(gòu)造函數(shù)的原型上定義了方法。
原型對象的問題:
省略了為構(gòu)造函數(shù)傳遞參數(shù),導(dǎo)致了所有實例在默認情況下都取得相同的屬性值。
原型對象的最大問題是由其共享屬性 的本質(zhì)所導(dǎo)致的:
function Person(){ } Person.prototype = { constructor: Person, name: "Nicholas", age: 29, job: "Software Engineer", friends: ["Sheldon","Court"], sayName: function(){ alert(this.name); } }; var person1 = new Person(); var person2 = new Person(); person1.friends.push("van"); alert(person1.friends); //sheldon,court,van alert(person2.friends); //sheldon,court,van alert(person1.friends === person2.friends);//true
出現(xiàn)上述問題的原因在于:person1和person2的friends屬性共享一個數(shù)組。
6.組合使用構(gòu)造函數(shù)模式和原型模式構(gòu)造函數(shù)模式用來定義實例屬性,原型模式用來定義方法和共享屬性。結(jié)果每個實例都會有自己的一份實例屬性的副本,但同時又共享著對方法的引用,最大限度的節(jié)省了內(nèi)存。
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.friends = ["sheldon","mary"]; } Person.prototype = { constructor: Person, sayName: function(){ alert(this.name); } }7.動態(tài)原型模式
結(jié)合使用構(gòu)造函數(shù)模式和原型模式是使用最為廣泛的創(chuàng)建自定義類型的方法,但是卻將屬性和方法分別定義(獨立的構(gòu)造函數(shù)和原型),使用動態(tài)原型模式可以解決這個問題,將所有信息都封裝在構(gòu)造函數(shù)中,通過在構(gòu)造函數(shù)中初始化原型、保持使用構(gòu)造函數(shù)和原型的優(yōu)點。
function Person(name, age, job){ this.name = name this.age = age this.job = job // 這段代碼只會在初次調(diào)用構(gòu)造函數(shù)時才會執(zhí)行 if(typeof this.sayName === "function"){ Person.prototype.sayName = function(){ alert(this.name) } } } var friend = new Person("xin", 29, "Softwar Engineer") friend.sayName()8.穩(wěn)妥構(gòu)造函數(shù)模式
特點:1.新創(chuàng)建對象的實例方法不引用this;2.不使用new 操作符調(diào)用構(gòu)造函數(shù)
function Person(name,age,job){ var o = new Object(); o.sayName = function(){ alert(name); } return o; }
以這種方式創(chuàng)建的對象中,除了使用sayName()方法之外,沒有其他辦法訪問name的值。
var friend = Person("Nicholas",29,"Software Engineer"); friend.sayName();
即使有其他代碼會給這個對象添加方法或數(shù)據(jù)成員,但也不可能有別的方法訪問傳入到構(gòu)造函數(shù)中的原始數(shù)據(jù)(name,job,age)。穩(wěn)妥構(gòu)造函數(shù)模式提供的這種安全性,使得它非常適合在某些安全環(huán)境中執(zhí)行。
使用穩(wěn)妥構(gòu)造函數(shù)模式創(chuàng)建的對象與構(gòu)造函數(shù)之間沒什么關(guān)系,因此instanceof操作符對這種對象沒有什么意義
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/83390.html
摘要:這種方法也存在這樣的問題如果修改了構(gòu)造函數(shù)的原型對象,之前創(chuàng)建的對象無法通過這種方式來確定類型修改構(gòu)造函數(shù)的原型對象會導(dǎo)致之前創(chuàng)建的對象無法通過這種方式判斷類型判斷對象繼承自哪些父類型使用使用 判斷對象類型的方法 使用原型對象上的constructor屬性來判斷 每個對象的原型上都有一個constructor屬性,指向了其構(gòu)造函數(shù) 注意:對象沒有constructor屬性(除非自己添加...
摘要:繼承原型鏈原型鏈?zhǔn)菍崿F(xiàn)繼承的主要方法。臨時的構(gòu)造函數(shù)將傳入的對象作為這個構(gòu)造函數(shù)的原型返回新實例以為原型創(chuàng)建一個新實例不僅屬于所有,而且也會被共享。上訴例子只調(diào)用了一次構(gòu)造函數(shù),因此避免了在上面創(chuàng)建不必要的多余的屬性。 繼承 1 原型鏈 原型鏈?zhǔn)菍崿F(xiàn)繼承的主要方法。其基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。 構(gòu)造函數(shù)、原型和實例的關(guān)系 每個構(gòu)造函數(shù)都有一個原型對...
摘要:私有變量任何在函數(shù)中定義的變量,都可以認為是私有變量,因為在不能再函數(shù)的外部訪問這些變量。我們把有權(quán)訪問私有變量和私有函數(shù)的公有方法稱為特權(quán)方法。模塊模式模塊模式是為單例創(chuàng)建私有變量和特權(quán)方法。 私有變量 任何在函數(shù)中定義的變量,都可以認為是私有變量,因為在不能再函數(shù)的外部訪問這些變量。私有變量包括函數(shù)的參數(shù)、函數(shù)中定義的變量和函數(shù)。我們把有權(quán)訪問私有變量和私有函數(shù)的公有方法稱為特權(quán)方...
摘要:首先導(dǎo)包依賴如下構(gòu)建應(yīng)用是以為中心的實例可以通過獲得其中是工廠接口任務(wù)用于創(chuàng)建配置文件將會解析配置文件在類對象中配置獲取數(shù)據(jù)源事務(wù)管理器映射器在文件下新建文件配置文件內(nèi)容如下定義別名定義數(shù)據(jù)庫信息事物管理 首先導(dǎo)包 依賴如下 mysql mysql-connector-java 8.0.15 org.m...
摘要:在中,并沒有對抽象類和接口的支持。例如,當(dāng)對象需要對象的能力時,可以有選擇地把對象的構(gòu)造器的原型指向?qū)ο螅瑥亩_到繼承的效果。本節(jié)內(nèi)容為設(shè)計模式與開發(fā)實踐第一章筆記。 動態(tài)類型語言 編程語言按數(shù)據(jù)類型大體可以分為兩類:靜態(tài)類型語言與動態(tài)類型語言。 靜態(tài)類型語言在編譯時已確定變量類型,動態(tài)類型語言的變量類型要到程序運行時,待變量被賦值后,才具有某種類型。 而JavaScript是一門典型...
閱讀 1031·2021-11-23 09:51
閱讀 2352·2021-10-08 10:22
閱讀 2583·2021-09-29 09:35
閱讀 862·2021-09-22 15:20
閱讀 2865·2019-08-30 15:53
閱讀 2417·2019-08-30 13:55
閱讀 1106·2019-08-29 17:27
閱讀 2874·2019-08-29 17:26