详解JavaScript中的Object对象:从基础到ES5高级特性

作者:木棉时间:2026-10-29 22:33:38浏览:208

本文深入解析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/,转载请注明

作者最新文章