JS基礎——Object.defineProperty

Object.defineProperty()方法能夠直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。html

/*
* obj 要定義屬性或修改屬性的目標對象。
* prop 屬性名稱
* descriptior 屬性描述符
*/
Object.defineProperty(obj, prop, descriptor)

屬性描述符

  • configurable 對象是否可經過Object.defineProperty修改,默認false
  • enumerable 可否枚舉(for..in 或 Object.keys),默認false
  • writable 只有爲true才能經過賦值來修改值,默認false
  • value 屬性的值,默認undefined
  • get 當訪問該屬性時,該方法會被執行,默認undefined
  • set 當屬性值修改時,觸發執行該方法。該方法將接受惟一參數,即該屬性新的參數值。默認undefined

(value或writable)和(get或set)不能同時存在vue

var a = {};
Object.defineProperty(a,'name',{configurable : false})
Object.defineProperty(a,'name',{value : 'xuriliang'})  //會拋出異常,若是configurable爲true則不會
a.name = 'rlxu' // a得值不會發生改變,由於writable默認爲false
Object.keys(a)  //沒有獲取到name,由於enumerable默認爲false

定義屬性

經過賦值操做添加的普通屬性是可枚舉的,可以在屬性枚舉期間呈現出來(for...in 或 Object.keys 方法), 這些屬性的值能夠被改變,也能夠被刪除。這個方法容許修改默認的額外選項(或配置)。默認狀況下,使用 Object.defineProperty() 添加的屬性值是不可修改的。ide

var obj = {};
Object.defineProperty(obj,'name',{
    configurable : true,
    writable : true,
    enumerable : true,
    value : 'xuriliang'
})
Object.keys(obj)  //enumerable爲true,可枚舉
obj.name = 'rlxu'; //writable爲true,可賦值

修改現有屬性

僅當屬性描述configurable爲true時,才能夠修改屬性。(經過賦值操做添加的普通屬性configurable、enumerable、writable默認爲true)oop

var obj = { name : 'xuriliang'}
var showLog = function(newval){
    console.log('name change :'+newval)
}
Object.defineProperty(obj,'name',{
    enumerable: true,
    configurable: true,
    set : function(newval){
        showLog(newval)
    }
})
obj.name = 'rlxu';

Vue中的應用

const sharedPropertyDefinition = {
  enumerable: true,
  configurable: true,
  get: noop,
  set: noop
}

export function proxy (target: Object, sourceKey: string, key: string) {
  sharedPropertyDefinition.get = function proxyGetter () {
    return this[sourceKey][key]
  }
  sharedPropertyDefinition.set = function proxySetter (val) {
    this[sourceKey][key] = val
  }
  Object.defineProperty(target, key, sharedPropertyDefinition)
}

function initData (vm: Component) {
  let data = vm.$options.data
  data = vm._data = typeof data === 'function'
    ? getData(data, vm)
    : data || {}
  if (!isPlainObject(data)) {
    data = {}
    process.env.NODE_ENV !== 'production' && warn(
      'data functions should return an object:\n' +
      'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
      vm
    )
  }
  // proxy data on instance
  const keys = Object.keys(data)
  const props = vm.$options.props
  const methods = vm.$options.methods
  let i = keys.length
  while (i--) {
    const key = keys[i]
    if (process.env.NODE_ENV !== 'production') {
      if (methods && hasOwn(methods, key)) {
        warn(
          `Method "${key}" has already been defined as a data property.`,
          vm
        )
      }
    }
    if (props && hasOwn(props, key)) {
      process.env.NODE_ENV !== 'production' && warn(
        `The data property "${key}" is already declared as a prop. ` +
        `Use prop default value instead.`,
        vm
      )
    } else if (!isReserved(key)) {
      proxy(vm, `_data`, key)    
    }
  }
  // observe data
  observe(data, true /* asRootData */)
}

參考資料

MDNui

相關文章
相關標籤/搜索