本篇主要介绍JS中对象的属性,包括:属性的分类、访问方式、检测属性、遍历属性以及属性特性等内容。
属性:对象的成员,不单单是'属性'(字段),属性也包含了方法
属性的命名方式
属性名称可以包含英文字符、数字(不能开头)、特殊符号(如:-、_、$等等)。
但一般使用纯英文字符,在特殊情况下会添加-(横杠:-webkit-、-moz- )以及 _(下划线)。
若属性名称包含了-(横杠),属性访问方式只能采用'[ ]'中括号访问:
var o = {
x: 1,
y: 2,
'-x': 3,
'-showX': function () {
alert(this.x);
}
}
// o.-x; // 此访问方式会报异常
console.log(o['-x']); // => 3 :读取带-(横杠)名称的属性,只能采用'[ ]'中括号访问方式
o['-showX'](); // => 弹出1 :若方法名称带-(横杠),执行方式很别扭
属性的查找路径
假设读取某个对象的属性x,首先会在此对象的实例属性中查找。若没有找到,将会在此对象的原型对象中查找属性x。若原型对象也没有属性x,将继续查找这个原型对象的原型(假设原型对象含有原型),一直到找到属性x或者无原型为止。
属性的分类
对象中的的属性根据是否是自身的分为自身属性和继承属性
① 自有属性:也可叫实例属性;指对象自身的属性。
② 继承属性:也可叫原型属性;指对象从原型中继承的属性。
删除属性
delete obj.prototypeName或者是delete obj[prototypeName]
只能删除对象的自身属性,不能删除继承(原型)属性
var o = {};
o.x = '1';
console.log(o.x); // => 1
delete o.x;
console.log(o.x); // => undefined :访问不存在的属性,返回undefined
o.constructor.prototype.y = '2'; // 在原型对象上添加一个y属性
console.log(o.y); // => 2
delete o.y; // 删除继承属性y
console.log(o.y); // => 2 :还是可以访问继承属性y
检测属性
检测对象中是否包含某个属性
in操作符
说明:判断对象是否包含某个属性,会从对象的实例属性、继承属性里进行检测。
语法:propertyName in obj
返回值:
{bool} 判断对象的实例属性或继承是否包含此属性。
true:对象的实例属性或继承属性包含此属性;
false:对象的实例属性或继承属性不包含此属性。
function People(name) {
this.name = name;
}
function Student(age) {
this.age = age;
}
Student.prototype = new People(); // 设置Student的原型为People对象
var s = new Student(22);
console.log('age' in s); // => true :age为实例属性
console.log('name' in s); // => true :name为继承属性
console.log('address' in s); // => false :address不存在此对象呢,返回false
obj.hasOwnProperty(propertyName)
说明:判断对象是否拥有一个指定名称的实例属性,不会检查继承属性。
参数:
①propertyName {string} :属性名称。
语法:obj.hasOwnProperty(propertyName)
返回值:
{bool} 判断对象是否拥有一个指定名称的实例属性;此方法不会检查对象原型链中的属性。
true :属性为对象的实例属性,非继承。
false :属性不为对象的实例属性。
var Student = function (name) {
this.name = name;
};
// 给Student的原型添加一个sayHello方法
Student.prototype.sayHello = function () {
alert('Hello,' + this.name);
}
// 给Student的原型添加一个age属性
Student.prototype.age = '';
var st = new Student('张三'); // 初始化对象st
console.log(st.hasOwnProperty('name')); // => true :调用构造函数时,通过this.name附加到实例对象上
console.log(st.hasOwnProperty('sayHello')); // => false :sayHello方法为原型上的成员
console.log(st.hasOwnProperty('age')); // => false :age属性为原型上的成员
obj.propertyIsEnumerable(propertyName)
说明:判断指定名称的属性是否为实例属性并且是可枚举的(可用for/in循环枚举)
参数:
①propertyName {string} :属性名称。
语法:obj.propertyIsEnumerable(propertyName)
返回值:
{bool} 判断属性是否为实例属性并且是可枚举的(可用for/in循环枚举),不考虑原型链中的成员。
true :属性为对象的实例属性并且是可枚举的。
false :属性不为对象的实例属性或不可枚举的。
var o = Object.create({}, {
name: {
value: 'tom',
enumerable: true // 可枚举
},
age: {
value: 22,
enumerable: false // 不可枚举
}
});
console.log(o.propertyIsEnumerable('name')); // => true :name为实例属性并且可枚举
console.log(o.propertyIsEnumerable('age')); // => false :age为实例属性但不可枚举
console.log(o.hasOwnProperty('age')); // => true :hasOwnProperty()方法只判断属性是否为实例属性
检测方法 | 语法 | 检测属性范围 | 返回值 |
---|---|---|---|
in操作符 | propertyName in obj | 实例属性,继承属性 | {bool} true 符合条件,false 不符合条件(下同) |
obj.hasOwnPropertyy(propertyName) | obj.hasOwnProperty(propertyName) | 实例属性 | |
obj.perpertyIdEnumerable(propertyName) | obj.propertyIsEnumerable(propertyName) | 可枚举的实例属性 |
遍历属性
for In语句块
说明:遍历对象的可枚举属的实例属性和继承属性
语法:
for (p in obj) {
// p表示遍历的属性名称
}
var po = { px: 1, py: 2 };
var o = { x: 1, y: 2 };
o.__proto__ = po; // 设置o的原型为po
for (property in o) {
console.log(property); // => 输出属性的名称:x、y、px、py
console.log(o[property]); // => 采用中括号访问方式,输出属性的值
}
Object.key(obj)
说明:返回一个数组,包含对象可枚举的实例属性名称
参数:
①obj {object} :实例对象
返回值:
{Array} 返回一个数组,包含对象可枚举的实例属性名称
示例:
var po = { px: 1, py: 2 };
var o = { x: 1, y: 2 };
o.__proto__ = po; // 设置o的原型为po
var propertyArray = Object.keys(o); // => 返回一个包含了可枚举的实例属性名称的数组
for (var i = 0, len = propertyArray.length; i < len; i++) {
console.log(propertyArray[i]); // => 输出实例属性名称:x、y
}
获取的属性只是可枚举的实例属性的集合
Object.getOwnPropertyNames(obj)
说明:返回一个数组,包含对象的所有实例属性名称。包括可枚举和不可枚举的
参数:
①obj {object} :实例对象
返回值:
{Array} 返回一个数组,包含对象所有实例属性名称
与Object.keys()的差别:Object.keys()只返回可枚举的实例属性,Object.getOwnPropertyNames()返回所有实例属性
示例:
var po = { px: 1, py: 2 };
var o = { x: 1, y: 2 };
// 设置对象o的属性特性:属性x为可枚举,属性y为不可枚举
Object.defineProperties(o, {
x: {
enumerable: true
},
y: {
enumerable: false
}
});
o.__proto__ = po; // 设置o的原型为po
// 1.Object.keys():获取一个可枚举的实例属性名称的数组
var propertyArray = Object.keys(o);
for (var i = 0, len = propertyArray.length; i < len; i++) {
console.log(propertyArray[i]); // => 输出实例属性名称:x
}
// 2.Object.getOwnPropertyNames():获取一个包含的实例属性名称的数组,不管实例属性是否可枚举
propertyArray = Object.getOwnPropertyNames(o);
for (var i = 0, len = propertyArray.length; i < len; i++) {
console.log(propertyArray[i]); // => 输出实例属性名称:x、y
}
检测方式 | 语法 | 遍历属性的范围 | 返回值 |
---|---|---|---|
for in语句块 | for (p in obj) { // p表示遍历的属性名称} | 可枚举的实例属性和继承属性 | {String} 属性的名称 |
Object.keys(obj) | Object.keys(obj) | 可枚举的实例属性 | {Array} 返回一个数组,包含对象可枚举的实例属性名称 |
Object.getOwnPropertyNames(obj) | Object.getOwnPropertyNames(obj) | 包含对象的所有实例属性名称。包括可枚举和不可枚举的 | {Array} 返回一个数组,包含对象所有实例属性名称 |
属性描述符
数据属性
1)在使用Object.defineProperty、Object.defineProperties 或 Object.create 函数的情况下添加数据属性,writable、enumerable和configurable默认值为false。
2)使用对象直接量创建的属性,writable、enumerable和configurable特性默认为true。
// 1)对象直接量;属性特性默认为true
var o1 = {
name: 'tom'
};
console.log(Object.getOwnPropertyDescriptor(o1, 'name')); // => Object {value: "tom", writable: true, enumerable: true, configurable: true}
// 2)通过Object.create创建,属性特性默认为false
var o2 = Object.create(null, {
name: {value:'tom'}
});
console.log(Object.getOwnPropertyDescriptor(o2, 'name')); // => Object {value: "tom", writable: false, enumerable: false, configurable: false}
访问器属性
说明:设置属性的访问方式;set、get特性等
var obj = {};
// 添加一个属性,并设置为访问器属性
Object.defineProperty(obj, "name", {
get: function () {
return this._name; // get和set里的变量不要使用属性,如:属性为name,get和set用的是_name
},
set: function (x) {
if (isNaN(x)) {
this._name = x;
} else {
this._name = 'name不能为纯数字';
}
},
enumerable: true,
configurable: true
});
console.log(Object.getOwnPropertyDescriptor(obj, 'name')); // => Object {get: function, set: function, enumerable: true, configurable: true}
obj.name = '12';
console.log(obj.name); // => name不能为纯数字