你們好,我是蘇日儷格,本文是面向對象的第二部分,純屬我的理解,有哪裏不對的地方請在評論區指出,你們一塊兒學習共同進步。前端
在面試中,常常會被問到建立對象都有哪些方式,在建立單個對象的時候一般就用對象字面量,多個對象就用工廠模式、構造函數、原型模式和構造函數原型的混合模式
下面來逐個介紹一下:面試
栗子以下:函數
let Person = { name: '蘇日儷格', age: 24, job: '前端開發' } console.log(Person) // {name: "蘇日儷格", age: 24, job: "前端開發"}
優勢:通俗易懂,人人都會的一種簡單的方法
缺點:只適用於建立單個對象,用同一個接口建立多個對象的話,就會有不少的冗餘代碼,爲了解決這個缺點,咱們使用工廠模式學習
栗子以下:測試
function createPerson(name, age, job){ let obj = new Object(); obj.name = name; obj.age = age; obj.job = job; obj.show = function(){ console.log(`姓名:${obj.name}, 年齡:${obj.age}, 工做:${obj.job}`); } return obj; } let person1 = createPerson('蘇日儷格', 24, '前端開發'); person1.show(); // 姓名:蘇日儷格, 年齡:24, 工做:前端開發 let person2 = createPerson('趙雲', 27, '救阿斗'); person2.show(); // 姓名:趙雲, 年齡:27, 工做:救阿斗
優勢:封裝了一個函數解決了代碼冗餘的問題
缺點:沒法明確建立的對象的類型,爲了解決這個缺點,咱們使用構造函數this
栗子以下:prototype
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.show = function(){ console.log(`姓名:${this.name}, 年齡:${this.age}, 工做:${this.job}`); } } let person1 = new Person('蘇日儷格', 24, '前端開發'); person1.show(); // 姓名:蘇日儷格, 年齡:24, 工做:前端開發 let person2 = new Person('趙雲', 27, '救阿斗'); person2.show(); // 姓名:趙雲, 年齡:27, 工做:救阿斗
和工廠模式的不一樣之處:code
優勢:因爲兩個實例共享了show這個全局的方法,就解決了兩個函數作一件事的問題
缺點:若是定義了多個全局的函數,那麼這個自定義的引用類型就絲毫滅有封裝性可言了,並且每一個方法都要在每一個實例上從新建立一遍,爲了解決這個缺點,咱們使用原型模式對象
栗子以下:blog
function Person(){} Person.prototype.name = '蘇日儷格'; Person.prototype.age = 24; Person.prototype.job = '前端開發'; Person.prototype.show = function(){ console.log(`姓名:${this.name}, 年齡:${this.age}, 工做:${this.job}`); } let person1 = new Person(); person1.show(); // 姓名:蘇日儷格, 年齡:24, 工做:前端開發 let person2 = new Person(); person2.show(); // 姓名:蘇日儷格, 年齡:24, 工做:前端開發 person2.name = '趙雲'; person2.age = 27; person2.job = '救阿斗'; person2.show(); // 姓名:趙雲, 年齡:27, 工做:救阿斗
優勢:可讓全部對象的實例共享它所包含的屬性和方法,不用再從實例中從新定義信息,直接將信息放在原型對象中
缺點:顯而易見,全部實例都是共享的屬性,可是實例通常會有本身單獨的屬性的,這種方法通常不用,那麼最後一種就是結合了前面全部的缺點的一種方式,也是最讓碼農們認同的
這個時候有些人就想了,重複寫那麼多代碼,咱們能夠簡寫成這樣的啊:
function Person(){} Person.prototype = { name: '蘇日儷格', age: 24, job: '前端開發', show: function(){ console.log(`姓名:${this.name}, 年齡:${this.age}, 工做:${this.job}`); } } let person1 = new Person(); person1.show(); // 姓名:蘇日儷格, 年齡:24, 工做:前端開發 let person2 = new Person(); person2.show(); // 姓名:蘇日儷格, 年齡:24, 工做:前端開發 person2.name = '趙雲'; person2.age = 27; person2.job = '救阿斗'; person2.show(); // 姓名:趙雲, 年齡:27, 工做:救阿斗
上面折中寫法確實清晰了許多,可是這個是在原型模式的狀況下,把構造函數的原型等於了以對象字面量的形式建立的對象,這個時候constructor屬性就再也不指向Person了,爲了證明這一點來看一個小東西instanceof
instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性。
這句話是什麼意思呢?
來看一個語法:object instanceof constructor
就是用instanceof來檢測一個構造函數的prototype屬性所指向的對象是否存在另一個要檢測對象的原型鏈上
字面理解: constructor.prototype 是否存在於object 的原型鏈上
在上面加上這四行代碼:
console.log(person1 instanceof Person) // true console.log(person1 instanceof Object) // true console.log(person1.constructor == Person) // false console.log(person1.constructor == Object) // true
很明顯,咱們要的效果出來了,實例的構造函數已經由Person指向了Object,這個時候須要在代碼里加上constructor的指向
Person.prototype = { constructor: Person, name: '蘇日儷格', age: 24, job: '前端開發', show: function(){ console.log(`姓名:${this.name}, 年齡:${this.age}, 工做:${this.job}`); } }
栗子以下:
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; } Person.prototype = { constructor: Person, show: function(){ console.log(`姓名:${this.name}, 年齡:${this.age}, 工做:${this.job}`); } }; let person1 = new Person('蘇日儷格', 24, '前端開發'); person1.show(); let person2 = new Person('趙雲', 27, '救阿斗'); person2.show(); console.log(person1.name == person2.name) // false console.log(person1.show == person2.show) // true
作了個實驗,看看兩個實例究竟是怎樣的,共享的方法獲得了驗證,二者的屬性並非共享的,由於在建立實例的同時,系統開闢了單獨的內存給它,每一個實例也都會給本身的屬性建立一個副本,因此他們以前是互不影響的
優勢:能夠經過構造函數模式來定義實例所須要的屬性,用原型來定義實例共享的屬性和方法(謹記:自己自帶的屬性的權重始終高於原型定義的屬性),分工明確
對象建立好了,關鍵的地方來了,在對象繼承以前先要搞明白__proto__和prototype的關係,這個懂了,就能夠玩原型鏈繼承了^^
本文的全部內容均是一字一句敲上去的,但願你們閱讀完本文能夠有所收穫,由於能力有限,掌握的知識也是不夠全面,歡迎你們提出來一塊兒分享!謝謝O(∩∩)O~