前言
关于 JavaScript 对象的知识比较广泛,本文只介绍整理了关于 Object构造器 方法的相关操作,同样基础重要,希望能帮助到你。
Object 构造器方法
创建对象
create
create 方法可以创建一个对象实例,并为其指定原型对象和属性。
/**
* prototype:必需,被创建对象的原型对象。
* descriptors:可选,包含一个或多个属性描述符的 JavaScript 对象。
**/
Object.create(prototype, descriptors)
let obj=Object.create(null,{
webName:{
value:"魔鬼鱼"
}
});
console.log(obj.webName); // 魔鬼鱼
console.log(obj.__proto__); // undefined
Object.create() 可以用来实现单一继承。
assing
assign 方法用于对象的合并,将源对象的所有可枚举属性,复制到目标对象。
// 源对象: 可以有多个。
Object.assing('目标对象','源对象')
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
需要注意的地方:
- assign方法实行的是浅拷贝,不会进行深拷贝。
- 一旦遇到同名属性,assign的处理方法是替换,而不是添加。
其他用途:
- 为对象添加属性。
- 为对象添加方法。
- 克隆对象。
Object.assign()
可以用来实现多重继承。
操作对象属性
defineProperty
添加或修改一个对象的多个属性,并返回此对象。
/**
* obj 必需,要定义属性的对象。
* prop 必需,要定义或修改的属性的名称或 Symbol 。
* descriptor 必需,要定义或修改的属性描述符。
*/
Object.defineProperty(obj,prop,descriptor)
let myObj = {};
Object.defineProperty( myObj, "a", {
value: 2,
writable: true,
configurable: true,
enumerable: true,
get:function(){},
set:function(){}
});
myObj.a; // 2
Vue
中的双向数据绑定实现原理就是基于这个完成的,不过在 vue3.0
中已经改用了 Proxy
。
defineProperty
有什么缺陷?为什么 Vue3.0
采用了 Proxy
?
- Object.defineProperty无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;
- Object.defineProperty只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy可以劫持整个对象,并返回一个新的对象。
- Proxy不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。
defineProperties
Object.defineProperty
方法一次只能为对象添加或者修改一个属性,在实际应用中,可能需要进行批量操作, Object.defineProperties
可以实现,使用方法基本与 Object.defineProperty
方法相同。
let obj = {
webName:"魔鬼鱼",
url:"softwhy.com"
};
Object.defineProperties(obj,{
address:{
value:"沈阳市皇姑区",
writable:true,
numerable:true,
configurable:true
},
age:{
value:2,
writable:true,
numerable:true,
configurable:true
}
});
console.log(obj.address); // 沈阳市皇姑区
console.log(obj.age); // 2
获取对象属性信息
keys
遍历自身的可枚举属性, 返回数组,不会遍历原型链上的属性以及 Symbol 属性。
Object.keys(对象||数组)
let obj = {
webName: "魔鬼鱼",
url: "https://chomper.online/",
address:"沈阳市皇姑区",
func:function(){
//code
}
}
console.log(Object.keys(obj)); // ["webName", "url", "address", "func"]
console.log(Object.keys(["webName", "url", "address", "func"])) // ["0", "1", "2", "3"]
getOwnPropertyDescriptor
如果prop属性存在对象obj上,则返回其属性描述符,如果不存在就返回undefined。
Object.getOwnPropertyDescriptor(obj,prop)
let antzone={
webName:"魔鬼鱼",
age:4
}
let descriptor=Object.getOwnPropertyDescriptor(antzone,"webName");
console.log(descriptor); // {value: "魔鬼鱼", writable: true, enumerable: true, configurable: true}
etOwnPropertyNames
返回一个数组,它包含了指定对象所有的可枚举或不可枚举的属性名。
let antzone={
webName:"魔鬼鱼",
age:6
}
Object.defineProperty(antzone, "url", {
value: "https://chomper.online/",
enumerable: false
});
console.log(Object.getOwnPropertyNames(antzone)); // ["webName", "age", "url"]
getPrototypeOf
返回对象的原型对象,如果没有的话,则返回null。
function Antzone(){
this.webName="魔鬼鱼";
this.url="chomper.onilne";
}
Antzone.prototype={
age:22,
address:"沈阳市"
}
let antzone=new Antzone();
console.log(antzone) // {webName: "魔鬼鱼", url: "chomper.onilne"}
console.log(Object.getPrototypeOf(antzone)); // {age: 22, address: "沈阳市"}
对于函数对象,其返回的并不是显式原型(prototype),而是隐式原型(proto)。
getOwnPropertySymbols
返回对象上自身的(非继承的)所有Symbol属性键。
扩展对象
preventExtensions
让一个对象永远不能添加新的属性,在严格模式下,如果强行为对象添加属性,会报错。
"use strict";
var obj = {name:"zhang"};
obj.name = "li"// 可以进行修改
Object.preventExtensions(obj); // obj.age = 14;严格模式下会报错
obj.__proto__.age = 13;
console.log(obj); // 能够在原型对象上添加属性
obj.__proto__ = {} // 不能直接重定义原型,会报错。
isExtensible
判断一个对象是否可扩展。
let antzone={
webName:"魔鬼鱼",
url:"chomper.onilne"
}
console.log(Object.isExtensible(antzone)) // true 表示可以继续扩展属性
Object.preventExtensions(antzone);
console.log(Object.isExtensible(antzone)) // false 表示以后不可以扩展属性
密封对象
seal
对一个对象进行密封,并返回被密封的对象,这些对象都是不能够添加属性,不能删除已有属性,以及不能够修改已有属性的可枚举型、可配置型、可写性。
let antzone = {
webName: "魔鬼鱼",
age:4,
address:"沈阳市"
};
Object.seal(antzone);
antzone.age = 5;
console.log(antzone.age) // 5
注意:直接量方式创建的属性即使密封后,还是可读写的,但是添加属性无效,不会报错,但在严格模式下会报错。
isSealed
判断一个对象是否是密封的。
let antzone = {
webName:"魔鬼鱼",
age:4,
address:"沈阳"
};
console.log(Object.isSealed(antzone)); // false
冻结对象
freeze
该方法将obj对象冻结,其任何属性都是不可以被修改的。
let obj = {
webName: "魔鬼鱼",
age:4
};
Object.freeze(obj);
obj.address="沈阳";
console.log(obj.address); // undefined
注意:可以看到obj对象冻结之后,为它扩展属性虽然没有报错,但是并未成功,如果在严格模式下执行扩展操作,会报错。
isFrozen
判断一个对象是否已经被冻结。
let antzone = {
webName: "魔鬼鱼",
url:"chomper.online"
}
Object.freeze(antzone);
console.log(Object.isFrozen(antzone)); // true
密封、冻结、扩展之间的区别
三个方法都是对 对象进行读写状态的控制,防止对象被改变,最弱一层是preventExtensions(扩展)
,只能让对象无法添加新的属性,其次是seal(密封)
,该方法无法添加属性,也无法删除属性,最后是freeze(冻结)
。
数据属性与访问器属性
在 javaScript 中,对象的属性分为两种类型:数据属性 和 访问器属性。
在学习 Object构造器 方法前必须了解的知识,上面的属性描述符,指的就是数据属性与访问器属性,在我们操作对象的过程中常会用到。
数据属性
value
设置属性的值,默认undefined。
writable
是否可以修改属性的值,默认true;
enumerable
是否可以通过for in循环返回(枚举),默认true;
configurable
能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性,默认为true。
访问器属性
get
在读取属性时调用的函数,默认为undefined。
set
在写入属性时调用的函数,默认为undefined。
其他常用操作
Object.create(null)
当你需要一个非常干净且高度可定制的对象当作数据字典的时候,请使用 Object.create(null)
,其他时候请使用字面量的方式。
create(null)、字面量、new Object 三者的区别是什么?
- 字面量和
new
关键字创建的对象是Object
的实例,原型指向Object.prototype
,继承内置对象Object
。 - Object.create(arg, pro)创建的对象的原型取决于arg,arg为null,新对象是空对象,没有原型,不继承任何对象;arg为指定对象,新对象的原型指向指定对象,继承指定对象。
JavaScript 对象分类
俗话说 JavaScript 万物皆对象,对新人来说并不友好,我现在仍然觉得 JavaScript 的对象概念有些混乱,不过 JavaScript 的对象也是有分类的,这里我就简单介绍下。
宿主对象
宿主对象,由 JavaScript 宿主环境提供的对象,或者说就是 javascript 运行的地方提供的对象,比如浏览器环境中的 Window 对象。
内置对象
内置对象,是由 JavaScript 语言提供的对象,内置对象分为:普通对象、原生对象、固有对象。
普通对象
Object 构造器创造出的对象为普通对象,字面量创造出的对象也是普通对象。
原生对象
JavaScript 标准中,提供了 30 多个构造器,盗用一张大佬的图,自己领会。

固有对象
有对象在任何 JavaScript 代码执行前就已经被创建出来了,它们通常扮演者类似基础库的角色,它会随着 JavaScript 运行时创建而自动创建的对象实例。
结尾
我一直认为模仿和借鉴是学习一个新东西最高效的方法,作为一名开发者,你需要时刻保持警惕,有危机意识,有持续学习的能力。
如果这篇文章帮助到了你,欢迎点赞和关注,搜索《海洋里的魔鬼鱼》加入我们的技术群一起学习讨论,共同探索前端的边界。
