zoukankan      html  css  js  c++  java
  • 关于javascript中defineProperty的学习

    语法

    Object.defineProperty(obj, prop, descriptor)

    参数

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

    返回值

        被传递给函数的对象。

    使用说明:

    我们一般给一个对象创建一个新的属性时,大部分采用的都是如下方式:

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

    但是这种创建方式的属性,其值可被修改,可被遍历等等。 如果想创建隐藏属性(使用for in 无法遍历出来)

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

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

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

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

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

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

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

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

    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
  • 相关阅读:
    Linux(8)查看服务器系统信息
    Scrapy爬取西刺代理ip流程
    Scrapy提取多个标签的text
    Scrapy常用命令行工具
    暴力&打表
    博客试水
    Linux --远程访问控制
    php--最新正则(手机号码)
    MySQLdump常用命令
    关于XSS攻击
  • 原文地址:https://www.cnblogs.com/demonxian3/p/8952873.html
Copyright © 2011-2022 走看看