zoukankan      html  css  js  c++  java
  • JS中的可枚举属性与不可枚举属性以及扩展

    在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。

    一、怎么判断属性是否可枚举

    js中基本包装类型的原型属性是不可枚举的,如Object, Array, Number等,如果你写出这样的代码遍历其中的属性:

    var num = new Number();
    for(var pro in num) {
        console.log("num." + pro + " = " + num[pro]);
    }

    它的输出结果会是空。这是因为Number中内置的属性是不可枚举的,所以不能被for…in访问到。

    Object对象的propertyIsEnumerable()方法可以判断此对象是否包含某个属性,并且这个属性是否可枚举。

    需要注意的是:如果判断的属性存在于Object对象的原型内,不管它是否可枚举都会返回false

    二、枚举性的作用

    属性的枚举性会影响以下三个函数的结果:

    for…in

    Object.keys()

    JSON.stringify

    先看一个例子,按如下方法创建kxy对象:

    function Person() {
        this.name = "KXY";
    }
    Person.prototype = {
        constructor: Person,
        job: "student",
    };
     
    var kxy = new Person();
    Object.defineProperty(kxy, "sex", {
        value: "female",
        enumerable: false
    });

    其中用defineProperty为对象定义了一个名为”sex”的不可枚举属性

    接下来做以下验证:
    a.

    for(var pro in kxy) {
        console.log("kxy." + pro + " = " + kxy[pro]);
      }

    结果:

    kxy.name = KXY
    kxy.constructor = function Person() {
        this.name = "KXY";
    }
    kxy.job = student

    b.

    console.log(Object.keys(kxy));

    返回结果:["name"]
    只包含”name”属性,说明该方法只能返回对象本身具有的可枚举属性。

    c.

    console.log(JSON.stringify(kxy));

    返回结果:{"name":"KXY"}
    此方法也只能读取对象本身的可枚举属性,并序列化为JSON字符串(通过typeof JSON.stringify(kxy)得到string类型)。

    Object.defineProperty()

    上面用到了Object.defineProperty()方法,下面讲解下。

    语法

    Object.defineProperty(object, propertyname, descriptor)

    参数:

    • object:必需。 要在其上添加或修改属性的对象。 这可能是一个本机 JavaScript 对象(即用户定义的对象或内置对象)或 DOM 对象。

    • propertyname:必需。 一个包含属性名称的字符串。

    • descriptor:必需。 属性描述符。 它可以针对数据属性或访问器属性。

    返回值:已修改对象。

    备注:
    可使用 Object.defineProperty 函数来执行以下操作:

    • 向对象添加新属性。 当对象不具有指定的属性名称时,发生此操作。

    • 修改现有属性的特性。 当对象已具有指定的属性名称时,发成此操作。

    描述符对象中会提供属性定义,用于描述数据属性或访问器属性的特性。 描述符对象是 Object.defineProperty 函数的参数。

    若要向对象添加多个属性或修改多个现有属性,可使用 Object.defineProperties 函数 (JavaScript)。

    异常

    如果以下任一条件为 true,则引发 TypeError 异常:

    • object 参数不是对象。

    • 此对象不可扩展且指定的属性名称不存在。

    • descriptor 具有 value 或 writable 特性,并且具有 get 或 set 特性。

    • descriptor 具有 get 或 set 特性,上述特性不是函数且已定义。

    • 指定的属性名称已存在,现有属性具有 false 的 configurable 特性,且 descriptor 包含一个或多个与现有属性中特性不同的特性。 但是,当现有属性具有 false 的 configurable 特性和 true 的 writable 特性时,则允许 value 或 writable 特性不同。

    添加数据属性

    在以下示例中,Object.defineProperty 函数向用户定义的对象添加数据属性。 若改为向现有的 DOM 对象添加属性,则取消对 var = window.document 行的注释。

    var newLine = "<br />";
    
    // Create a user-defined object.
    var obj = {};
    
    // Add a data property to the object.
    Object.defineProperty(obj, "newDataProperty", {
        value: 101,
        writable: true,
        enumerable: true,
        configurable: true
    });
    
    // Set the property value.
    obj.newDataProperty = 102;
    document.write("Property value: " + obj.newDataProperty + newLine);
    
    // Output:
    // Property value: 102

    若要列出对象属性,请将以下代码添加到此示例中。

    var names = Object.getOwnPropertyNames(obj);
    for (var i = 0; i < names.length; i++) {
        var prop = names[i];
    
        document.write(prop + ': ' + obj[prop]);
        document.write(newLine);
    }
    
    // Output:
    //  newDataProperty: 102

    修改数据属性

    若要修改对象的属性特性,请将以下代码添加到前面所示的 addDataProperty 函数。 descriptor 参数只包含 writable 特性。 其他数据属性特性保持不变。

    // Modify the writable attribute of the property.
    Object.defineProperty(obj, "newDataProperty", { writable: false });
    
    // List the property attributes by using a descriptor.
    // Get the descriptor with Object.getOwnPropertyDescriptor.
    var descriptor = Object.getOwnPropertyDescriptor(obj, "newDataProperty");
    for (var prop in descriptor) {
        document.write(prop + ': ' + descriptor[prop]);
        document.write(newLine);
    }
    
    // Output
    // writable: false
    // value: 102
    // configurable: true
    // enumerable: true

    添加访问器属性

    在以下示例中,Object.defineProperty 函数向用户定义的对象添加访问器属性。

    var newLine = "<br />";
    
    // Create a user-defined object.
    var obj = {};
    
    // Add an accessor property to the object.
    Object.defineProperty(obj, "newAccessorProperty", {
        set: function (x) {
            document.write("in property set accessor" + newLine);
            this.newaccpropvalue = x;
        },
        get: function () {
            document.write("in property get accessor" + newLine);
            return this.newaccpropvalue;
        },
        enumerable: true,
        configurable: true
    });
    
    // Set the property value.
    obj.newAccessorProperty = 30;
    document.write("Property value: " + obj.newAccessorProperty + newLine);
    
    // Output:
    // in property set accessor
    // in property get accessor
    // Property value: 30

    若要列出对象属性,请将以下代码添加到此示例中。

    var names = Object.getOwnPropertyNames(obj);
    for (var i = 0; i < names.length; i++) {
        var prop = names[i];
    
        document.write(prop + ': ' + obj[prop]);
        document.write(newLine);
    }
    // Output:
    // in property get accessor
    // newAccessorProperty: 30

    修改访问器属性

    若要修改对象的访问器属性,请将以下代码添加前面所示的代码。 descriptor 参数只包含 get 访问器定义。 其他属性特性保持不变。

    // Modify the get accessor.
    Object.defineProperty(obj, "newAccessorProperty", {
        get: function () { return this.newaccpropvalue; }
    });
    
    // List the property attributes by using a descriptor.
    // Get the descriptor with Object.getOwnPropertyDescriptor.
    var descriptor = Object.getOwnPropertyDescriptor(obj, "newAccessorProperty");
    for (var prop in descriptor) {
        document.write(prop + ': ' + descriptor[prop]);
        document.write(newLine);
    }
    
    // Output:
    // get: function () { return this.newaccpropvalue; }
    // set: function (x) { document.write("in property set accessor" + newLine); this.newaccpropvalue = x; }
    // configurable: true
    // enumerable: true

    修改 DOM 元素上的属性

    下面的示例演示如何通过使用 Object.getOwnPropertyDescriptor 函数来获取和修改属性的属性描述符,从而自定义内置 DOM 属性。 对于此示例中,必须通过使用 ID 为“div”的 DIV 元素。

    // Get the querySelector property descriptor.
    var descriptor = Object.getOwnPropertyDescriptor(Element.prototype, "querySelector");
    
    // Make the property read-only.
    descriptor.value = "query";
    descriptor.writable = false;
    // Apply the changes to the Element prototype.
    Object.defineProperty(Element.prototype, "querySelector", descriptor);
    
    // Get a DOM element from the HTML body.
    var elem = document.getElementById("div");
    
    // Attempt to change the value. This causes the revised value attribute to be called.
    elem.querySelector = "anotherQuery";
    document.write(elem.querySelector);
    
    // Output:
    // query

    Object.keys()

    返回对象的可枚举属性和方法的名称。

    语法

    Object.keys(object)

    参数object:必需。包含属性和方法的对象。这可以是您创建的对象或现有文档对象模型 (DOM) 对象。
    返回值:一个数组,其中包含对象的可枚举属性和方法的名称。
    异常:如果为 object 参数提供的值不是对象的名称,则将引发 TypeError 异常。

    备注

    keys 方法仅返回可枚举属性和方法的名称。若要返回可枚举的和不可枚举的属性和方法的名称,可使用 Object.getOwnPropertyNames 函数 (JavaScript)。
    有关属性的 enumerable 特性的信息,请参见 Object.defineProperty 函数 (JavaScript)和 Object.getOwnPropertyDescriptor 函数 (JavaScript)。

    下面的示例创建一个对象,该对象具有三个属性和一个方法。然后使用 keys 方法获取该对象的属性和方法。

    // Create a constructor function.
    function Pasta(grain, width, shape) {
       this.grain = grain;
       this.width = width;
       this.shape = shape;
    
       // Define a method.
       this.toString = function () {
           return (this.grain + ", " + this.width + ", " + this.shape);
       }
    }
    
    // Create an object.
    var spaghetti = new Pasta("wheat", 0.2, "circle");
    
    // Put the enumerable properties and methods of the object in an array.
    var arr = Object.keys(spaghetti);
    document.write (arr);
    
    // Output:
    // grain,width,shape,toString

    下面的示例显示 Pasta 对象中以字母“g”开头的所有可枚举属性的名称。

    // Create a constructor function.
    function Pasta(grain, width, shape) {
        this.grain = grain;
        this.width = width;
        this.shape = shape;
    }
    
    var polenta = new Pasta("corn", 1, "mush");
    
    var keys = Object.keys(polenta).filter(CheckKey);
    document.write(keys);
    
    // Check whether the first character of a string is "g".
    function CheckKey(value) {
        var firstChar = value.substr(0, 1);
        if (firstChar.toLowerCase() == "g")
            return true;
        else
            return false;
    }
    
    // Output:
    // grain

    Object.getOwnPropertyNames()

    返回对象自己的属性的名称。一个对象的自己的属性是指直接对该对象定义的属性,而不是从该对象的原型继承的属性。对象的属性包括字段(对象)和函数。

    语法

    Object.getOwnPropertyNames(object)

    参数:object,必需。包含自己的属性的对象。
    返回值:一个数组,其中包含对象自己的属性的名称。
    异常:如果为 object 参数提供的值不是对象的名称,则将引发 TypeError 异常。

    备注

    getOwnPropertyNames 方法同时返回可枚举的和不可枚举的属性和方法的名称。若要仅返回可枚举的属性和方法的名称,可使用 Object.keys 函数 (JavaScript)。

    下面的示例创建一个对象,该对象具有三个属性和一个方法。然后使用 getOwnPropertyNames 方法获取该对象自己的属性(包括方法)。

    js代码:

    function Pasta(grain, width, shape) {
       // Define properties.
       this.grain = grain;
       this.width = width;
       this.shape = shape;
       this.toString = function () {
           return (this.grain + ", " + this.width + ", " + this.shape);
       }
    }
    
    // Create an object.
    var spaghetti = new Pasta("wheat", 0.2, "circle");
    
    // Get the own property names.
    var arr = Object.getOwnPropertyNames(spaghetti);
    document.write (arr);
    
    // Output:
    //   grain,width,shape,toString

    下面的示例显示了使用 Pasta 构造函数构造的 spaghetti 对象中以字母“S”开头的属性名。

    function Pasta(grain, size, shape) {
        this.grain = grain; 
        this.size = size; 
        this.shape = shape; 
    }
    
    var spaghetti = new Pasta("wheat", 2, "circle");
    
    var names = Object.getOwnPropertyNames(spaghetti).filter(CheckKey);
    document.write(names); 
    
    // Check whether the first character of a string is 's'. 
    function CheckKey(value) {
        var firstChar = value.substr(0, 1); 
        if (firstChar.toLowerCase() == 's')
            return true; 
        else
             return false; 
    }
    // Output:
    // size,shape

    参考

    https://msdn.microsoft.com/zh...
    https://msdn.microsoft.com/li...
    https://msdn.microsoft.com/zh...

    相关阅读:JS基础篇--JS apply的巧妙用法以及扩展到Object.defineProperty的使用

  • 相关阅读:
    学习笔记
    .net $&替换正则查找到的内容
    sql 常用日期函数
    2010学习计划
    优化存储过程
    sql server 标量值函数
    job88数据库操作
    .net 调用有返回值的存储过程
    GridView 18种操作
    SQLite的局限性
  • 原文地址:https://www.cnblogs.com/moqiutao/p/7389146.html
Copyright © 2011-2022 走看看