Object 构造函数创建一个对象包装器。
在 JavaScript 中,几乎所有的对象都是 Object 类型的实例,都会从 Object.prototype 继承属性和方法。
语法
-
对象初始化器(Object initialiser)或对象字面量(literal)
{ key1: value1, key2:value2, ... }
-
以构造函数形式调用
var obj = new Object([value])
根据传入的value的类型,创建的对象有一下几种情况:
- value 为 null 或 undefined 时,创建并返回一个空对象。
var o1 = new Object() var o2 = new Object(undefined) var o3 = new Object(null)
- value 为基本数据类型的值,则会构造其包装类型的对象。
var bo = new Object(true) // 等价于 var bo = new Boolean(true)
- value 为引用类型的,仍然会返回这个值,并且这个值和原值一样都指向同一个引用地址。
- value 为 null 或 undefined 时,创建并返回一个空对象。
属性
Object.length
其值为1。
Object.prototype
Object.prototype属性是一个对象类型,在该对象上添加属性可以为所有的 Object 类型的对象添加属性(无论是之前还是之后创建的对象)。
JavaScript中的所有对象都来自 Object,所有对象从 Object.prototype 继承方法和属性,Object.prototype 的更改将传播到所有对象。
Object.prototype 的属性有:
Object.prototype.constructor
用于创建一个对象的原型,返回Object构造函数的引用,而不是一个包含函数名称的字符串。
所有对象都会从它的原型上继承一个 constructor 属性
var o1 = {}
var o2 = new Object()
o1.constructor === o2.constructor === Object // true
var arr1 = []
var arr2 = new Array()
arr1.constructor === arr2.constructor === Array // true
var n1 = new Object(1)
var n2 = new Number(1)
n1.constructor === n2.constructor === Number // true
var s1 = new Object('s')
var s2 = new String('s')
s1.constructor === s2.constructor === String // true
var b1 = new Object(true)
var b2 = new Boolean(true)
b1.constructor === b2.constructor === Boolean
Object.prototype.hasOwnProperty()
判断一个对象自身是否含有指定的属性,而且该属性 不是从原型链上继承的。
语法:obj.hasOwnProperty(prop)
Object.prototype.isPrototypeOf()
判断一个对象是否存在于另一个对象的原型链上。
语法:prototypeObj.isPrototypeOf(Object)
Object.prototype.propertyIsEnumerable()
判断指定的自身(非通过原型链继承)属性是否可枚举。
语法:obj.propertyIsEnumerable(prop)
Object.prototype.toLocaleString()
返回一个对象的字符串表示。
语法:obj.toLocaleString()
Object.prototype.toString()
返回一个对象的字符串表示。
语法:obj.toString()
所有对象都能转换为 [object 类型] 的格式。
Object.prototype.valueOf()
返回指定对象的原始值。
语法:obj.valueOf()
如果对象没有原始值,则返回对象本身。
JavaScript的内置对象基本都重写了该方法,对应的返回值如下表所示:
对象 | 返回值 |
---|---|
Boolean | 布尔值 |
Number | 数字值 |
String | 字符串 |
Array | 返回数组对象本身 |
Date | 存储的事件是1970年1月1日午夜开始计的毫秒数UTC |
Object | 对象本身 |
Function | 函数本身 |
Math和Error对象没有valueOf方法。
Object.prototype.__proto__
指向Object的实例的原型对象。
方法
创建对象方法
Object.assign(target, ...sources)??:
通过复制一个或多个源对象的自身可枚举属性分配到目标对象上,并返回目标对象。
如果目标对象中有相同的属性,则目标对象的该属性会被源对象的属性覆盖,后面的源对象属性覆盖前面的源对象属性。
该方法使用到源对象的[[Get]]和目标对象的[[Set]],会调用相关的getter和setter。
特点:
- 只有字符串的包装对象才有自身可枚举的属性,才能被被包装成对象后再进行拷贝。
- null和undefiend会被忽略。
- 再拷贝时属性时引用类型的只会拷贝该引用,也称浅拷贝。
- 异常会打断后续的拷贝任务。
一个Polyfill实现(不支持Symbol):
if (typeof Object.assign !== 'function') {
// Object.assign必须是可写、不可枚举和可配置的
Object.defineProperty(Object, 'assign', {
value: function assign(target, varArgs) {
'use strict'
if (target === null || target === undefined) {
throw new TypeError('不能把null和undefined转换为对象')
}
var to = Object(target)
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index]
if (nextSource !== null && nextSource !== undefined) {
for (var nextKey in nextSource) {
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey]
}
{
}
}
return to
},
writable: true,
configurable: true
})
}
拷贝访问器:
function completeAssign(target, ...sources) {
sources.forEach(source => {
let descriptors = Object.keys(source).reduce((descriptor, key) => {
descriptors[key] = Object.getOwnPropertyDescriptor(source, key)
return descriptors
})
// Object.assign 默认会拷贝可枚举的Symbols
Object.getOwnPropertySymbols(source).forEach(sym => {
let descriptor = Object.getOwnPropertyDescriptor(source, sym)
if (descriptor.enumerable) {
descriptors[sym] = descriptor
}
})
Object.defineProperties(target, descriptors)
})
return target
}
Object.create()
使用指定的原型对象和属性创建一个新对象.
语法:Object.create(proto, [propertiesObject])
参数解析:
- 第一个参数proto,充当新对象的原型对象;
- 第二个参数propertiesObject的属性类型按照Object.defineProperties()的第二个参数来把 自身可枚举属性 配置到新对象上,包括 属性值和对应的属性描述符。
实现类式继承:
function Shape(x, y) {
this.x = 0
this.y = 0
}
Shape.prototype.move = function(x, y) {
this.x += x
this.y += y
}
function Rectangle() {
super.call(this)
}
Rectangle.prototype = Object.create(Shape.prototype)
Rectangle.prototype.constructor = Rectangle
var rect = new Rectangle()
rect instanceOf Rectangle // true
rect instanceOf Shape // true
继承多个对象:
function MyClass() {
SuperClass.call(this)
OtherSuperClass.call(this)
}
// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype)
// 混合其他
Object.assign(MyClass.prototype, OtherSuperClass.prototype)
// 重新指定constructor
MyClass.prototype.constructor = MyClass
设置/获取属性及其配置的方法
Object.defineProperty()
给对象添加/修改一个属性并指定该属性的配置,并返回该对象。
语法:Object.defineProperty(obj, propName, descriptor)
参数解析:
- obj 是要定义属性的对象
- propName 是要定义或修改的属性名或Symbol
- descriptor 要定义或修改的属性描述符
通过 赋值操作 添加的是普通属性是可枚举的,在枚举对象属性时会被枚举到 for..in 或 Object.keys,可以改变这些属性的值,也可以删除这些属性。
而 Object.defineProperty() 可以修改属性配置信息,但是默认情况下,Object.defineProperty() 添加的属性值是不可以修改的。
属性描述符有两种:
- 数据描述符:对象类型,是一个具有值的属性,该值可以是可写的,也可以是不可写的。
- 访问器描述:对象类型,由 getter函数 和 setter函数 所描述的属性。
两种描述符 都有 以下2个 可选的 属性:
- configurable:默认false。当且仅当值为true时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上删除。
- enumerable:默认false。当且仅当值为true时,该属性才会出现在对象的枚举属性中。
数据描述符 还有以下2个 可选的 属性:
- writable:默认false。当且仅当值为true时,属性的 (下面的)value 才能赋值运算符改变。
- value:属性值,默认undefined。可以是任何有效的JavaScript值。
访问器描述符 还有以下2个 可选的 属性:
- get:属性的getter函数,默认undefined。当访问属性时会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的 this 并不一定是定义该属性的对象。该函数的返回值会被用作属性的值。
- set:属性的setter函数,默认undefined。当属性的值被修改时会调用此函数。该方法接收一个参数(也是被赋予的新值),并传入赋值时的this对象。
备注:
- 描述符属性不一定是自身的属性,也可以能是继承来的属性。
- 应当直接调用Object.defineProperty(),而不是调用Object的实例的defineProperty()方法。
- 在ES6中,Object.defineProperty() 是定义key为Symbol类型的方法之一。
Object.defineProperties()
给对象添加多个属性并分别指定他们的配置。
Object.getOwnPropertyDescriptor()
返回对象指定的属性配置。
获取对象属性及属性值的方法
Object.entries()
返回给定对象自身可枚举属性的 [key,value] 数组。
Object.keys(arg)
返回一个 字符串数组,包含给定对象自身(非继承的)可枚举的属性名称 。
返回值数组的元素的顺序和for...in循环的循序相同,按升序输出。
在ES5中,如果arg不是一个对象(原始值),则会抛出 TypeError。在ES中,则会将非对象参数强制转换为对象在调用。for...in遍历对象的可枚举属性,包含继承的可枚举属性。
Object.keys()的Polyfill写法:
if (!Object.keys) {
Object.keys = (function() {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumbBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('在非对象上调用Object.keys')
var result = []
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop)
}
}
// 如果存在枚举属性bug,则把不可枚举的属性也输出
if (hasDontEnumbBug) {
for (var i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i])
}
}
}
return result
}
})
}
Object.values()
返回一个数组,包含给定对象自身(非继承)可枚举的属性值,该数组元素的顺序和for...in循环的循序相同。
当传入一个非对象参数时,会强制转换成对象再进行调用。
Object.values('abc') // 返回 ['a', 'b', 'c']
当传入的类数组时,且类数组的key值时数值类型,当生成的数组元素顺序按数字key的升序输出。
Object.values({2: 'aa', 1: 'bb', 3: 'cc'} // 返回 ['bb', 'aa', 'cc']
Object.values()的Polyfill写法:
if (!Object.values) {
Object.values = function(obj) {
if (obj !== Object(obj)) {
throw new TypeError('请传入一个对象参数')
}
var values = [], key
for (key in obj) {
if(Object.prototype.hasOwnProperty.call(obj, key)) {
values.push(obj[key])
}
}
return values
}
}
Object.getOwnPropertyNames()
返回一个数组,它包含了指定对象所有 可枚举或不可枚举 的属性名。
Object.getOwnPropertySymbols()
返回一个数组,包含了指定对象自身所有的 符号(Symbol) 属性。
对象不可用的方法
Object.freeze()
冻结对象,其他代码不能删除或更改任何属性。
Object.isFrozen()
判断对象是否以冻结。
Object.isExtensible()
判断对象是否可扩展。
Object.isSealed()
判断对象是否已经密封。
Object.preventExtensions()
防止对象的任何扩展。
Object.seal()
防止其他代码删除对象的属性。
原型对象的方法
Object.getPrototypeOf()
返回指定对象的原型对象。
Object.setPrototypeOf()
设置对象的原型(即设置对象的prototype属性)。
比较的方法
Object.is()
比较两个值是否相同,所有的NaN值都相等。