当你走的很远的时候,回过头来看看自己走过的道路,可能会发现曾错过的风景。
JS中万物都是对象,今天就深度讲一下Object的里面到底有什么。文章主要讲对象的自有属性和原型中的属性,至于原型链就不在这篇文章多讲了。
一、Object简述
创建对象的方法有如下几种
- new + Object
- 字面式 {name: 'vinter'}
- 工厂模式(可以创建多个对象)
let person = (name, age) => {
let o = new Object()
o.name = name
o.age = age
Object.prototype.say = () => {
console.log('你好')
}
return o
}
let p1 = person('vinter', 18)
let p2 = person('xzwen', 20)
// 无法识别对象类型 都是Object
- 构造函数
function Person(name){
this.name = name
this.say = () => {}
}
let p = new Person('vinter')
console.log(p instanceof Person) // true
console.log(p instanceof Object) // true
// 能够识别对象的类型
- 原型模式
function Person(name){
}
Person.prototype = {
name: 'viter',
age: 18,
say: () => {}
}
let p = new Person()
// 所有属性写进原型,对象都能访问,没有对象的私有属性
- 混合模式
实例拥有自己的私有属性,又拥有共同的原型方法
function Person(name, age){
this.name = name
this.age = age
}
Person.prototype = {
constructor: Person, // 将constructor 指向Person
say: () => {console.log('你好')}
}
let p = new Person('vinter', 18)
console.log(p.name)
p.say()
二、Object私有属性解析
1. Object.assign
Object.assign() 方法用于将其他对象的可枚举属性复制到目标对象(即第一个参数对象)
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const sources = { d: 2, b: 6 }
Object.assign(target, source, sources)
// { a: 1, b: 6, c: 5, d: 2}
console.log(target.c)
// 5
常用于将某个对象合并到新对象{}。
Object.assign({}, source)
2. Object.create
Object.create = function (obj) {
var F = function () {};
F.prototype = obj;
return new F();
};
常用于继承某个构造函数的原型属性,但是不能继承该构造函数的实例属性,例如上面例子
let P = () => {}
p.prototype = obj
let p1 = Object.create(obj)
3. Object.defineProperty
Object.defineProperty(obj, prop, descriptor)
该属性是实现vue双向数据绑定的核心,这里主要讲它的使用方法。
讲它的相关用法时,就得先理解的概念。
1.数据属性
数据属性的四个特性
configurable:表示是否能被delete删除属性且能重新定义该属性。
enumerable:表示能否通过for-in遍历的属性。
writable:表示是否能修改属性。
value:属性的值。
let person = {
name: 'vinter'
}
console.log(Object.getOwnPropertyDescriptor(person, 'name'))
2.访问器属性
数据属性不包含数据值,包含一对get和set的核心方法,在读取访问器属性时,就是通过这两个方法进行操作处理的。
访问器属性的四个特性
configurable:表示是否能被delete删除属性且能重新定义该属性。
enumerable:表示能否通过for-in遍历的属性。
get:读取属性时调用的方法,默认值是undefined。
set:写入属性时调用的方法,默认值是undefined。
let person = {
name: 'vinter',
_age: 18, // 下划线是常用标记,表示是内部属性,只能通过对象的方法进行读写
weight: 120
}
Object.defineProperty(person, 'age', { // 'age'代替'_age'
get(){
return this._age
},
set(newValue){
this._age = newValue
this.weight += 2
}
})
person.age = 10
console.log(person.weight, person.age) // 122 10
console.log(Object.getOwnPropertyDescriptor(person, 'age'))
从图中可以看到访问器属性的configurable和enumerable两个属性的默认值都是false,如果后面要对该访问器属性进行delete删除时,将configurable转化成true即可。
console.log(Object.getOwnPropertyDescriptors(person))
从图可以看出该对象具有四个属性,
4. Object的四个相关属性
(defineProperty、defineProperties、getOwnPropertyDescriptor、getOwnPropertyDescriptors)
这四个属性是分为两对:defineProperty vs getOwnPropertyDescriptor、defineProperties vs getOwnPropertyDescriptors。
意思为属性设置和属性的获取解析,第一对上面讲过了,这里就大概说一下第二对的意思,也就是支持设置对个属性,获取多个属性的意思。
Object.defineProperties()
Object.defineProperties(obj, props)
var obj = new Object();
Object.defineProperties(obj, {
name: {
value: '张三',
configurable: false,
writable: true,
enumerable: true
},
age: {
value: 18,
configurable: true
}
})
console.log(obj.name, obj.age) // 张三, 18
Object.getOwnPropertyDescriptors()
打印出对象的所有属性
Object.getOwnPropertyDescriptors(obj)
5. Object.entries
Object.entries() 方法返回一个给定对象
let obj = {
name: 'vinter',
age: 18
}
let arr = [2, 3, 4]
let string = 'abc'
console.log(Object.entries(obj)) // [['name', 'vinter'], ['age', 18]]
console.log(Object.entries(arr)) // [['0', 2], ['1', 3], ['2', 4]]
console.log(Object.entries(string)) // [['0', 'a'], ['1', 'b'], ['2', 'c']]
Object转Map
new Map()构造函数接受一个二维数组,而Object.entries()方法生成一个二维数组,所以对象、数组、字数串转化为Map结构变得简单。
obj = {name: 'vinter', age: 18}
new Map(Object.entries(obj))
// Map {'name' => 'vinter', 'age' => 18}
6. Object.freeze,Object.preventExtension,Object.seal
正常对象的数据属性都可以被但是通过以下方法,改变了数据属性的四大特性。
- Object.freeze():冻结对象
【增、删、改、查】 —— Object.freeze() ==> 【-、-、-、查】 - Object.perventExtension(): 不可扩展对象
【增、删、改、查】 —— Object.perventExtension() ==> 【-、删、改、查】 - Object.seal(): 密封对象
【增、删、改、查】 —— Object.seal() ==> 【-、-、改、查】
相对应的检测方法,返回Boolean。
- Object.isFrozen()
- Object.isExtensible()
- Object.isSealed()
举例
Object.freeze()方法可冻结对象,冻结后,对象属性不能删除,修改以及添加,只能for...in读取。
obj = {
name: 'vinter',
age: 18
}
Object.freeze(obj)
console.log(Object.getOwnPropertyDescriptors(obj))
7. Object.is
该对象方法和==与===运算符相似,但是有明显区别。
Object.is与==比较
== 会将两边的操作数进行隐式转化,之后再进行比较,但是Object.is就不会进行转化。
'' == false // true
'1' == 1 // true
Object.is与===比较
=== NaN和NaN不等,-0与+0相等,但是Object.is就认为NaN和NaN是相等,而-0和+0是不相等的。
所以总的来说这两个的相似程度比== 运算符更相近。
8.Object.keys,Object.values
Object.keys()返回一个名称(键)的数组
let arr = [2, 3, 4]
let str = 'abc'
console(Object.keys(arr)) // ['0', '1', '2']
console.log(Object.str(str)) // ['0', '1', '2']
// 因为JSON对象的特性,所以返回都会是字符串的数组
Object.values()返回可枚举属性值得数组
var obj = { foo: 'bar', baz: 42 }
let str = 'abc'
console.log(Object.values(obj)) // ['bar', 42]
console.log(Object.values(str)) // ['a', 'b', 'c']
9.Object.setPrototypeOf
Object.setPrototypeOf(obj, prototype)
为对象obj设置新的原型对象。
注意
如果对象的[[Prototype]]被修改成不可扩展(通过 Object.isExtensible()
查看),就会抛出 TypeError
异常。如果prototype
参数不是一个对象或者null
(例如,数字,字符串,boolean,或者 undefined
),则什么都不做。否则,该方法将obj
的[[Prototype]]
修改为新的值。
var obj = { foo: 'bar', baz: 42 }
let prototypeC = {name: 'vinter'}
Object.setPrototypeOf(obj, prototypeC)
console.log(obj)