跳到主要内容

操作属性

属性包括名和值,属性名可以包括空字符串在内的任意字符串,但对象中不能存在两个同名的属性。值可以是任意的 JavaScript 值。除了明和值以外,每个属性还有一些相关的值,称之为属性特性。

  • 可写 :(writable attribute) 表明是否可以设置该属性的值
  • 可枚举 :(enumerable attribute) 表明是否可以通过 for/in 循环返回该属性
  • 可配置 :(configurable attribute) 表明是否可以删除或是修改该属性

即便属性是 configurable:false ,我们还是可以 把 writable 的状态由 true 改为 false ,但是无法由 false 改为 true 。

定义属性

  • 直接冒号定义
  • 对象外用 点 运算符构造
  • 通过构造函数构造

在声明变量时可以使用 var ,但是在声明对象属性时不能使用 var 语句。

ECMAScript 5 新增两个静态函数 , 来指定对象定义的属性。

Object.defineProperty

将属性添加到对象(在对象未指明的属性名称时) , 或者修改现有属性(在对象指明属性名称时)。

Object.defineProperty(object, propertyName, descriptors);
  • object 必须参数 , 指定要添加或修改的属性的对象
  • propertyName 必须参数 , 表示一个包含属性名称的字符串
  • descriptors 必须参数 , 定义属性的描述 , 它可以针对属性和访问器属性

Object.defineProperty 返回值为已修改的对象 (writeable _ 是否可写_ 、 enumerable _ 是否可枚举_ 、 configurable _ 是否可修改_ ) 。

var obj = {};
Object.defineProperty(obj, 'newDataProperty', {
value: 101,
writable: true,
enumerable: true,
configurable: true,
});
obj.newDataProperty = 102;
console.log(obj.newDataProperty); // 102
var obj = {};
Object.defineProperty(obj, 'newAccessorProperty', {
set: function (x) {
this.newaccpropvalue = x * x;
},
get: function () {
return '<h1>' + this.newaccpropvalue + '</h1>';
},
enumerable: true,
configurable: true,
});
obj.newAccessorProperty = 30;
console.log(obj.newAccessorProperty);
// <h1>900</h1>

上例中,使用 Object.defineProperty 函数将访问器将属性添加到用户定义对象 obj 。定义当前为对象的 newAccessorProperty 属性添加新值,设置其值为赋值的平方,而读取该属性时,会以一级标题的形式显示,即输出值为 HTML 字符串。

Object.defineProperties

添加多个或修改多个属性。

Object.defineProperties(object, descriptors);
  • object 必须参数,对其添加或修改属性的对象,可以是本地对象或 DOM 对象
  • descriptors 必须参数,包含一个或多个描述对象。每个描述对象描述一个数据属性或访问器属性

该参数为一 , 需要用 括起来

var obj = {};
Object.defineProperties(obj, {
newDataProperty: {
value: 101,
writable: true,
configurable: true,
enumerable: true,
},
newAccessorProperty: {
set: function (x) {
this.newAccessorPropValue = x;
},
get: function () {
return this.newAccessorPropValue;
},
enumerable: true,
configurable: true,
},
});
obj.newAccessorPropValue = 10;
console.log(obj.newAccessorPropValue); // 10

上例中,使用 Object.defineProperties 函数将数据属性和访问器添加到用户指定的对象上。使用对象文本创建了 newDataProperty 和 newAccessorPropValue 描述符对象的 descriptors 对象。

访问属性

  • 点号 访问 —— -- 点运算符左侧是对象引用的变量,右侧是属性名,属性名必须是一个标识符,而不是一个字符串
  • 中括号访问 —— -- 以中括号(数组形式)访问属性时,应以字符串形式指定属性名,而不是
  • for/in 遍历 <li class="noList indent2"> 由于属性没有固定顺序 , 同时也只能枚举自定义属性 . 如果遇到不存在属性 , 返回 undefined

ECMAScript 新增了四个 函数来访问对象属性。

  • Object.getPrototypeOf(object) 返回指定对象的原型
  • Object.getOwnPropertyNames(object) 返回私有属性的名称
  • Object.keys(object) 返回指定对象可枚举的属性和方法的名称
  • Object.getOwnPropertyDescriptor(object, propertyName) 获取指定对象的私有属性的描述

Object.getPrototypeOf

Object.getPrototypeOf 可以返回指定对象的原型。

Object.getPrototypeOf(object);
function Pasta(grain, width) {
this.grain = grain;
this.width = width;
}
var spaghetti = new Pasta('wheat', 0.2);
var proto = Object.getPrototypeOf(spaghetti);
console.log(proto === Pasta.prototype); // true

Object.getOwnPropertyNames

Object.getOwnPropertyNames 可以返回指定对象私有属性的名称。私有属性是指直接对该属性定义的属性,而不是从该对象与那行继承的属性。具体用法如下。

Object.getOwnPropertyNames(object);
function Pasta(grain, width, shape) {
this.grain = grain;
this.width = width;
this.shape = shape;
this.toString = function () {
return this.grain + ', ' + this.width + ', ' + this.shape;
};
}
var spaghetti = new Pasta('wheat', 0.2, 'circle');
var arr = Object.getOwnPropertyNames(spaghetti);
console.log(arr); // rain,width,shape,toString

Object.keys

Object.keys 与 Object.getOwnPropertyNames 类似,但是, Object.Keys 仅能返回指定可枚举属性和方法的名称。

Object.keys(object);

参数 object 表示指定的属性,可以是创建的对象或现有 DOM 对象。返回值是一个数组。其中包含可枚举属性和方法的名称。

function Pasta(grain, width, shape) {
this.grain = grain;
this.width = width;
this.shape = shape;
this.toString = function () {
return this.grain + ', ' + this.width + ', ' + this.shape;
};
}
var spaghetti = new Pasta('wheat', 0.2, 'circle');
var arr = Object.keys(spaghetti);
arr.forEach(k => {
console.log(k + '***');
});
// grain *** width *** shape *** toString ***
console.log('');
for (var i in arr) {
console.log(' 这是第 ' + (1 + Number(i)) + '属性,名称: ' + arr[i] + '');
}
// 这是第 1 属性,名称: grain
// 这是第 2 属性,名称: width
// 这是第 3 属性,名称: shape
// 这是第 4 属性,名称: toString

Object.getOwnPropertyDescriptor

Object.getOwnPropertyDescriptor 能够获得指定对象的私有属性的描述。

Object.getOwnPropertyDescriptor(object, propertyName);

参数 object 表示指定的对象, propertyName 表示属性的名称。返回值为属性的描述对象。

var obj = {};
obj.newDataProperty = 'abc';
var descriptor = Object.getOwnPropertyDescriptor(obj, 'newDataProperty');
descriptor.writable = false;
Object.defineProperty(obj, 'newDataProperty', descriptor);
var desc2 = Object.getOwnPropertyDescriptor(obj, 'newDataProperty');
for (var prop in desc2) {
console.log(prop + ': ' + desc2[prop]);
console.log('');
}
/****
* value: abc
* writable: false
* enumerable: true
* configurable: true
*/

赋值属性

与读取对象值操作相同,设置对象属性的值也可以使用使用点运算符和数组操作方法来实现。

var o = {
// 定义对象 x: 1, y: 2
};
o.x = 2; // 设置属性的新值,覆盖原值
o['y'] = 1; // 设置属性的新值,覆盖原值
alert(o['x']); // 返回 2
alert(o.y); // 返回 1

删除属性

删除属性 delete 运算符直接删除属性 , 枚举失效。

var o = { x: 1 }; // 定义对象
delete o.x;
// 删除对象的属性 x
alert(o.x); // 返回 undefined

当删除对象属性之后,不是将该属性值设置为 undefined ,而是从对象中彻底清除属性。如果使用 for/in 语句枚举对象属性,只能枚举属性值为 undefined 的属性,但是不会枚举已删除的属性。

使用方法

在 JavaScript 中,方法 ( Method )就是对象属性的一种特殊形式,即值为函数的属性。从功能角度分析,方法就是对象执行特定行为的逻辑块,是与外界交互的动作。

由于函数是一类数据,所以可以赋值给对象属性,于是该属性就是对象的一个方法。

var o = {
x: function () {
// 定义对象方法
alert('Method');
},
};

也可以这样定义方法。

var o = {};
o.x = function () {
// 定义对象方法
alert('Method');
};

使用小括号运算符可以调用对象的方法。

o.x(); // 调用对象的方法

对象内有一个 this 关键字,它总是指向引用调用该方法的对象。

var o = {
x: function () {
// 定义对象的方法
alert(this.y); // 访问当前对象的属性 y 的值
},
};
o.x(); // undefined
var f = o;
f.y = 2;
o.x(); // 2

方法和普通函数一样,可以传入参数,可以设置返回值。

var o = {};
o.x = function (a) {
return a * 10;
};
var f = o.x(5); // 调用方法,设置参数值 5
alert(f); // 返回值 50

构造函数是一类特殊的函数,它能够初始化对象,利用参数初始化 this 关键字所引用对象的 x 和 y 属性值。因此,构造函数就相当于对象的结构模板,利用它可以实例化包含相同属性但属性值不同的对象。

function f() {
// 定义方法
return this.x + this.y;
}
function MyClass(x, y) {
// 定义类
this.x = x;
this.y = y;
this.add = f; //将方法封装在类中,这样每一个实例都拥有该方法
}
var o = new MyClass(10, 20); // 实例化类,并初始化参数值
alert(o.add()); // 调用方法,返回值 30
function f() {
// 定义方法
return this.x + this.y;
}
function MyClass() {
// 定义类
this.x = arguments[0];
this.y = arguments[1];
this.add = f; // 将方法封装在类中,这样每一个实例都拥有该方法
}
var o = new MyClass(10, 20); // 实例化类,并初始化参数值
alert(o.add()); // 调用方法,返回值 30

配置特性

ECMAScript 5 新增 3 个函数用来设置对象属性的特性: Object.seal 、 Object.freeze 和 Object.preventExtensions 。这 3 个函数用来保护指定属性,防止修改现有属性,或阻止添加新属性。但是,作用略有不同。

Object.seal(object);
Object.freeze(object);
Object.preventExtensions(object);
函数不可添加新属性不可设置特性不可修改属性值
Object.preventExtensionsYNN
Object.sealYYN
Object.freezeYYY

在上述 3 个函数用法相同,都有一个参数,用来指定要限制的对象。

  • Object.freeze 能够阻止修改现有的属性的特性和值,并阻止添加新值
  • Object.seal 能够阻止修改现有属性的特性,并阻止添加新属性。但是对属性值不进行保护
  • Object.preventExtensions 能够阻止向对象添加新属性。但是对属性的值和特性不进行保护
var obj = { pasta: 'spaghetti', length: 10 };
Object.preventExtensions(obj);
obj.newProp = 50;
obj.pasta = 50;
console.log(obj.newProp); // undefined
console.log(obj.pasta); // 50

上例,使用 Object.preventExtensions 函数阻止 obj 添加新的属性。下例,将函数由 Object.preventExtensions 改为 Object.freeze 将阻止修改属性。

var obj = { pasta: 'spaghetti', length: 10 };
Object.freeze(obj);
obj.newProp = 50;
obj.pasta = 50;
console.log(obj.newProp); // undefined
console.log(obj.pasta); // spaghetti

检测特性

为确定属性的特性, ECMAScript 5 新增了 3 个函数来检测,即 Object.isSealed 、 Object.isFrozen 和 Object.Extensible 。

  • Object.isSealed() :如果无法在对象中修改现有属性的特性,且无法向属性添加新属性,则返回 true
  • Object.isFrozen() :如果无法在对象中修改现有属性的特性和值,且无法添加新属性,则返回 true
  • Object.isExtensible() :如果对象是可扩展的(这表示可向对象添加新属性),则为 true ,否则为 false
var obj = { pasta: 'spaghetti', length: 10 };
if (!Object.isFrozen(obj)) {
obj.pasta = 50;
}
Object.freeze(obj);
console.log(obj.pasta); // 50
var obj = { pasta: 'spaghetti', length: 10 };
Object.freeze(obj);
if (!Object.isFrozen(obj)) {
obj.pasta = 50;
}
console.log(obj.pasta); // spaghetti