关于javascript中defineProperty的学习

语法

Object.defineProperty(obj, prop, descriptor)

参数

obj
要在其上定义属性的对象。
prop
要定义或修改的属性的名称。
descriptor
将被定义或修改的属性描述符。

返回值

    被传递给函数的对象。app

 

使用说明:函数

咱们通常给一个对象建立一个新的属性时,大部分采用的都是以下方式:this

var obj = {}; obj.key = "Hello"

可是这种建立方式的属性,其值可被修改,可被遍历等等。 若是想建立隐藏属性(使用for in 没法遍历出来)spa

或者想建立一个只读属性(不可写入),使用这种方式就不可取了。在ES6中,有一个叫作Symbol类型的东西prototype

这个东西能够人为的定义它是否可写,可枚举,可重配置等等,而定义这个Symbol的方法则是Object对象的 definePropertycode

这里能够将Symbol理解为带特殊技能的属性。 咱们能够为一个对象,使用defineProperty方法来定义一个带红蓝buff的属性对象

 

先来讲说属性描述符,由名称可知是用来描述一个属性具备什么特色用的,属性描述符分为两类: 数据描述符存取描述符blog

数据描述符表示一个具备值的属性,该值可能只读,可能可写继承

存储描述符表示一个具备对数据进行存取操做的属性。ip

一个属性只能为以上两种类别中的一个,不能同时是二者

 

下面是一些上面两个描述符可选的键值:

configurable:  是否容许改变描述符,是否容许删除属性,默认false

enumerable:   是否容许被枚举(for in), 默认false

writeable:   是否可写,默认false

value:    设定数据描述符的value值,默认是undefine

get:     设定存储描述符的getter方法,默认undefine

set:     设定存储描述符的setter方法,默认undefine

 

注意: configurable enumerable 这两个描述键值 是数据描述符 与 存储描述符 共有的

writeable 和 value 是数据描述符独有的, 而set 和 get方法是存储描述符独有的,另外

这些选项不必定是自身的属性,也须要考虑继承,为确保留有默认值,须要冻结以前的

Object.prototype,或者将__proto__属性指向null

 

说了那么多概念性的东西,下面来实战练习一下吧

任务一: 建立一个带有只读属性的对象

var o = {};

Object.defineProperty(o, "myName", {
   value: "孙悟空",
   writeable: false        //不容许写,只读的
});

document.write(o.myName);        //孙悟空

//尝试改变属性

o.myName = "猪八戒";              //这里不会报错,可是会抛出readonly
document.write(o.myName);        //孙悟空

 

任务二: 建立一个带有"隐藏"属性的对象

var o = {};

Object.defineProperty(o, "myName", {
   value: "孙悟空",
   enumerable: false                   //不容许被枚举出来
});


//经过普通方式建立其余属性
o.myAge = 33;
o.myAddress = "China";

//枚举对象全部变量
for(var i in o){
    document.write(i +":"+ o[i] + "<br>");
}

//输出结果:
//myAge: 33
//myAddress: China

//虽然没法遍历出来,可是依然是能够访问的
document.write(o.myName);            //孙悟空

 

任务三:建立一个带有存储描述符的属性对象

var p;              //稍后使用存储描述符对他进行读写操做
var o = {};

Object.defineProperty(o, "b", {   //属性名为b
        get: function(){
             return p;                //取全局变量
        },

        set: function(value){
             p = value;              //写全局变量
        },

        enumerable: true,        //可遍历
        configurable: true         //可修改
});

o.b = 38;             //看起来像是直接赋值,实际上是调用了set方法赋值

document.write(p);   //38, 由于get方法读写的对象是全局变量
    

存储描述符,给人感受像是对 对象的属性进行读写操做,但其实背后多是对其余变量的读写

操做,由于能够人为的定义读写操做执行的函数 set/get ,因此咱们就能够实现读写时实现本身

想要的功能,好比数据类型判断等等,若是对存储描述符仍是不太理解,能够看看下面两段代码

实现一个自存档的属性

function Archiver() {
  var temperature = null;
  var archive = [];

  Object.defineProperty(this, 'temperature', {
    get: function() {
      console.log('get!');
      return temperature;
    },
    set: function(value) {
      temperature = value;
      archive.push({ val: temperature });
    }
  });

  this.getArchive = function() { return archive; };
}

var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]

第二段

var pattern = {
    get: function () {
        return 'I alway return this string,whatever you have assigned';
    },
    set: function () {
        this.myname = 'this is my name string';
    }
};


function TestDefineSetAndGet() {
    Object.defineProperty(this, 'myproperty', pattern);
}


var instance = new TestDefineSetAndGet();
instance.myproperty = 'test';

// 'I alway return this string,whatever you have assigned'
console.log(instance.myproperty);
// 'this is my name string'
console.log(instance.myname);

对于configurable的效果,你们可能还有疑问,能够阅读下面这段代码,本身动手试试

var o = {};
Object.defineProperty(o, "a", { get : function(){return 1;}, 
                                configurable : false } );

// throws a TypeError
Object.defineProperty(o, "a", {configurable : true}); 
// throws a TypeError
Object.defineProperty(o, "a", {enumerable : true}); 
// throws a TypeError (set was undefined previously) 
Object.defineProperty(o, "a", {set : function(){}}); 
// throws a TypeError (even though the new get does exactly the same thing) 
Object.defineProperty(o, "a", {get : function(){return 1;}});
// throws a TypeError
Object.defineProperty(o, "a", {value : 12});

console.log(o.a); // logs 1
delete o.a; // Nothing happens
console.log(o.a); // logs 1
相关文章
相关标签/搜索