對於面向對象,相信你們必定不陌生。最近看了一些關於es6面向對象的知識,正好經過這篇文章把關於面向對象的東西給串起來分享給你們。前端
不少人會鄙視我,說你這篇文章是騙騙剛入行的小朋友的吧,什麼是對象我還能不知道?罵個人吃瓜羣衆先冷靜一下,你可能對對象一無所知。vue
{ name: '李小花', sayname () { console.log(this.name) } }
這是咱們最多見的對象,這個對象是經過對象字面量形式建立的。程序員
對象的含義是無序的集合,其屬性能夠包含基本值、對象或者函數。es6
js中有兩種內置的屬性,數據屬性和訪問器屬性,這兩個屬性是隻有內部才能訪問的屬性,因此這些屬性都放在了兩對方括號中,如[[enumerable]],你們在vue中常常面試
數據屬性包含一個數據值的位置。在這個位置能夠讀取和寫入值。數據屬性有 4 個描述其行爲的特性。
[[Configurable]]:表示可否經過 delete
刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成訪問器屬性。後端
[[Enumerable]]:表示可否經過 for-in 循環返回屬性。瀏覽器
[[Writable]]:表示可否修改屬性的值。閉包
[[Value]]:包含這個屬性的值。讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,把新值保存在這個位置。這個特性的默認值爲
undefined。函數
如今有一個對象經過字面量建立性能
var person = { name: '張全蛋' }
[[Configurable]]、[[Enumerable]]、[[Writable]]屬性都會被設置爲true,[[Value]]被設置爲了‘張全蛋’。若是想修改這幾個屬性任意一個值,必須使用大名鼎鼎的Object.defineProperty()方法,爲啥說它大名鼎鼎,由於若是你接觸過vue,就知道他核型就是經過這個方法實現的。
var person = {}; Object.defineProperty(person, 'name', { writable: false, value: '張全蛋' }) Object {name: "張全蛋"}
如今的name屬性是隻讀的,若是是嚴格模式的話,
這樣作還會報錯。一樣的也適用於其餘屬性,我這裏就不一一演示了。
注意⚠️,Object.defineProperty()方法只有現代瀏覽器才支持,IE8只是部分實現。
訪問器屬性不包含數據值,它們包含一對 getter 和 setter 函數(這兩個函數都不是必須的)。在讀取訪問器屬性時,會調用
getter 函數,這個函數負責返回有效的值;在寫入訪問器屬性時,會調用 setter
並傳入新值,這個函數負責決定如何處理數據。訪問器屬性有以下 4 個特性。
[[Configurable]]:表示可否經過 delete 刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成數據屬性。
[[Enumerable]]:表示可否經過 for-in 循環返回屬性。
[[Get]]:在讀取屬性時調用的函數。默認值爲 undefined。
[[Set]]:在寫入屬性時調用的函數。默認值爲 undefined。
訪問只能經過bject.defineProperty()方法來定義。
var book = { _year: 2004, edition: 1 }; Object.defineProperty(book, 'year', { get: function() { return this._year; }, set: function(newValue) { if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } }); book.year = 2005; alert(book.edition); // 2 alert(book.year); // 2005
訪問器屬性 year 則包含一個 getter 函數和一個 setter 函數。getter 函數返回 _year 的值,setter 函數經過計算來肯定正確的版本。所以,把 year 屬性修改成 2005 會致使 _year 變成 2005,而 edition 變爲 2。這是使用訪問器屬性的常見方式,即設置一個屬性的值會致使其餘屬性發生變化。
注意⚠️,訪問器屬性只有IE9以上才支持,這就是爲何VUE只能支持到IE9的緣由。
js面向對象第一步是什麼?答:建立對象。建立對象有不少中方式,咱們最經常使用的是對象字面量來建立對象,var obj = {}
,你看我這不就建立了一個對象了嗎,我還幹嗎要繼續瞭解那些奇葩的方法呢?這麼想的人活該單身,多掌握些找對象只有好處沒有壞處哈。正經的,高階上有這麼一句話,使用對象字面量建立單個對象,有個明顯的缺點,使用同一個接口建立不少對象,會產生大量重複的代碼。爲了解決這個問題,咱們須要瞭解下面?這些方式。
工廠模式很簡單,貼上一段代碼。
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("鐵蛋", 20, '工頭') var person2 = createPerson("李四", 30, '挖掘機駕駛員')
工廠模式的優勢沒必要多說,若是我想建立兩個對象,上面一樣有name、age、job屬性,這樣就省去了建立包含一樣屬性多個對象的麻煩,可是卻沒有解決對象識別的問題。
有人會問,對象識別是什麼鬼。咱們建立對象是爲了模仿類的概念,這裏的person1,person2應該都屬於「人」一類,可是顯然咱們如今沒辦法將他們歸爲一類,因此這個時候逼格更高的方法出現了。
function Person (name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function () { alert(this.name) } } var person1 = new Person("鐵蛋", 20, '工頭') var person2 = new Person("李四", 30, '挖掘機駕駛員')
這裏有個顯然很突出的地方,就是這個Person的P是大寫的,其實大寫不是必須的,聽說這種習慣是不少後端程序員轉前端帶過來的。構造函數模式跟工廠模式不同的地方還在於,沒有用new Object顯式地建立對象,一樣沒有return語句。
那咱們在new完一個構造函數,實則產生一個實例,咱們new一個構造函數,會經歷如下神奇的四步。
建立對象 將this指向這個新對象 爲這個對象添加屬性 返回這個對象
person一、person2 是咱們經過 new Person這個構造函數獲得的,因此這兩個的構造函數都是Person,constructor(構造函數)屬性就都是Person,我之前一直都不能理解constructor是什麼東西,如今才理解原來constructor的中文翻譯就是構造函數?,也難怪我英文最熟的一句就是"hello kugou"了。咱們能夠經過使用instanceof操做符來檢測對象的類型。
let arr = new Array(2) arr instanceof Array // true arr instanceof Object // true
構造函數優於工廠模式也是在於它能夠經過instanceof辨識出一類的對象。
接下來你們看一段通常沒品的面試官會考的問題
this.name = "張全蛋" function Person (name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function () { alert(this.name) } } var person1 = new Person("鐵蛋", 20, '工頭') var person2 = Person("李小花", 30, "廠花") person1.sayName() // 鐵蛋 person2.sayName() // 報錯
咱們首先要肯定一個概念,構造函數也是函數,若是不用new 的方式來調用它,它跟普通函數沒有半毛錢的區別,咱們知道在函數的做用域是window,因此this指向的是window,因此這段代碼person2對象this就是window,window沒有sayName屬性,因此會報錯。若是經過的是new方式調用的話,咱們上面也講了,爲將this賦值給這個對象,因此this就是person1這個實例。那麼構造函數是否是沒有缺點呢?顯然是不對的,由於我已經這麼問了。構造函數的缺點,每一個方法都要在實例上從新建立一遍,js中函數也是對象,定義函數就是實例化對象
function Person (name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = new Function () { alert(this.name) } }
每次new一個function就會多一次標識符解析,標識符(一般指命名)的解析是有代價的,實際上沒有那種計算機操做能夠不產生性能開銷。在執行環境的做用域鏈(扯到做用域鏈就必定會扯到閉包問題,之後有空再仔細聊聊閉包)中,一個標識符所在的位置越深,它的讀寫速度也就越慢。也就是說函數中讀寫局部變量老是最快的,而讀寫全局變量老是最慢的。由於全局變量老是在執行環境做用域的末端。其實咱們能夠將函數移出來當全局函數來處理,但那樣會形成全局函數污染,這裏就很少作介紹。