今天遇到一個這樣的功能:前端
var o = obj (4, {name: 'xu', age: 21}) // 返回了一個能容納4條數據的對象,初始數據爲name:'xu'和age: 21
o.name // xu o.name //undefined o.size //1
那麼問題來了,如何設置屬性在使用一次後自動消除呢,通過思考,想到了,get和set方法,get和set又是什麼呢,以下:es6
var o = { _id: 11, get id () { return this._id + '_get' }, set id (value) { this._id = value + '_set' } } console.log(o.id) // 11_get o.id = '666' console.log(o.id) // 666_set_get
js中引用屬性的值視爲get,給屬性賦值視爲set,get和set方法能夠在獲取/設置屬性值時進行必定的操做。緩存
本文中所用到了get和set方法,不過並非上述例子那樣簡單的在對象中書寫,咱們藉助了本文的主角Object.defineProperty方法。函數
Object.defineProperty是es5新加的給對象屬性設置描述符的方法,使用方法以下:學習
Object.defineProperty(obj, prop, descriptor) // 對象、屬性、描述符
基本的描述符有3個:this
下面分別舉個簡單的例子來講明其用法es5
顧名思義,設置屬性是否爲可寫,若是是false,則屬性以後的賦值操做無效spa
var o = { name: 'xu' } Object.defineProperty(o, 'name', { writeable:false }) o.name = 'lee' console.log(o.name) //xu
屬性是否可配置,設置爲false後,該屬性不可被刪除,也不可再更改成可配置的,可是能夠從可寫改成不可寫code
var o = { name: 'xu' } Object.defineProperty(o, 'name', { configurable:false }) o.name = 'lee' console.log(o.name) // lee 不可配置可寫 delete o.name console.log(o.name) //lee 刪除失敗 Object.defineProperty(o, 'name', { writable: false }) o.name ='li' console.log(o.name) // lee 不可配置不可寫
屬性是否可枚舉,若是是false,則屬性不可枚舉,不可枚舉屬性對 for ... in語句和Ojbect.keys是不可見的。對象
var o = { name: 'xu', age: 21 } Object.defineProperty(o, 'name', { enumerable: false }) console.log(Object.keys(o)) //["age"]
分界線----------------------------------------------------------------------------
除了上面三個屬性,defineProperty方法內部還能夠定義屬性的value值, get/set方法,那麼本章則用到了使用Object.defineProperty方法定義屬性的get/set值。
思路:本題主要圍繞着屬性的get/set作進一步處理,要求引用一次屬性值後,屬性值消失(undefined),那麼就須要在get方法中作文章,因此咱們先制定一個定義屬性描述符的方法,我把它定義成這樣:
var _defineProperty = function (ret, key) { Object.defineProperty(ret, key, { set: function (value) { // 針對 o.key = value 的set方法 if (!datas[key]) { ret.size++ } datas[key] = value }, get: function () { // 獲取當前數據,若是當前數據有值,返回值並將當前屬性值設置爲undefined var res = undefined if (typeof datas[key] !== undefined) { res = datas[key] ret.size-- datas[key] = undefined } return res } }) }
本題的主要部分就在這裏,這段代碼利用的屬性的get和set方法,針對題目的要求,作出了這個功能函數。注意:返回的對象ret並無保存數據,他只是經過set和get方法對datas緩存對象中的數據進行的設置和讀取。
datas對象是這樣的,他利用的es6中的Object.assign方法,把init拷貝了一份做初始化
// 緩存數據 var datas = Object.assign({}, init)
整個代碼就在這裏,也很簡單,寫的也比較亂。若是有問題,請指出。
function FirstVaild (overLength, init) { // 定義最終返回對象,初始兩個值,一個對象總容量,一個是當前長度 var ret = { overLength: overLength, size: Math.min(Object.keys(init).length, overLength) //若是傳入初始數據條數大於容量,取容量值 } // 緩存數據 var datas = Object.assign({}, init) // 定義屬性的函數 var _defineProperty = function (ret, key) { Object.defineProperty(ret, key, { set: function (value) { // 針對 o.key = value 的set方法 if (!datas[key]) { ret.size++ } datas[key] = value }, get: function () { // 獲取當前數據,若是當前數據有值,返回值並將當前屬性值設置爲undefined var res = undefined if (typeof datas[key] !== undefined) { res = datas[key] ret.size-- datas[key] = undefined } return res } }) } // 將dirty初始化false,並定義每一個屬性的get/set Object.keys(init).slice(0,ret.size).map(function (key) { _defineProperty(ret, key) }) Object.assign(ret, { cache: function (key ,value) { if (this.size >= this.overLength) { throw '內存已滿,請擴展容量' } // 屬性不存在,定義他,而且長度+1, 屬性存在但值不存在,長度+1, if (!(key in datas)) { _defineProperty(this, key) this.size++ } else if (!datas[key]) { this.size++ } // 不論怎樣,新值覆蓋舊值 datas[key] = value return this }, // 刪除屬性直接把datas中的屬性設置爲undefined delete: function (key) { datas[key] = undefined this.size-- return this } }) return ret }
本章就到這裏,博主爲一介前端菜鳥,並無多少知識,try my best,寫點基礎知識,分享給正在學習前端的新人們。