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