资讯专栏INFORMATION COLUMN

JS基础篇--JS中的可枚举属性与不可枚举属性以及扩展

dreamans / 834人阅读

摘要:在中,对象的属性分为可枚举和不可枚举之分,它们是由属性的值决定的。这是因为中内置的属性是不可枚举的,所以不能被访问到。此对象不可扩展且指定的属性名称不存在。返回值一个数组,其中包含对象的可枚举属性和方法的名称。

在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

可以看到除了”sex“之外的属性都遍历到了

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 = "
"; // 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 = "
"; // 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 方法获取该对象的属性和方法。

js代码:

// 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 方法获取该对象自己的属性(包括方法)。

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...
相关阅读:Javascript apply的巧妙用法以及扩展到Object.defineProperty的使用

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87317.html

相关文章

  • JS进阶--JS apply的巧妙用法以及扩展到Object.defineProperty的使用

    摘要:的使用对象是由多个名值对组成的无序的集合。目标属性所拥有的特性返回值传入函数的对象。是一种获得属性值的方法是一种设置属性值的方法。参考相关阅读链接基础篇中的可枚举属性与不可枚举属性以及扩展 Math.max 实现得到数组中最大的一项 var array = [1,2,3,4,5]; var max = Math.max.apply(null, array); console.log(m...

    jasperyang 评论0 收藏0
  • JS基础--HTML DOM classList 属性

    摘要:使用,程序员还可以用它来判断某个节点是否被赋予了某个类。现在是增加现在是删除是否存在类检查是否含有某个类结果是或者。属性返回类列表中类的数量。查看元素有多少个类名获取获取元素的所有类名返回类名在元素中的索引值。 页面DOM里的每个节点上都有一个classList对象,程序员可以使用里面的方法新增、删除、修改节点上的CSS类。使用classList,程序员还可以用它来判断某个节点是否被赋...

    snowell 评论0 收藏0
  • JS学习之Object

    摘要:文中的多为构造函数原型对象属性为函数的专属属性,表示函数的原型对象。关于各种数据类型的属性的展示对象的构造器函数该属性指向创建该对象原型的构造函数。对对象的冻结状态的设置和判断,前者让冻结对象,后者判断对象是否被冻结。 前言 上篇文章介绍了JS的对象,本文将介绍Object这个基类,主要介绍其属性和方法(其实这些在MDN里都有^_^,点击这里可以直通MDN)。好了废话不多说了,直接开始...

    qujian 评论0 收藏0
  • JS基础05「对象」

    摘要:对象是的数据类型。对象是动态的,可以随时新增和删除自有属性。客户端中表示网页结构的对象均是宿主对象。提供第二个可选参数,用以对对象的属性进行进一步描述。没有原型的对象为数不多,就是其中之一。运算符的左侧是属性名字符串,右侧是对象。 对象是 JavaScript 的数据类型。它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值,因此我们可以把它看成是从字符串到值的映射。对象是...

    frolc 评论0 收藏0
  • 浅谈 JS 对象之扩展、密封及冻结三大特性

    摘要:尝试删除一个密封对象的属性或者将某个密封对象的属性从数据属性转换成访问器属性,结果会静默失败或抛出异常严格模式。 扩展特性 Object.isExtensible 方法 Object.preventExtensions 方法 密封特性 Object.isSealed 方法 Object.seal 方法 冻结特性 Object.isFrozen 方法 Object...

    ChristmasBoy 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<