摘要:將構造函數的作用域賦值給新對象因此指向了新對象執(zhí)行構造函數的代碼為這個新對象添加屬性返回對象最初是用來標識對象類型的。但提到檢測對象類型,還是使用將構造函數當作函數構造函數與其他函數唯一區(qū)別。
創(chuàng)建對象
雖然Object構造函數與對象字面量都能創(chuàng)建單個對象, 但這些方式都有明顯的缺點: 使用同一個接口創(chuàng)建很多對象, 會產生大量重復代碼。
var obj = {}; //對象字面量 var obj = new Object(); //對象構造函數(對象構造器)工廠模式
這種模式抽象了對象具體創(chuàng)建的過程(類似其它語言的類)
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 = createPerson("汪淼", 50, "納米"); var person2 = createPerson("楊冬", 20, "基礎物理學");
工廠模式解決了創(chuàng)建多個對象的問題, 確沒有解決對象識別問題(如何知道一個對象的類型)因為使用該模式并沒有給出對象的類型
構造函數模式創(chuàng)建自定義構造函數意味著將來可以將它的實列類型標識為一種特定的類型。(更優(yōu)點)
這種方式定義的函數是定義在global中的
function Person (name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function () { alert (this.name); } } var person1 = new Person("汪淼", 50, "納米"); var person2 = new Person("楊冬", 20, "基礎物理學");
與工廠模式區(qū)別
沒有顯示的創(chuàng)建對象
直接將屬性和方法賦給 this 對象
沒有return語句
使用new 來調用函數,或者說發(fā)生構造函數調用時,會自動執(zhí)行下面的操作。
創(chuàng)建(或者說構造)一個全新的對象。
這個新對象會被執(zhí)行[[原型]]連接。
這個新對象會綁定到函數調用的this 。
如果函數沒有返回其他對象,那么new 表達式中的函數調用會自動返回這個新對象。
高級編程對象處的說法 1.創(chuàng)建(或者說構造)一個全新的對象。 2.將構造函數的作用域賦值給新對象(因此this指向了新對象) 3.執(zhí)行構造函數的代碼(為這個新對象添加屬性) 4.返回對象
person1.constructor == Person; person2.constructor == Person;
constructor 最初是用來標識對象類型的。但提到檢測對象類型,還是使用 instanceof
person1 instanceof Person // true person2 instanceof Person // true將構造函數當作函數
構造函數與其他函數唯一區(qū)別。調用方式的不同。 用new 操作符調用就是作為構造函數,不用則為普通函數
// 構造函數 var person = new Person("羅輯", 20, "宇宙社會學"); person.sayName(); //羅輯 // 普通函數 Person("葉文潔", 20, "基礎物理學"); window.sayName(); //葉文潔 // 在另一個對象作用域中調用 var o = new Object(); Person.call(o, "泰勒", 25, "面壁者"); //call() apply() 是會立即調用函數的 而bind() 則不會 o.sayName(); // 泰勒構造函數問題
使用構造函數的主要問題是每個方法都要在每個實例上重新創(chuàng)建一遍,創(chuàng)建多個完成相同任務的方法完全沒有必要,浪費內存空間
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = new Function("alert(this.name)"); // 等價于 // this.sayName = function () { // alert (this.name); // } }差的嘗試
function Person (name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName() { alert (this.name); } var person1 = new Person("汪淼", 50, "納米"); var person2 = new Person("楊冬", 20, "基礎物理");
sayName 放到了構造函數外部, 構造函數內部通過sayName指針指向sayName函數;
問題: 創(chuàng)建了全局函數sayName
原型模式 原型模式于是這個自定義引用類型就沒有絲毫封裝性可言
我們創(chuàng)建的每個函數都有一個 prototype(原型屬性),該屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型所有實例共享的屬性和方法。
用原型對象,可以讓所有實例共享它的屬性和方法。換句話說,不必在構造函數中定義對象實例的信息,而是可以將這些信息直接添加到原型對象中
function Person() { } Person.prototype.name = "維德"; Person.prototype.age = "24"; Person.prototype.sayName = function() { alert(this.name); } var person1 = new Person(); person1.sayName(); // 維德 var person2 = new Person(); person2.sayName(); // 維德 alert(person1.sayName == person2.sayName); //true // @todo 原型鏈圖更簡單的原型模式
function Person(){}; Person.prototype = { name: "丁怡", age: 50, job: "物流", sayName : function(){ console.log(this.name); } }; var person1 = new Person(); person1.sayName();// "丁怡" console.log(person1.constructor === Person);// false console.log(person1.constructor === Object);// true
這種語法 constructor 不再指向Person,(每創(chuàng)建一個函數,就會同時創(chuàng)建prototype, 同時這個對象也會自動獲取constructor),而該方法本質上相當于完全重寫了prototype的默認屬性,constructor 也變成了新對象的constructor屬性(指向Object構造函數),不再指向Person函數。此時盡管instanceof操作符還能返回正確的結果,但通過constructor已經無法確定對象的類型了
var friend = new Person(); friend instanceof Object; // true friend instanceof Person; // true friend constructor Person; // false friend constructor Object; // true修正 constructor 方法
function Person(){}; Person.prototype = { // 方法1:添加 constructor constructor: "Person", name: "丁怡", age: 50, job: "物流", sayName : function(){ console.log(this.name); } }; // 方法2:通過defineProperty() 添加 Object.defineProperty(Person.prototype,"constructor",{ enumerable: false, value: Person });原型 1.理解原型對象
2.原型與 in 操作符無論什么時候,只要創(chuàng)建了一個新函數,就會根據一組特定的的規(guī)則為該函數創(chuàng)建一個prototype屬性,這個屬性指向函數的原型對象。在默認情況下,所有的原型對象都會自動獲取constructor(構造函數)屬性,這個屬性包含了一個指向prototype屬性所在函數數的指針
in 會查找 原型鏈 hasOwnProperty() 則只查找實例本身
3.更簡單的原型模式function Person(){}; Person.prototype = { name: "丁怡", age: 50, job: "物流", sayName : function(){ console.log(this.name); } }; var person1 = new Person(); person1.sayName();// "丁怡" console.log(person1.constructor === Person);// false console.log(person1.constructor === Object);// true4.原型的動態(tài)性 && 重寫原型
var friend = new Person(); Person.prototype.sayHi = function() { alert("hi"); } friend.sayHi(); // hi (ok!)
重寫function原型之后
function Person() {} var friend = new Person(); Person.prototype = { constructor: Person, name: "程心", age: 21, job: "天體物理", sayName: fucntion() { alert(this.name); } }; friend.sayName(); //error 原型鏈重寫 @todo 原型鏈圖5.原生對象的原型
js 所有原生的引用類型,都是采用這種模式(Object, Array, String)
原型對象的問題原型模式問題在于引用類型值屬性會被所有的實例對象共享并修改,這也是很少有人多帶帶使用原型模式的原因
function Person(){} Person.prototype = { constructor: Person, name: "bai", age: 29, job: "Software Engineer", friend : ["shelby","Court"], sayName: function(){ console.log(this.name); } }; var person1 = new Person(); var person2 = new Person(); person1.friends.push("Van"); alert(person1.friends);//["shelby","Court","Van"]; alert(person2.friends);//["shelby","Court","Van"]; alert(person1.friends === person2.friends);//true組合使用構造函數模式和原型模式
組合使用構造函數模式和原型模式是創(chuàng)建自定義類型的最常見方式。構造函數模式用于定義實例屬性,而原型模式用于定義方法和共享的屬性,這種組合模式還支持向構造函數傳遞參數。實例對象都有自己的一份實例屬性的副本,同時又共享對方法的引用,最大限度地節(jié)省了內存。該模式是目前使用最廣泛、認同度最高的一種創(chuàng)建自定義對象的模式
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.friends = ["丁怡", "汪淼"]; } Person.prototype = { constructor: Person, sayName: function() { alert(this.name); } } var person1 = new Person("bai",29,"Software Engineer"); var person2 = new Person("hu",25,"Software Engineer"); person1.friends.push("楊冬"); alert(person1.friends);// ["丁怡", "汪淼", "楊冬"]; alert(person2.friends);// ["丁怡", "汪淼"]; alert(person1.friends === person2.friends);//false alert(person1.sayName === person2.sayName);//true動態(tài)原型模式
動態(tài)原型模式將組合模式中分開使用的構造函數和原型對象都封裝到了構造函數中,然后通過檢查方法是否被創(chuàng)建,來決定是否初始化原型對象
function Person(name, age, job) { // 屬性 this.name = name; this.age = age; this.job = job; // 方法 if(typeof this.sayName != "function") { Person.prototype.sayName = function(){ console.log(this.name); }; } } var friend = new Person("bai",29,"Software Engineer"); friend.sayName();//"bai"寄生構造函數模式
該模式的基本思想是創(chuàng)建一個函數,該函數的作用僅僅是封裝創(chuàng)建對象的代碼,然后再返回新創(chuàng)建的對象。該模式是工廠模式和構造函數模式的結合
寄生構造函數模式與構造函數模式有相同的問題,每個方法都要在每個實例上重新創(chuàng)建一遍,創(chuàng)建多個完成相同任務的方法完全沒有必要,浪費內存空間
function Person(name,age,job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ console.log(this.name); }; // o.sayName = new Function("console.log(this.name);"); return o; } var person1 = new Person("bai", 29, "software Engineer"); var person2 = new Person("hu", 25, "software Engineer"); //具有相同作用的sayName()方法在person1和person2這兩個實例中卻占用了不同的內存空間 console.log(person1.sayName === person2.sayName);//false
使用new 操作符會默認返回新對象實例,這里return 重寫了調用構造函數的時返回的值
穩(wěn)妥構造函數模式所謂穩(wěn)妥對象指沒有公共屬性,而且其方法也不引用this的對象。穩(wěn)妥對象最適合在一些安全環(huán)境中(這些環(huán)境會禁止使用this和new)或者在防止數據被其他應用程序改動時使用
穩(wěn)妥構造函數與寄生構造函數模式相似,但有兩點不同:一是新創(chuàng)建對象的實例方法不引用this;二是不使用new操作符調用構造函數
function Person(name,age,job){ //創(chuàng)建要返回的對象 var o = new Object(); //可以在這里定義私有變量和函數 //添加方法 o.sayName = function(){ console.log(name); }; //返回對象 return o; } //在穩(wěn)妥模式創(chuàng)建的對象中,除了使用sayName()方法之外,沒有其他方法訪問name的值 var friend = Person("bai",29,"Software Engineer"); friend.sayName();//"bai"
與寄生構造函數模式相似,使用穩(wěn)妥構造函數模式創(chuàng)建的對象與構造函數之間也沒有什么關系,因此instanceof操作符對這種對象也沒有什么意義
最后本文從使用Object構造函數與對象字面量創(chuàng)建一個對象開始說起,創(chuàng)建多個對象會造成代碼冗余;使用工廠模式可以解決該問題,但存在對象識別的問題;接著介紹了構造函數模式,該模式解決了對象識別的問題,但存在關于方法的重復創(chuàng)建問題;接著介紹了原型模式,該模式的特點就在于共享,但引出了引用類型值屬性會被所有的實例對象共享并修改的問題;最后,提出了構造函數和原型組合模式,構造函數模式用于定義實例屬性,而原型模式用于定義方法和共享的屬性,這種組合模式還支持向構造函數傳遞參數,該模式是目前使用最廣泛的一種模式。此外,一些模式下面還有一些解決特殊需求的拓展模式(寄生構造函數模式, 穩(wěn)妥寄生模式)
Object構造函數與對象字面量創(chuàng)建一個對象 創(chuàng)建多個對象會造成代碼冗余
使用工廠模式可以解決該問題 存在對象識別的問題
介紹了構造函數模式,該模式解決了對象識別的問題 但存在關于方法的重復創(chuàng)建問題
介紹了原型模式,該模式的特點就在于共享 但引出了引用類型值屬性會被所有的實例對象共享并修改的問題
提出了構造函數和原型組合模式,構造函數模式用于定義實例屬性,而原型模式用于定義方法和共享的屬性,這種組合模式還支持向構造函數傳遞參數,該模式是目前使用最廣泛的一種模式
一些模式下面還有一些解決特殊需求的拓展模式(寄生構造函數模式, 穩(wěn)妥寄生模式)
參考javascript面向對象系列第二篇——創(chuàng)建對象的5種模式
javascript高級編程
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88929.html
摘要:所以覺得把這個執(zhí)行的詳細過程整理一下,幫助更好的理解。類似的語法報錯的如下圖所示三預編譯階段代碼塊通過語法分析階段之后,語法都正確的下回進入預編譯階段。另開出新文章詳細分析,主要介紹執(zhí)行階段中的同步任務執(zhí)行和異步任務執(zhí)行機制事件循環(huán)。 一、概述 js是一種非常靈活的語言,理解js引擎的執(zhí)行過程對于我們學習js是非常有必要的。看了很多這方便文章,大多數是講的是事件循環(huán)(event loo...
摘要:所以覺得把這個執(zhí)行的詳細過程整理一下,幫助更好的理解。類似的語法報錯的如下圖所示三預編譯階段代碼塊通過語法分析階段之后,語法都正確的下回進入預編譯階段。另開出新文章詳細分析,主要介紹執(zhí)行階段中的同步任務執(zhí)行和異步任務執(zhí)行機制事件循環(huán)。 一、概述 js是一種非常靈活的語言,理解js引擎的執(zhí)行過程對于我們學習js是非常有必要的。看了很多這方便文章,大多數是講的是事件循環(huán)(event loo...
摘要:以下知識點是前輩師兄總結基礎語義化標簽引進了一些新的標簽,特別注意等,注意的標題結構理解瀏覽器解析的過程,理解的樹形結構,及相應理解標簽在各個瀏覽器上的默認樣式代理樣式,理解中的重置樣式表的概念理解等功能性標簽理解標簽,理解文件提交過程推薦 以下知識點是前輩師兄總結 1、HTML/HTML5基礎: 1.0、語義化H5標簽1.1、H5引進了一些新的標簽,特別注意article...
摘要:以下知識點是前輩師兄總結基礎語義化標簽引進了一些新的標簽,特別注意等,注意的標題結構理解瀏覽器解析的過程,理解的樹形結構,及相應理解標簽在各個瀏覽器上的默認樣式代理樣式,理解中的重置樣式表的概念理解等功能性標簽理解標簽,理解文件提交過程推薦 以下知識點是前輩師兄總結 1、HTML/HTML5基礎: 1.0、語義化H5標簽1.1、H5引進了一些新的標簽,特別注意article...
摘要:至此作用域鏈創(chuàng)建完畢。好了,通過深入理解作用域鏈,我們能跟好的理解的運行機制和閉包的原理。 前言 理解javascript中的作用域和作用域鏈對我們理解js這們語言。這次想深入的聊下關于js執(zhí)行的內部機制,主要討論下,作用域,作用域鏈,閉包的概念。為了更好的理解這些東西,我模擬了當一個函數執(zhí)行時,js引擎做了哪些事情--那些我們看不見的動作。 關鍵詞: 執(zhí)行環(huán)境 作用域 作用域鏈 變...
20190124問: 如何理解es6中的Proxy? 試題解析:對proxy的理解,可能會延伸到vue的雙向綁定 Proxy(代理) 定義 可以理解為為目標對象架設一層攔截,外界對該對象的訪問,都必須通過這層攔截 簡單示例: const obj = new Proxy({}, { get: (target, key, receiver) => { return JS ...
閱讀 1411·2021-10-11 11:12
閱讀 3244·2021-09-30 09:46
閱讀 1633·2021-07-28 00:14
閱讀 3132·2019-08-30 13:49
閱讀 2581·2019-08-29 11:27
閱讀 3211·2019-08-26 11:52
閱讀 598·2019-08-23 18:14
閱讀 3435·2019-08-23 16:27