详解JavaScript中的Object对象:从基础到ES5高级特性
本文深入解析JavaScript中Object对象的核心功能。从构造函数与字面量创建方式入手,详细讲解constructor、hasOwnProperty等实例方法。重点剖析ES5引入的数据属性与访问器属性特性,包括[[Configurable]]、[[Enumerable]]等描述符,以及Object.defineProperty等高级API的使用与限制。
Object对象概述与创建方式
Object是JavaScript中最基础且高频使用的内置类型,所有JS对象均继承自它。尽管日常开发中多仅利用其存储数据,但Object内置了大量实用属性与方法,特别是ES5版本新增的功能。本文将自基础概念切入,系统梳理Object的常用方法及其实际应用场景。
基础介绍
创建对象
对象本质上是相似数据与功能的集合,用于模拟现实世界实体。在JavaScript中,创建对象主要采用两种途径:构造函数法与对象字面量法。
new构造函数法
var person = new Object();
person.name = "狼狼的蓝胖子";
person.age = 25;
该方法需使用new关键字调用Object构造函数,随后动态为实例添加属性。此方式相对繁琐,通常不推荐,建议优先使用对象字面量。
对象字面量
对象字面量通过key/value形式直接构建对象,简洁直观。
var person = {
name: “狼狼的蓝胖子”,
age: 25
};
此方式利用花括号包裹属性,以key/value形式定义属性,各属性间以逗号分隔。注意:最后一个属性后不应添加逗号,否则在部分旧版浏览器中会引发错误。
对象实例的内置属性与方法
对象实例的属性和方法
无论采用何种方式创建对象实例,该实例均具备以下属性与方法,下文将逐一解析。
constructor属性
constructor属性用于保存当前对象的构造函数。前例中,该属性指向Object方法。
var obj1 = new Object();
obj1.id = "obj1";
var obj2 = {
"id": "obj2"
};
console.log(obj1.constructor);//function Object(){}
console.log(obj2.constructor);//function Object(){}
hasOwnProperty(propertyName)方法
hasOwnProperty接收字符串参数(属性名),用于判断该属性是否存在于当前对象实例中,而非原型链上。参考以下示例:
var arr = [];
console.log(arr.hasOwnProperty("length"));//true
console.log(arr.hasOwnProperty("hasOwnProperty"));//false
示例中定义了数组实例arr,数组通过原型链继承Object并拥有自身属性。利用hasOwnProperty判断length为arr自有属性,而hasOwnProperty本身位于原型链上。该方法常与for...in结合,以获取对象自身的key。
isPrototypeOf(Object)方法
isPrototypeOf接收对象参数,用于判断当前对象是否位于传入参数对象的原型链上。具体见代码:
function MyObject() {}
var obj = new MyObject();
console.log(Object.prototype.isPrototypeOf(obj));
MyObject继承自Object,JS中继承通过prototype实现,故Object的prototype必在MyObject实例的原型链上。
propertyIsEnumerable(prototypeName)方法
propertyIsEnumerable用于判断指定属性是否可被for...in语句枚举。见代码:
var obj = {
name: "objName"
}
for (var i in obj) {
console.log(i);
}
执行输出字符串“name”,表明for...in可枚举obj的name属性。尽管obj还包含constructor、hasOwnProperty等属性,但未输出,说明它们不可被for...in枚举,可通过propertyIsEnumerable验证。
代码如下:
console.log(obj.propertyIsEnumerable("constructor"));//false
判断“constructor”是否可枚举,输出false表示不可枚举。
toLocaleString()方法
toLocaleString返回对象的字符串表示,结果与代码执行环境相关。
var obj = {};
console.log(obj.toLocaleString());//[object Object]
var date = new Date();
console.log(date.toLocaleString());//2016/2/28 下午1:39:27
toString()方法
toString用于返回对象的字符串表示。
var obj = {};
console.log(obj.toString());//[object Object]
var date = new Date();
console.log(date.toString());//Sun Feb 28 2016 13:40:36 GMT+0800 (中国标准时间)
valueOf()方法
valueOf返回对象的原始值,可能是字符串、数值或布尔值等,具体取决于对象类型。
var obj = {
name: "obj"
};
console.log(obj.valueOf());//Object {name: "obj"}
var arr = [1];
console.log(arr.valueOf());//[1]
var date = new Date();
console.log(date.valueOf());//1456638436303
如代码所示,不同对象实例调用valueOf返回不同数据。
数据属性与访问器属性详解
属性的类型
JavaScript中属性分为数据属性和访问器属性,下文将具体阐述。
数据属性
数据属性即平时定义对象时赋予的可读写属性。ES5定义了描述属性特征的特性(内部值,不可直接访问),以双中括号表示,如[[Enumerable]]。特性有默认值,修改需使用ES5新增的Object.defineProperty方法。数据属性包含4个描述特性的特性,依次说明如下: (1)[[Configurable]]:表示是否可通过delete操作符删除属性,默认值为true。
var obj = {};
obj.name = "myname";
delete obj.name;
console.log(obj.name);//undefined
代码显示,删除obj的name属性后再次访问返回undefined。 通过Object.defineProperty修改[[Configurable]]特性。
var obj = {};
obj.name = "myname";
Object.defineProperty(obj, "name", {
configurable: false
})
delete obj.name;
console.log(obj.name);//myname
将configurable设为false后,delete无法删除name属性;严格模式下执行delete将报错。
(2)[[Enumerable]]:表示是否可通过for...in枚举属性,默认true。 参考前例:
var obj = {
name: "objName"
}
for (var i in obj) {
console.log(i);//name
}
代码仅输出name属性,尝试将constructor的[[Enumerable]]设为true。
var obj = {
name: "objName"
}
Object.defineProperty(obj, "constructor", {
enumerable: true
})
for (var i in obj) {
console.log(i);//name,constructor
}
console.log(obj.propertyIsEnumerable("constructor"));//true
代码中for...in循环获取name和constructor,propertyIsEnumerable判断constructor返回true。
(3)[[Writable]]:表示属性值是否可修改,默认true。 若[[Writable]]设为false,尝试修改无效,严格模式下报错。
(4)[[Value]]:表示属性值,默认undefined。
通过简单示例验证这两个特性:
var obj = {
name: "name"
};
console.log(obj.name);//name
Object.defineProperty(obj, "name", {
value: "newValue",
writable: false
})
console.log(obj.name);//newValue
obj.name = "oldValue";
console.log(obj.name);//newValue
定义obj的name属性值为“name”,通过defineProperty修改值并设为不可修改。再次修改name无效。 若通过defineProperty修改name值,是否可修改?答案是肯定的:
Object.defineProperty(obj, "name", {
value: "oldValue"
})
console.log(obj.name); //oldValue
访问器属性
访问器属性类似C#中的属性,区别于数据属性在于其无[[Writable]]和[[Value]],而拥有一对getter和setter函数。 [[Get]]:读取时调用的函数,默认undefined。 [[Set]]:设置时调用的函数,默认undefined。 getter和setter非常实用,例如第二个属性值随第一个变化。此前需手动修改,现可通过get/set解决。见示例:
var person = {
age: 10
}
Object.defineProperty(person, "type", {
get: function () {
if (person.age > 17) {
return "成人";
}
return "小孩";
}
})
console.log(person.type);//小孩
person.age = 18;
console.log(person.type);//成人
修改age值,type值同步更新,无需手动维护type。 以下方式也可实现相同效果:
var person = {
_age: 10,
type: "小孩"
}
Object.defineProperty(person, "age", {
get: function () {
return this._age;
},
set: function (newValue) {
this._age = newValue;
this.type = newValue > 17 ? "成人" : "小孩";
}
})
console.log(person.type);
person.age = 18;
console.log(person.type);
访问器属性注意事项: 1、严格模式下,必须同时设置get和set。 2、非严格模式下,可只设其一;仅设get则为只读,仅设set则不可读。 3、Object.defineProperty为ES5新方法,IE9支持(IE8部分支持,仅限DOM对象),旧浏览器可通过非标准方法defineGetter()和defineSetter()设置,此处不赘述。
ES5属性特性操作方法
特性操作的相关方法
ES5提供读取或操作属性特性的方法,前文已用Object.defineProperty。总结常用方法如下:
(1)Object.defineProperty 定义对象属性,前文已多次使用,简述用法。
代码如下:
Object.defineProperty(obj,propName,descriptor);
defineProperty类似Object静态方法,直接调用,接收3个参数: obj:需定义属性的对象。 propNane:被定义的属性名称。 defineProperty:属性描述符,含特性定义。 示例如下:
var obj = {};
Object.defineProperty(obj, "name", {
value: "name",
configurable: true,
writable: true,
enumerable: true
});
(2)Object.defineProperties 与defineProperty类似,用于定义对象属性,不同之处在于可同时定义多个属性,用法如下:
var obj = {};
Object.defineProperty(obj, {
"name": {
value: "name",
configurable: true,
writable: true,
enumerable: true
},
"age": {
value: 20
}
});
(3)Object.getOwnPropertyDescriptor ES5提供读取特性值的方法,接收对象及属性名,返回对象,根据属性类型不同返回不同值。
var person = {
_age: 10,
type: "小孩"
}
Object.defineProperty(person, "age", {
get: function () {
return this._age;
},
set: function (newValue) {
this._age = newValue;
this.type = newValue > 17 ? "成人" : "小孩";
}
})
console.log(Object.getOwnPropertyDescriptor(person, "type"));//Object {value: "成人", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(person, "age")); //Object {enumerable: false, configurable: false, get: function(),set: function ()}
ES5新增Object方法与应用
Object的方法
ES5中Object新增一批方法,可直接通过Object访问,前文已用defineProperty。此外还有许多方法,归纳如下:
对象创建型方法
Object.create(proto, [propertiesObject])
前文提及创建对象有构造函数和字面量两种方法。 这两种方法的缺点是:创建多个对象时编写繁琐,故后来出现自定义构造函数法,如下所示:
function Person(name, age) {
this.name = name;
this.age = age;
}
var person = new Person("Jack", 15);
此方式方便创建多个同类对象,是目前常用方法。
ES5提供的Object.create方法也是创建对象的方式,允许为创建对象选择原型,无需定义构造函数。用法如下:
var obj = Object.create(Object.prototype, {
name: {
value: "Jack"
}
})
console.log(obj.name);//Jack
该方法首参作为被创建对象的原型,次参为对象属性。注意:此例中name属性不可修改,因未设writable特性,默认false。 个人看法:Object.create创建方式略显繁琐,除非需修改属性特性,否则不建议使用。
属性获取型方法
Object.keys
Object.keys用于获取给定对象所有可枚举的自身属性名,返回数组。
function Parent() {
this.lastName = "Black"
}
function Child(firstName) {
this.firstName = firstName;
}
Child.prototype = new Parent();
var son = new Child("Jack");
console.log(Object.keys(son));//["firstName"]
代码返回firstName,未返回从prototype继承的lastName及不可枚举属性。 在部分旧浏览器中,可使用hasOwnProperty和for...in达到类似效果。
Object.keys = Object.keys ||
function (obj) {
var keys = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
keys.push(key);
}
}
return keys;
}
Object.getOwnPropertyNames()
getOwnPropertyNames用于获取对象自身所有属性,包括可枚举和不可枚举,如下所示:
function Parent() {
this.lastName = "Black"
}
function Child(firstName) {
this.firstName = firstName;
}
Child.prototype = new Parent();
var son = new Child("Jack");
Object.defineProperty(son, "age", {
enumerable: false
})
console.log(Object.keys(son));//["firstName"]
console.log(Object.getOwnPropertyNames(son));//["firstName", "age"]
为son对象定义不可枚举属性age,通过keys和getOwnPropertyNames获取属性列表,可明显看出两者区别。
属性特性型方法
主要指前文提到的三个方法:defineProperty,defineProperties和getOwnPropertyDescriptor。
对象限制型方法
ES5提供一系列限制对象被修改的方法,防止因无意修改导致的错误。每种限制类型包含判断方法和设置方法。
阻止对象扩展
Object.preventExtensions()用于限制对象扩展,设置后对象无法添加新属性,用法如下:
代码如下:
Object.preventExtensions(obj);
该方法接收需设为不可扩展的对象作为参数,注意两点: 1、对象属性不可扩展,但已存在属性可被删除。 2、无法添加新属性指无法在自身添加,若在对象原型上仍可添加。
function Person(name) {
this.name = name;
}
var person = new Person("Jack");
Object.preventExtensions(person);
delete person.name;
console.log(person.name);//undefined
Person.prototype.age = 15;
console.log(person.age);//15
Object.isExtensible方法用于判断对象是否可扩展,默认true。
将对象密封
Object.seal可密封对象并返回被密封对象。 密封对象无法添加或删除已有属性,也无法修改属性的enumerable、writable、configurable,但可修改属性值。
function Person(name) {
this.name = name;
}
var person = new Person("Jack");
Object.seal(person);
delete person.name;
console.log(person.name);//Jack
密封对象后,使用delete删除对象属性,仍可访问得到属性。
通过Object.isSealed可判断对象是否被密封。
冻结对象
Object.freeze方法用于冻结对象,被冻结对象无法添加、修改、删除属性值,也无法修改属性特性,即对象不可被修改。
function Person(name) {
this.name = name;
}
var person = new Person("Jack");
Object.freeze(person);
delete person.name;
console.log(person.name);//Jack
Person.prototype.age = 15;
console.log(person.age);//15
分析代码发现,被冻结对象无法删除自身属性,但通过其原型对象仍可新增属性。
通过Object.isFrozen可判断对象是否被冻结。
可见:这三个限制对象方法的限制程度依次上升。
总结
Object虽是开发中最常用对象,但其诸多功能尚未被充分挖掘。本文首先介绍Object基本使用,接着介绍较少使用的属性特性,最后分析常用方法,尤其是ES5新增方法。欢迎大家交流!!
本文地址:http://luopq.com/2016/02/28/Object-in-Javascript/,转载请注明
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
为什么JS中typeof []返回object:数组类型检测误区解析
2026-11-04 19:50:47
