JavaScript中的 Object 类型

 2016年06月02日    93     声明


在ECMAScript中,Object是一个特殊的对象。它本身是一个顶级对象,同时还是一个构造函数,可以通过它(如:new Object())来创建一个对象。我们可以认为JavaScript中所有的对象都是Object的一个实例。


  1. Object类型与对象的定义
  2. Object类型的属性和方法

1. Object类型与对象的定义

对象是一个包含键/值对的集合。ECMAScript提供了两种创建创建对象的方式:构造函数创建字面量创建。构造函数创建是指使用new Object()的方式创建,而字面量创建是指使用{}创建。示例如下:

// 使用构造函数创建对象
var obj = new Object({key:'a value'});

// 使用构造函数创建对象后,再添加属性
var obj1 = new Object();
obj1.key = 'a value';

// 使用字面量创建
var obj2 = {
  key: 'a value'
};

// 字面量也可以使用以下形式
var obj3 = {};
obj3.key = 'a value';

使用构造函数创建对象时,如果不需要传递还可以省略括号:

var obj = new Object;

从以上几种形式可以看出,使用字面量的形式创建对象更为简洁,这也是比较推荐的一种使用方式。


2. Object类型的属性和方法

在面向对象编程中,属性和方法有两种:类方法(属性)实例方法(属性)。类方法一般是指静态方法,是只能通过类名调用的方法,如:Object.key()。而实例方法是只能在实例化后,通过实例名调用的方法,如:obj.valueOf()。虽然Object并不是严格意义上的类,但它也有这两种方法/属性,Object的实例方法可以被继承,可以其实例及子对象的实例中调用;而其类方法,只能通过Object来调用。

2.1 实例属性与方法

ECMAScript基于原型链-prototype实现对象的继承,我们所说实例属性/方法就是指定prototype上的属性/方法。而Object是所有对象的父对象,它的实例属性与方法也同时存在于所有的对象的实例中。

Object的实例属性/方法如下:

  • Object.prototype.constructor - 对象的构造函数。前面使用new创建对象时,其构造函数是Object()
  • Object.prototype.hasOwnProperty(propName) - 返回一个布尔值。用于检查给定的属性是实例属性,而非从原型链继承的属性。
    var o = new Object();
    o.site = 'itbilu.com';
    o.hasOwnProperty('site');             // 返回 true
    o.hasOwnProperty('toString');         // 返回 false,toString继承自Object
  • Object.prototype.isPrototypeOf(object) - 返回一个布尔值。用于检查给定的对象是否在原型链上
  • Object.prototype.propertyIsEnumerable(propName) - 判断对象属性是否是可枚举的
  • Object.prototype.toLocaleString() - 返回对象的字符串表示,即:调用Object.prototype.toString()
  • Object.prototype.toString() - 返回对象的字符串表示
  • Object.prototype.valueOf() - 返回对象的原始值


2.2 类属性与方法

Object中有几个类方法,这些方法可实现对象继承、属性添加/修改等,在JavaScript编程中这些属性/方法会经常使用,通过这些方法可以实现类似Java等高级语言中的一些面向对象特征。

Object.assign()-复制多个对象属性到新对象

Object.assign()方法可以把任意多个的源对象自身的可枚举属性(enumerable=true)拷贝给目标对象,然后返回目标对象。

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

详细介绍请参考:JavaScript 对象属性拷贝

Object.create()-通过对象原型创建新对象

Object.create()方法用于通过对象原型来创建新对象,这样我们就可以通过个方法来实现的JavaScript对象的继承。

详细介绍请参考:Object.create()方法实现对象继承与创建新的JavaScript对象

Object.defineProperty()-为对象添加或修改属性

Object.defineProperty()用于为对象添加一个属性或修改已存在的属性。

详细介绍请参考:Object.defineProperty()定义/修改属性

Object.defineProperties()-添加或修改多个对象属性

Object.defineProperties()Object.defineProperty()方法的批量操作。

详细介绍请参考:Object.defineProperties()定义/修改多个属性

Object.freeze() - 冻结对象

Object.freeze()用于冻结对象,是将对象设置为不能添加新属性、不能修改已有属性的值、不能删除已有属性,且不能修改已有属性的可枚举性、可配置性、可写性。

var obj = {
  prop: function (){},
  foo: "bar"
};

// 对象冻结前,可以添加新的属性,也可以修改或删除已有属性
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;

var o = Object.freeze(obj);

assert(Object.isFrozen(obj) === true);  // true

// 冻结后所有修改操作都会失败
obj.foo = "quux"; // 静默失败
obj.site = "http://itbilu.com"; // 静默失败,并没有成功添加上新的属性

// 而在严格模式中,以上操作会抛出TypeError异常

Object.getOwnPropertyDescriptor() - 返回对象属性描述

该方法用于返回对象自有属性的描述,属性描述包括:configurableenumerablewritablevaluegetset。自有属性指那些不是从原型链上继承的属性。

Object.getOwnPropertyDescriptor(obj, prop)

如,可以下面这样返回对象属性描述:

var o, d;

o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
// d is { configurable: true, enumerable: true, get: /*访问器函数*/, set: undefined }

o = { bar: 42 };
d = Object.getOwnPropertyDescriptor(o, "bar");
// d is { configurable: true, enumerable: true, value: 42, writable: true }

o = {};
Object.defineProperty(o, "baz", { value: 8675309, writable: false, enumerable: false });
d = Object.getOwnPropertyDescriptor(o, "baz");
// d is { value: 8675309, writable: false, enumerable: false, configurable: false }

Object.getOwnPropertyNames() - 返回对象自身的所有属性名

返回对象自身的所有属性名组成的数组,包括不可枚举属性。

Object.getOwnPropertyNames(obj)
var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]

var obj = { 0: "a", 1: "b", 2: "c"};
console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]

Object.getPrototypeOf() - 返回对象的原型属性

返回对象的原型属性,即从原型链继承的属性

Object.getPrototypeOf(object)

使用示例:

var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true

Object.is() - 返回两个值是否严格相等

这个方法是ECMAScript 2015中新增的方法,两个值是否严格相等,其与===操作符类似。示例如下:

Object.is('foo', 'foo');     // true
Object.is(window, window);   // true

Object.is('foo', 'bar');     // false
Object.is([], []);           // false

var test = { a: 1 };
Object.is(test, test);       // true

Object.is(null, null);       // true

// 两个特例,=== 也没法判断的情况
Object.is(0, -0);            // false
Object.is(NaN, 0/0);         // true

Object.isExtensible() - 判断对象是否是可扩展的

Object.isExtensible()用于判断对象是否是可扩展的,即:是否可向其添加新属性。

// 新对象默认是可扩展的.
var empty = {};
Object.isExtensible(empty); // === true

// ...可以变的不可扩展.
Object.preventExtensions(empty);
Object.isExtensible(empty); // === false

// 密封对象是不可扩展的.
var sealed = Object.seal({});
Object.isExtensible(sealed); // === false

// 冻结对象也是不可扩展.
var frozen = Object.freeze({});
Object.isExtensible(frozen); // === false

Object.isFrozen() - 判断对象是否已冻结

判断对象是否已冻结,使用Object.freeze()冻结对象后,该方法将返回true

// 一个对象默认是可扩展的,所以它也是非冻结的.
assert(Object.isFrozen({}) === false);

// 一个不可扩展的空对象同时也是一个冻结对象.
var vacuouslyFrozen = Object.preventExtensions({});
assert(Object.isFrozen(vacuouslyFrozen) === true);

// 一个非空对象默认也是非冻结的.
var oneProp = { p: 42 };
assert(Object.isFrozen(oneProp) === false);

Object.isSealed() - 判断对象是否已密封

判断对象是否已密封,使用Object.seal()密封对象后,该方法将返回true,密封对象不能删除属性

// 新建的对象默认不是密封的.
var empty = {};
Object.isSealed(empty); // === false

// 如果你把一个空对象变的不可扩展,则它同时也会变成个密封对象.
Object.preventExtensions(empty);
Object.isSealed(empty); // === true

Object.keys() - 返回对象所有可遍历的属性名

该方法会返回一个数组,其中包含对象的所有可遍历属性的名称

var arr = ["a", "b", "c"];
alert(Object.keys(arr)); // 弹出"0,1,2"

// 类数组对象
var obj = { 0 : "a", 1 : "b", 2 : "c"};
alert(Object.keys(obj)); // 弹出"0,1,2"

// getFoo是个不可枚举的属性
var my_obj = Object.create({}, { getFoo : { value : function () { return this.foo } } });
my_obj.foo = 1;

alert(Object.keys(my_obj)); // 只弹出foo

Object.preventExtensions() - 阻止对象扩展

该方法用于设置对象不可扩展,设置后Object.isExtensible()将返回false

Object.seal() - 密封对象

在防止对象属性被删除时我们可以使用Object.seal()方法将对象密封

Object.setPrototypeOf() - 设置对象原型

这个方法是ECMAScript 2015(ES6)规范中新增的方法,用于设置对象的原型

Object.setPrototypeOf(obj, prototype)