你应该知道的关于Object的一些方法
前言
最近接触了一下vue3里面的关于方法的源码,里面用到了很多对象的方法,看着里面的一些方法,所以就想着一边理解一边学习,希望理解知识点并且以后再次看的时候印象更深刻。想着按照增删改这种方式来学习,也方便记忆。下面是一些看vue3源码里面需要用到的object方法。
在 JavaScript 中,几乎所有的对象都是 Object
类型的实例,它们都会从 Object.prototype
继承属性和方法,虽然大部分属性都会被覆盖(shadowed)或者说被重写了(overridden),Object
还可以被故意的创建,但是这个对象并不是一个“真正的对象”。
对象初始化(增)
可以通过new Object()
,Object.create()
等方法,或者使用字面量标记(初始化标记)初始化对象。
-
构造函数
new Object() ,构造函数将给定的值包装为一个新对象- 如果给定的值是
null
或undefined
, 它会创建并返回一个空对象
- 如果给定的值是
let emptyObject = new Object() // {}
let emptyObject = new Object(undefined) // {}
let emptyObject = new Object(null) // {}
const valueObject1 = new Object({"name":"沐阳vae"})
console.log(valueObject1) //{name: '沐阳vae'}
const valueObject2 = new Object()
valueObject.name = "沐阳"
console.log(valueObject2) // {name: '沐阳'}
-
静态方法
1,Object.assign
语法:
Object.assign(target, ...sources)
,不会在sources
对象值null或undefined时抛出错误const target = { a: 1, b: 2 }; const source = { b: 4, c: 5 }; const returnTarget = Object.assign(target, source); console.log(target) // {a: 1, b: 4, c: 5} console.log(returnTarget) // {a: 1, b: 4, c: 5} console.log(source) //{ b: 4, c: 5 }
Object.assign()通过复制一个或多个对象来创建一个新的对象,
Object.assign()
复制创建出来的对象是浅拷贝的,只会复制属性值。假如源对象是一个对象的引用,它只会复制其引用值。let obj = {a: 1, b: { c: 0}} let newObj = Object.assign({}, obj) console.log(newObj) // {a: 1, b: { c: 0}} ,浅拷贝,复制的是引用值,a复制的是1,b复制的就是引用地址了。 obj.a = 3 console.log(obj) // {a: 3, b: { c: 0}} console.log(newObj) // {a: 1, b: { c: 0}} // 后面在加上这里obj.b.c = 2,改变之后,整个引用地址里面的属性值也被改变了 obj.b.c = 2 console.log(obj) // {a: 3, b: { c: 2}} console.log(newObj) // {a: 1, b: { c: 2}} // 使用JSON.parse(JSON.stringify())进行深拷贝 let deepObj = JSON.parse(JSON.stringify(obj)) obj.a = 4 obj.b.c = 4 console.log(JSON.stringify(obj3)) // {"a":3,"b":{"c":2}} console.log(obj) // {"a":4,"b":{"c":4}}
原型链上
的属性和不可枚举
属性不能被复制const obj = Object.create({ foo: 1 }, { // foo 是对象原型链上的属性. notEnum: { value: 2 //没有设置enumerable,不可枚举. }, canEnum: { value: 3, enumerable: true // enumerable设置是否可以枚举. } }); const copy = Object.assign({}, obj); console.log(copy); // { canEnum: 3 }
2,Object.create
语法:
Object.create(proto)
或Object.create(proto, propertiesObject)
。Object.create()
方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型const person = { name: 'person', printIntroduction: function() { console.log('this':this) console.log(`this指向新创建的对象${this.name}`); } } console.log(person.printIntroduction()) //this: {name: 'person', printIntroduction: ƒ} //this指向新创建的对象person const mine = Object.create(person) console.log(person.printIntroduction()) // this: {} // this指向新创建的对象person,新创建的对像上没有name属性时,回在原来的对象是取用,但是此时的this指向新创建的对象 mine.name = 'mine' console.log(mine.printIntroduction() // this: {name: 'mine'} , //this指向新创建的对象mine
异常:
proto
参数为null,或除基本类型包装对象
以外的对象
基本类型包装对象除了
null
和undefined
之外,所有基本类型都有其对应的包装对象名字 解释 String 字符串基本类型 Number 数值基本类型 BigInt 大整数基本类型 Boolean 布尔基本类型 Symbol 字面量基本类型 使用null为原型的对象时,以
null
为原型的对象存在不可预期的行为,因为它未从Object.prototype
继承任何对象方法。 而缺少Object.prototype.toString()
方法通常会使调试变得非常困难const normalObj = {}; // 普通对象 const nullProtoObj = Object.create(null) // null作为自己的原型 console.log(normalObj) // {} console.log(nullProtoObj) // {} console.log("" + normalObj) // [object Object] console.log("" + nullProtoObj) // 报错 alert(normalObj); // 展示 [object Object] alert(nullProtoObj) // 报错 normalObj.valueOf() // shows {} nullProtoObj.valueOf() // 报错 normalObj.hasOwnProperty("p") // 展示 "false" nullProtoObj.hasOwnProperty("p") //报错 normalObj.constructor // 出现 "Object() { [native code] }" nullProtoObj.constructor // 出现"undefined"
可以为以 null 为原型的对象添加
toString
方法,类似于这样:nullProtoObj.toString = Object.prototype.toString; // console.log(nullProtoObj.toString()); // 展示 "[object Object]" console.log("nullProtoObj is: " + nullProtoObj); // 展示 "nullProtoObj is: [object Object]"
在实践中,以
null
为原型的对象通常用于作为map
的替代。因为Object.prototype
原型自有的属性的存在会导致一些错误const ages = { '张三': 18, '李四': 27 }; function hasPerson(name) { return name in ages; } function getAge(name) { return ages[name]; } hasPerson('李四') //true getAge('李四') // 27 hasPerson("hasOwnProperty") // true getAge("toString") // ƒ toString() { [native code] }
使用以 null 为原型的对象消除了这种潜在的问题,也不会给
hasPerson
和getAge
函数引入太多复杂的逻辑:const ages = Object.create(null, { '张三': { value: 18, enumerable: true }, '李四': { value: 27, enumerable: true }, }); function hasPerson(name) { return name in ages; } function getAge(name) { return ages[name]; } hasPerson('李四') //true getAge('李四') // 27 hasPerson("hasOwnProperty") // false getAge("toString") // undefined
对象不继承
Object.prototype
原型的方法也可以防止原型污染攻击。如果恶意脚本向Object.prototype
添加了一个属性,这个属性将能够被程序中的每一个对象所访问,而以 null 为原型的对象则不受影响
对象属性删除(删)
Object 自身没有提供方法删除其自身属性(Map 中的 Map.prototype.delete()
可以删除自身属性 )。为了删除对象上的属性,必须使用 delete 操作符
- map原型上的delete删除
// 创建Map实例
const willDeleteMap = new Map()
// 对willDeleteMap对象设置属性和值
willDeleteMap.set('name', 'value')
// delete删除name属性,删除成功返回true
console.log(willDeleteMap.delete('name')) // true
// has查询对象里面是否还有名为name的属性,没有,结果返回false
console.log(willDeleteMap.has('name')) // false
- delete 操作符
// 字面量创建对象
const willDeleteMap = {
firstname: '沐',
lastname: '阳'
}
// 删除成功返回true
delete willDeleteMap.firstname
console.log(willDeleteMap) // {lastname: '阳'}
console.log(willDeleteMap.firstname)// undefined
比较对象
语法:Object.is(value1, value2)
Object.is()
,方法判断两个值是否为同一个值。Object.is
不会强制转换两边的值,
// Case 1
Object.is(25, 25); // true
Object.is('foo', 'foo'); // true
Object.is('foo', 'bar'); // false
Object.is(null, null); // true
Object.is(undefined, undefined); // true
Object.is(window, window); // true
Object.is([], []); // false
var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo); // true
Object.is(foo, bar); // false
// Case 2: Signed zero
Object.is(0, -0); // false
Object.is(+0, -0); // false
Object.is(-0, -0); // true
Object.is(0n, -0n); // true
// Case 3: NaN
Object.is(NaN, 0/0); // true
Object.is(NaN, Number.NaN) // true
冻结对象 Object.freeze()
语法:Object.freeze(obj)
Object.freeze()
方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze()
返回和传入的参数相同的对象
const freezeObj = {
prop: function() {},
foo: 'bar',
childObj: {},
childArr: []
}
freezeObj.foo = '第一次修改后的foo' //可修改
delete freezeObj.prop // 可删除
freezeObj.childArr.push(0)
freezeObj.addChild = "增加的数据"
console.log(freezeObj) // {foo: '第一次修改后的foo', childObj: {…}, childArr: Array(1), addChild: '增加的数据'}
//进行冻结
const newObj = Object.freeze(freezeObj); // 作为参数传递的对象freezeObj与返回的对象newObj都被冻结,也不用保存返回的对象(因为两个对象全等)
newObj === freezeObj // true,
newObj.foo = '第二次修改,No改动'
newObj.childArr.push('第二次修改,可以改动,freeze只冻结第一层')
newObj.addNewChild = "第二次增加数据,No新增"
newObj.childObj.addName = "对对象里层的数据修改,可以新增"
console.log(newObj)
// {foo: '第一次修改后的foo', childObj: {…}, childArr: Array(2), addChild: '增加的数据'}
// childArr: (2) [0, '第二次修改,可以改动,freeze只冻结第一层']
//childObj: {addName: '对对象里层的数据修改,可以新增'}
要使对象不可变,可以递归冻结每个类型为对象的属性(深冻结)
结语
知识点还是要弄清楚才能融会贯通,唯有学习才能让自己不断进步。
转载自:https://juejin.cn/post/7137206242694397966