JavaScript 之存取器属性

首先介绍一下此篇随笔的主角:

  Object.getOwnPropertyDescriptor 和 Object.getOwnPropertyDescriptors

  通过这两个api,可以访问除 null 以外任何对象的属性。

  来看一个事实:

    var obj = { x : 1 }

    console.log( obj.x )  //  1

  通过小圆点访问的真的是 x 的值吗?你可以将小圆点看成一个运算符,访问到的永远是存取器属性内部的value值 或者 get 方法的返回值。

  前面我在一篇随笔中说到函数对象是存储在堆内存中的数据,而数字 1 明显应该是存在栈内存中的数据,难不成还会从堆内存中分配出一个地址指向栈内存?显然只有从栈定位到堆这种单向定位比较合理,那么是否 1 是一个对象的一部分呢? 是的,x 是另一个堆地址,开辟了一块空间,存储着存取器属性这个对象。

    Object.getOwnPropertyDescriptor( obj , 'x' )

    // { value: 1 , configurable: true , enumerable: true, writable: true }

  不难发现通过小圆点访问这个属性,实际上访问的是存取器属性的 value 值,其他三个属性见名知义,configurable控制着另外两个属性的修改权限,这里的 writable 简单理解就是说是否可以修改 x 的值,x 表示什么? 上面已经说到是堆内存的另一个地址,可以理解为是一个对象,因此不要误解为 value 的值,当然,这已经是最后一层存取器属性了,存取器的存取器属性如果有的话,那可能就不是我等能见到的底层了。。

  说了这么多,我们来实验一下,使得 obj 这个变量无法再指向另一个地址,也可以理解成 obj 这个对象的内容无法被改变:

  Object.defineProperty( window, 'obj', { writable: false } )

  obj = {}  // error

  知道了存取器属性的存在,我们能发现许多有意思的现象:

  var fn = new Function ;

  Object.getOwnPropertyDescriptor( fn , 'prototype' ) //{ writable: true , ... }

  Object.getOwnPropertyDescriptor( Object , 'prototype' ) //{ writable: false , ... }

  Object.getOwnPropertyDescriptor( Object.prototype , 'valueOf' ) //{ writable: true , ... }

  也就是说普通函数的原型地址是可以移动的,而内嵌的函数原型地址则不可以更改,但可以修改原型里的某些方法,这些都需要本文开头提到的两个 api 去鉴别。

  事实上,在存储器属性内除了这四个属性,还有可能具有 getter 和 setter 方法,但 value 属性和 get 方法不能同时存在:

  var a = { x:1 }
  Object.defineProperty( a , 'x' , {
    get ( ){
    return this.tmp
  },
    set ( val ){
    val > 0 ? this.tmp = val : this.tmp = 0
  }})
  a.x = 5 ;
  console.log( a.x )  // 5 
  a.x = -5 ;
  console.log( a.x ) // 0
 
  这里还有一点要注意的是, get 和 set 方法在存取器属性外的用法有所不同。
 

  

猜你喜欢

转载自www.cnblogs.com/lowki/p/10420653.html