Object

432 阅读7分钟

Object

在JavaScript中,几乎所有的对象都是Object的实例,它们都会从Object.prototype继承属性和方法。(MDN定义)

我们在控制台打印一下Object (注意Object O是大写

console.dir(Object)  // ƒ Object() 
typeof Object // function
{}  instanceof Object  // true
[]  instanceof Object  // true
()=>{}  instanceof Object // true

Object()

Object本身是一个函数,可以当作工具方法使用,将任意值转为对象。这个方法常用于保证某个值一定是对象。如果参数为空(或者为undefined和null),Object()返回一个空对象。

var obj = Object();  // {}
// 等同于
var obj = Object(undefined);
var obj = Object(null);

obj instanceof Object // true

上面代码的含义,是将undefined和null转为对象,结果得到了一个空对象obj。

instanceof运算符用来验证,一个对象是否为指定的构造函数的实例。obj instanceof Object返回true,就表示obj对象是Object的实例。

如果参数是原始类型的值,Object方法将其转为对应的包装对象的实例。包装对象请参考我的这篇文章

var obj = Object(1); 相当于 var obj = new Number(1)
obj instanceof Object // true
obj instanceof Number // true

var obj = Object('foo'); 相当于 var obj = new String("foo")
obj instanceof Object // true
obj instanceof String // true

var obj = Object(true); 相当于 var obj = new Boolean(true)
obj instanceof Object // true
obj instanceof Boolean // true

上面代码中,Object函数的参数是各种原始类型的值,转换成对象就是原始类型值对应的包装对象。

如果Object方法的参数是一个对象,它总是返回该对象,即不用转换。

var arr = [];
var obj = Object(arr); // 返回原数组
obj === arr // true

var value = {};
var obj = Object(value) // 返回原对象
obj === value // true

var fn = function () {};
var obj = Object(fn); // 返回原函数
obj === fn // true

利用这一点,可以写一个判断变量是否为对象的函数。

function isObject(value) {
  return value === Object(value);
}

isObject([]) // true
isObject(true) // false

Object()总结:

  • 如果参数为 null 或 undefined或空字符串,将会创建并返回一个空对象
  • 如果传进去的是一个基本类型的值,则会构造其包装类型的对象
  • 如果传进去的是引用类型的值,仍然会返回这个值,返回的值和传进去的值有相同的引用地址

Object 构造函数

Object不仅可以当作工具函数使用,还可以当作构造函数使用,即前面可以使用new命令。 Object构造函数的首要用途,是直接通过它来生成新对象。

var obj = new Object();

注意,通过var obj = new Object()的写法生成新对象,与字面量的写法var obj = {}是等价的。或者说,后者只是前者的一种简便写法。

Object构造函数的用法与工具方法可以说是一模一样。使用时,可以接受一个参数,如果该参数是一个对象,则直接返回这个对象;如果是一个原始类型的值,则返回该值对应的包装对象

以下为MDN上的原话

当以非构造函数形式被调用时,Object 的行为等同于 new Object()。

var o1 = {a: 1};
var o2 = new Object(o1);
o1 === o2 // true

var obj = new Object(123);
obj instanceof Number // true

Object 的静态方法

所谓“静态方法”,是指部署在Object对象自身的方法。(只介绍常用)

Object.keys()

Object.keys方法用来遍历对象的属性。参数是一个对象,返回一个数组。该数组的成员都是该对象自身的(而不是继承的)所有属性名。Object.keys方法只返回可枚举的属性

var obj = {
  p1: 123,
  p2: 456
};

Object.keys(obj) // ["p1", "p2"]

想得到值 而不是属性名可以用 Object.values() 这个方法

Object.assign()

介绍浅拷贝中已经讲过 Object.freeze() 表示冻结一个对象,一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。

const obj = {
  prop: 42
};

Object.freeze(obj);

obj.prop = 33; // Throws an error 

console.log(obj.prop); // 42

Object.getPrototypeOf()

获取对象的原型(Prototype)对象。

let obj = {}
Object.getPrototypeOf(obj) === obj.__proto__

Object 的实例方法

除了静态方法,还有不少方法定义在Object.prototype对象。它们称为实例方法,所有Object的实例对象都继承了这些方法。

Object实例对象的方法,这里只介绍下面三个

  • Object.prototype.valueOf():返回当前对象对应的值。
  • Object.prototype.toString():返回当前对象对应的字符串形式。
  • Object.prototype.hasOwnProperty():判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性。

Object.prototype.valueOf()

valueOf方法的作用是返回一个对象的“值”,默认情况下返回对象本身。

var obj = new Object();
obj.valueOf() === obj // true

除了下面的例子,可以认为valueOf,都是返回对象的本身。

new Number(123).valueOf() // 123 
new String('abc').valueOf() // "abc" 
new Boolean(false).valueOf() // false

注意 new Boolean(false) 是一个包装对象,为true

valueOf方法的主要用途是,JavaScript 自动类型转换时会默认调用这个方法

var obj = new Object();
1 + obj // "1[object Object]"

上面代码将对象obj与数字1相加,这时 JavaScript 就会默认调用valueOf()方法,求出obj的值再与1相加。所以,如果自定义valueOf方法,就可以得到想要的结果。

var obj = new Object();
obj.valueOf = function () {
  return 2;
};

1 + obj // 3

上面代码自定义了obj对象的valueOf方法,于是1 + obj就得到了3。这种方法就相当于用自定义的obj.valueOf,覆盖Object.prototype.valueOf。

Object.prototype.toString()

toString方法的作用是返回一个对象的字符串形式,默认情况下返回类型字符串。

var o1 = new Object();
o1.toString() // "[object Object]"

var o2 = {a:1};
o2.toString() // "[object Object]"

上面代码表示,对于一个对象调用toString方法,会返回字符串[object Object],该字符串说明对象的类型。

字符串[object Object]本身没有太大的用处,但是通过自定义toString方法,可以让对象在自动类型转换时,得到想要的字符串形式。

var obj = new Object();

obj.toString = function () {
  return 'hello';
};

obj + ' ' + 'world' // "hello world"

上面代码表示,当对象用于字符串加法时,会自动调用toString方法。由于自定义了toString方法,所以返回字符串hello world。

注意:
数组、字符串、函数、Date 对象都分别部署了自定义的toString方法,覆盖了Object.prototype.toString方法。

[1, 2, 3].toString() // "1,2,3"

'123'.toString() // "123"

(function () {
  return 123;
}).toString()
// "function () {
//   return 123;
// }"

(new Date()).toString()
// "Tue May 10 2016 09:11:31 GMT+0800 (CST)"

上面代码中,数组、字符串、函数、Date 对象调用toString方法,并不会返回[object Object],因为它们都自定义了toString方法,覆盖了原始方法。

toString() 的应用:判断数据类型

Object.prototype.toString方法返回对象的类型字符串,因此可以用来判断一个值的类型。

由于实例对象可能会自定义toString方法,覆盖掉Object.prototype.toString方法,所以为了得到类型字符串,最好直接使用Object.prototype.toString方法。通过函数的call方法,可以在任意值上调用这个方法,帮助我们判断这个值的类型。

Object.prototype.toString.call(value)

上面代码表示对value这个值调用Object.prototype.toString方法。

不同数据类型的Object.prototype.toString方法返回值如下。

  • 数值:返回[object Number]。
  • 字符串:返回[object String]。
  • 布尔值:返回[object Boolean]。
  • undefined:返回[object Undefined]。
  • null:返回[object Null]。
  • 数组:返回[object Array]。
  • arguments 对象:返回[object Arguments]。
  • 函数:返回[object Function]。
  • Error 对象:返回[object Error]。
  • Date 对象:返回[object Date]。
  • RegExp 对象:返回[object RegExp]。
  • 其他对象:返回[object Object]。 这就是说,Object.prototype.toString可以看出一个值到底是什么类型。

Object.prototype.hasOwnProperty()

Object.prototype.hasOwnProperty方法接受一个字符串作为参数,返回一个布尔值,表示该实例对象自身是否具有该属性。

var obj = {
  p: 123
};

obj.hasOwnProperty('p') // true
obj.hasOwnProperty('toString') // false

上面代码中,对象obj自身具有p属性,所以返回true。toString属性是继承的,所以返回false。