静态方法
- 如何查看
console.dir(Object)
- 复制对象 并且返回目标对象,如果源对象1和源对象2有
重复属性(下标),后面会覆盖前面的 ,空元素不覆盖 - for..in 不能遍历到的就叫做不可枚举
- 不能复制不可枚举的属性和方法,不能复制原型和原型属性
Object.assign(目标对象,源对象1,源对象2...)
- 案例
var o1={a:1,b:3}
var o2={c:7,f:3}
var o3={...o1,...o2}
console.log(o3) // {a: 1, b: 3, c: 7, f: 3}
var a1=[1,2,3,4]
var a2=[6,7,8,4]
var a3=[...a1,...a2]
console.log(a3) // (8) [1, 2, 3, 4, 6, 7, 8, 4]
var b1=Object.assign([],[1,2,3,4],[7,8,9,0])
console.log(b1) // (4) [7, 8, 9, 0]
- 复制数组
var arr=[1,2,3,4,5];
var arr1=Object.assign([],arr);
// arr[0]=10; 不会改变原数组的值
console.log(arr1)
- 数组覆盖
var arr=[1,2,3,4,5];
var arr2=[6,7,8]
var arr1=Object.assign([],arr,arr2);
// arr[0]=10;
console.log(arr1) // 67845
var arr=[1,2,3,4,5,6]
var arr2=[,6,7,8]
var arr1=Object.assign([],arr,arr2)
arr[0]=10
console.log(arr1) // (6) [1, 6, 7, 8, 5, 6]
定义属性
- defineProperty :直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
- 基本使用
var o={}
Object.defineProperty(o,"c",{
value:3,
set:function(value){
// setter属性
},
get:function(){
//getter属性
}
})
console.log(o) // {c:3}
- enumerable:true 是否可以枚举
- configurable:true 是否可以删除或者修改对象该属性的描述对象
- writable:true 是否可以修改
Object.defineProperty(o,"c",{
configurable:true,
enumerable:true,
writable:false,
value:1
});
- setter和getter与value和writable冲突,使用setter和getter时不使用value和writable
- 如果configurable:false ,那么无法使用delete来进行删除
- 如果enumerable:false,不可枚举,控制台的颜色为浅色
- 如果writable:false,不可修改,这个对象的属性变成一个常量
- 当使用Object.keys 也无法获取不能枚举的key
// 默认所有的属性都是false
Object.defineProperty(o,"c",{
value:2
})
console.log(o)
- 设置多个属性
var o={}
Object.defineProperties(o,{
a:{
configurable:true, // 可删除
value:1
},
b:{
writable:true, // 可修改
value:2
},
c:{
enumerable:true, // 可枚举
value:3
}
})
console.log(delete o.a) // 删除o.a 属性
console.log(o.b=60) // 将o.b 修改为60
for(var key in o){
console.log(key)
}
entries
- 将对象转换为一个二维数组,里面的数组第0项是key,第1项是value
- 将对象转换为数组迭代器
var o={a:1,b:2};
console.log(Object.entries(o));
fromentries
- 将迭代器转换为对象 一种是二维数组,另一种是map类型
var o= Object.fromEntries([["a",1],["b",2]])
console.log(o) //{a: 1, b: 2}
var m=new Map();
m.set("a",1);
m.set("b",2);
var o=Object.fromEntries(m);
console.log(o)
freeze
- 冻结:不能添加属性,不能修改属性,不能删除属性
var o={a:1,b:2};
Object.freeze(o);
o.a=10;
console.log(o)
- 枚举类型创建
const Mouse_Event={
CLICK:"click",
MOUSE_DOWN:"mousedown",
MOUSE_UP:"mouseup",
MOUSE_ENTER:"mouseenter",
MOUSE_LEAVE:"mouseleave",
MOUSE_MOVE:"mousemove",
MOUSE_OUT:"mouseout",
MOUSE_OVER:"mouseover",
CONTEXT_MENU:"contextmenu"
}
Object.freeze(Mouse_Event);
Mouse_Event.CONTEXT_MENU=1
- 希望类里面不能更改数值,就将他使用冻结的方式设置为不可修改的只读模式
class Box{
static SPEED=3;
}
// 使用冻结的方式给类的静态属性设置为不可修改的只读模式
Object.freeze(Box);
Box.SPEED=4;
console.log(Box.SPEED)
- 判断是否被冻结
var o={a:1};
Object.freeze(o);
console.log( Object.isFrozen(o))
seal
- 密封的,不能添加新属性,也不能删除属性,但是可以修改属性值
var o={a:1,b:2};
Object.seal(o);
o.c=3;
delete o.a;
o.a=10;
console.log(o)
isSealed
- 判断对象是否是密封的
var o={r:3,d:5}
Object.seal(o)
console.log(Object.isSealed(o))
preventExtensions
- 设置对象禁止扩展,不能添加新属性,但是可以删除和修改属性
var o={a:1,b:2}
Object.preventExtensions(o);
o.c=3;
// delete o.a;
// o.a=10;
console.log(o)
isExtensible
- 判断对象是否禁止扩展
var o={a:10,b:20}
Object.preventExtensions(o)
console.log(Object.isExtensible(o))
易错点
- freeze(封闭):
isFrozen和isSealed是trueisExtensible是false - seal(密封):
isSealed是trueisExtensible,isFrozen是false
var o={a:1};
Object.freeze(o);//isFrozen和isSealed 是true isExtensible是false
// Object.seal(o);isSealed 是true isExtensible,isFrozen是false
console.log(Object.isFrozen(o));
获取所有对象的属性
- getOwnPropertyNames:获取对象的所有
key是字符串的对象属性(不管原型属性),包括不可枚举的属性
var o={};
Object.defineProperties(o,{
a:{
configurable:true,
value:1
},
b:{
writable:true,
value:2
},
c:{
enumerable:true,
value:3
}
})
// console.log(Object.keys(o))
// 获取对象的所有key是字符串的对象属性,包括不可枚举的属性
var names=Object.getOwnPropertyNames(o);
console.log(names) // a,b,c
- getOwnPropertySymbols:获取对象的所有symbol类型的对象属性,包括不可枚举属性
var o1={d:3,e:4}
var o=Object.create(o1);
Object.defineProperties(o,{
a:{
configurable:true,
value:1
},
b:{
writable:true,
value:2
},
c:{
enumerable:true,
value:3
},
[Symbol()]:{
value:4
}
})
var symbolNames=Object.getOwnPropertySymbols(o);
console.log(symbolNames) // [Symbol()]
- 通过Reflect方法获取对象的所有属性,什么类型都可以
console.log( Reflect.ownKeys(o)) // reflect是object对象的映射类型 // (4) ['a', 'b', 'c', Symbol()]
- getOwnPropertyDescriptor:获取对象指定属性的描述对象
var desc=Object.getOwnPropertyDescriptor(o,"a");
console.log(desc)
- 重新赋值
var o1 = { d: 3, e: 4 }
var o = Object.create(o1);
Object.defineProperties(o, {
a: {
configurable: true,
value: 1
},
b: {
writable: true,
value: 2
},
c: {
enumerable: true,
value: 3
},
[Symbol()]: {
value: 4
}
})
// 获取对象指定属性的描述对象
var desc=Object.getOwnPropertyDescriptor(o,"a")
// console.log(desc)
desc.writable=true
desc.value=10
Object.defineProperty(o,"a",{
configurable:desc.configurable,
writable:true, // 可以被修改,得到a:10
enumerable:desc.enumerable,
value:10
})
console.log(o) // {c: 3, a: 10, b: 2, Symbol(): 4}
- getOwnPropertyDescriptors:获取对象所有属性的描述对象
var descs=Object.getOwnPropertyDescriptors(o);
console.log(descs)
对象原型
- setPrototypeOf:设置对象原型为另一个原型
- Object.setPrototypeOf(目标对象,原型对象);
// Object.setPrototypeOf(目标对象,原型对象);
var o1={b:20,c:30};
var o={a:1};
// Object.setPrototypeOf(o1,o);
// console.log(o1)
- 要想修改原型就使用setPrototypeOf,不能直接使用proto
- getPrototypeOf:获取对象的原型对象
// 获取对象的原型对象
var o={a:1}
var o1=Object.create(o)
o1.b=2
console.log(o1.__proto__) // {a: 1}
// 获取o1的原型对象
console.log(Object.getPrototypeOf(o1)) //{a: 1}
- hasOwn/hasOwnProperty:判断对象下是否有这个对象属性,对象属性返回true,没有或者原型属性返回false
var o={a:1,b:2};
var o1=Object.create(o);
o1.c=3;
o1.d=4;
// 判断对象下是否有这个对象属性
console.log(Object.hasOwn(o1,"a"))
console.log(Object.hasOwn(o1,"c"))
console.log(o1.hasOwnProperty("c")) // 两者方法相同
- is:判断值是否是绝对相等,与===一样,可以比较NaN
var a=3;
var b="3";
console.log(Object.is(a,b))
- keys/value:不能获取原型上的值
var o={a:1,b:2};
var o1=Object.create(o);
o1.c=3;
o1.d=4;
console.log(Object.keys(o1)); // ['c', 'd']
console.log(Object.values(o1)); // [3, 4]
对象方法
-
constructor :实例化构造函数
-
hasOwnProperty :判断这个属性是不是对象的对象属性,原型属性返回false
-
isPrototypeOf :判断这个对象是否是另一个对象的原型
- 格式:原型对象.isPrototypeOf(对象)
var o={a:1,b:2};
var o1=Object.create(o);
o1.c=3;
o1.d=4;
// 判断o是否是o1的原型对象
console.log(o.isPrototypeOf(o1)) // T
console.log(o1.isPrototypeOf(o)) // F
- 判断原型内容
var div=document.createElement("div");
console.log(HTMLDivElement.prototype.isPrototypeOf(div)) // T
console.log(HTMLElement.prototype.isPrototypeOf(div)) // T
console.log(Element.prototype.isPrototypeOf(div)) // T
console.log(Node.prototype.isPrototypeOf(div)) // T
console.log(EventTarget.prototype.isPrototypeOf(div)) /// T
console.log(Object.prototype.isPrototypeOf(div)) // T
- propertyIsEnumerable :判断是否可枚举
var o={a:1,b:2}
Object.defineProperty(o,"c",{
value:3
})
console.log(o.propertyIsEnumerable("a")) // T
console.log(o.propertyIsEnumerable("c")) // F
setter和getter
- 属性不会执行多条语句,只能存储值
- 方法会执行多条语句,但是方法不能存储值
- 希望既可以像属性一样存储,也可以在存储值后执行多条语句
// 基本格式
var o={
_list:[],
set list(value){
console.log(value)
this._list=value;
},
get list(){
return this._list;
}
}
o.list=[1,2,3];
setter
设置 set的方法中有且只有一个参数获取 get的方法中不能有参数,并且必须使用 return 返回一个值
var o={
// 设置 set的方法中有且只有一个参数
set d(value){
console.log(value) // 10
},
// 获取 get方法中不能有参数,并且必须使用return 返回一个值
get d(){
return 1
}
}
// o.d(1);错误
o.d=10; // 等号后面的值会赋值给 set d(value) 中的value
console.log(o.d) // 1
var o={
_a:1,
set a(value){
console.log('aaaa') // aaa
this._a=value;
},
get a(){
return this._a;
}
}
o.a=10;
console.log(o.a) // 10
- 方块移动案例
<div></div>
<style>
div{
width: 50px;
height: 50px;
background-color: red;
position: absolute;
left: 0;
top: 0;
}
</style>
var div=document.querySelector('div')
div._x=0
div._y=0
// 直接在一个对象上定义新的属性或修改现有属性
Object.defineProperties(div,{
x:{
// 设置x的值
set(value){
// 这里的value值就是外面div传进来的值
this._x=value
// 左边的值就是value值
this.style.left=value+"px"
},
get(){
// 直接获取_x的值,返回上面得到的value数值
return this._x
}
},
y:{
set(value){
this._y=value
this.style.top=value+"px"
},
get(){
return this._y
}
}
})
setInterval(() => {
div.x++
}, 16);
- setter、getter 语法糖 访问器属性
- 数据驱动显示(set/get)
- 当只写了set方法时,这个属性不可读,只能设置
- 当只写了get方法时,这个属性只读,不能修改
- 把类的某个静态属性设置为只读属性
class Box{
// 由于书写了get方法,所以这个属性是只读属性
static get EVENT_ID(){
return "event_id";
}
}
console.log(Box.EVENT_ID)
Box.EVENT_ID="events" // 修改无效
- 数组也可以使用freeze:冻结!!!!无法修改
var arr=[1,2,3,4,5]
Object.freeze(arr)
arr[0]=10
// arr.push(3)
console.log(arr)
-
关于冻结的易错点
var o={ _list:[1,2,3,4,5], set list(value){ console.log(value,"aaa") this._list=value }, get list(){ return this._list } } Object.freeze(o.list) o.list=[2,3,4,5,6] // 更改引用地址,输出[2,3,4,5,6] o.list.push(6) // 冻结引用地址,报错,无法添加 Object.freeze(o) o.list=[1,2,3,4] // [1, 2, 3, 4] 'aaa' console.log(o.list) // [1, 2, 3, 4, 5] o.list.push(18) // [1, 2, 3, 4, 5, 18] o.list=o.list.concat(10) // [1, 2, 3, 4, 5, 10] 'aaa' o.list=o.list.slice(0,-1) // [1, 2, 3, 4] 'aaa'
对象深复制
function deepClone(source,list,target){
// 如果没有给入目标对象,创建一个新的目标对象
if(target===undefined){
switch(true){
// 如果要复制的对象是HTMLElement,则直接深复制Node
case source instanceof HTMLElement:
target=source.cloneNode(true);
break;
// 如果要复制的对象是类型化数组
case source.buffer && source.buffer instanceof ArrayBuffer:
// 如果要复制是日期对象
case source instanceof Date:
// 如果要复制的是正则
case source instanceof RegExp:
// 如果要复制是map
case source instanceof Map:
// 如果要复制的是set
case source instanceof Set:
// new 要复制对象的构造函数 例如 a=/a/g a.constructor-->Regexp b=new Regexp(a)
target=new source.constructor(source);
break;
case typeof source==="function":
var arr= source.toString().replace(/\n|\t/gi,"").match(/((.*?))\s*{(.*)}/i).slice(1);
target=new Function(arr[0].trim(),arr[1].trim())
break;
case !(source instanceof source.constructor):
// 如果要复制的是prototype对象,这个对象下自动会有一个constructor,我们创建这个prototype不能使用new constructor,所以直接创建一个对象
// 如果要复制是一个函数,使用正则表达式先把这个函数转换为字符串,并且删除所有换行,然后正则表达式通过群组提出参数和函数{}里面的内容
var arr= source.constructor.toString().replace(/\n|\t/gi,"").match(/((.*?))\s*{(.*)}/i).slice(1);
// 然后同new Function()将函数的参数和函数内容放入这里创建一个新函数
target=new Function(arr[0].trim(),arr[1].trim())
break;
default:
// 其他类型都是根据对象的构造函数创建
target=new source.constructor()
}
}
// 对象中如果出现互相引用关系的值,很容易出现迭代死循环,我们创建一个map用了存储,原值和目标值
if(list===undefined){
list=new Map();
// 先把当前这个对象的原值和目标值存储
list.set(source,target);
}
// 获取源对象下所有属性
var keys=Reflect.ownKeys(source);
// 遍历所有属性
for(var i=0;i<keys.length;i++){
// 获取当前这个属性的属性描述对象
var desc=Object.getOwnPropertyDescriptor(source,keys[i]);
// 判断这个属性描述对象是不是引用类型,并且不是null
if(desc.value instanceof Object && desc.value!=null){
var targetValue;
// 判断如果这个源对象在列表已经存在,就将列表中已经复制的模板对象直接复制
if(list.has(desc.value)){
targetValue=list.get(desc.value);
}else{
// 如果不存在,判断是不是constructor,是constructor跳出
if(keys[i]==="constructor"){
continue;
}
// 深 复制一个新的目标对象
targetValue= deepClone(desc.value,list);
// 判断是否是原型,如果是原型,这个创建一个构造函数放在里面
if(keys[i]==="prototype"){
Object.defineProperty(targetValue,"constructor",{
value:targetValue
})
}
// 将当前的源对象和创建出的目标存储在map中
list.set(desc.value,targetValue);
}
// 定义当前目标对象中的对应属性的值
Object.defineProperty(target,keys[i],{
configurable:desc.configurable,
writable:desc.writable,
enumerable:desc.enumerable,
value:targetValue
})
}else{
// 非引用类型值直接赋值
Object.defineProperty(target,keys[i],desc);
}
}
return target;
}