本章总结了JS中对象的内容
JS的对象定义为一组属性的无序集合,类似于一个散列表,内容是k/v对,v是值或函数。
定义对象的两种方式
1 2 3 4 5
| let person = new Object() person.name = "jojo" person.sayName = function () { console.log(this.name) }
|
1 2 3 4 5 6
| let person = { name:"jojo", sayName() { console.log(this.name) } }
|
属性类型
1 数据属性
属性如下:
configurable
是否可以使用delete
、修改特性、修改为访问器属性等
enumberable
是否可以通过for in
语句进行便利
writable
属性值是否可以被修改
value
包含实际属性的值
1 2 3 4 5 6 7
| let obj = {} Object.defineProperty(obj, "info", { writable: false, value: 'haha' }) obj.info = 'jaja' console.log(obj.info)
|
2 访问器属性
属性如下:
configurable
是否可以使用delete
、修改特性、修改为访问器属性等
enumberable
是否可以通过for in
语句进行便利
get
属性值是否可以被修改
set
包含实际属性的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| let obj = { }
Object.defineProperty(obj, "cnt_", { writable : true, value:0 })
for(let i in obj) console.log(i) Object.defineProperty(obj, "cnt", { get() { this.cnt_ += 1 return this.cnt_ }, set(val) {this.cnt_ = val} }) console.log(obj.cnt) console.log(obj.cnt) obj.cnt = 100 console.log(obj.cnt) console.log(obj.cnt)
|
读取属性
按key读取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| let obj = { }
Object.defineProperty(obj, "cnt_", { writable : true, value:0 })
for(let i in obj) console.log(i) Object.defineProperty(obj, "cnt", { get() { this.cnt_ += 1 return this.cnt_ }, set(val) {this.cnt_ = val} })
console.log(Object.getOwnPropertyDescriptor(obj,"cnt"))
|
全部读取:使用getOwnPropertyDescriptors
方法,会返回一个新的静态对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| let obj = { }
Object.defineProperty(obj, "cnt_", { writable : true, value:0 })
for(let i in obj) console.log(i) Object.defineProperty(obj, "cnt", { get() { this.cnt_ += 1 return this.cnt_ }, set(val) {this.cnt_ = val} })
console.log(Object.getOwnPropertyDescriptors(obj))
|
合并对象
注意 合并对象操作Object.assign
是浅拷贝
1 2 3
| dest = {} Object.assign(dest, {test:1}, {test1:2}) console.log(dest)
|
创建对象
1.工厂模式
1 2 3 4 5 6 7 8
| function createPerson(age) { let obj = new Object() obj.age = age obj.sayAge = function () { console.log(this.age) } return obj }
|
缺点:
2.构造函数模式
1 2 3 4 5 6 7 8 9 10 11
| function Person(age) { this.age = age this.sayAge = function(){ console.log(this.age) } } let p1 = Person(1) let p2 = Person(2) console.log(p1.constructor === Person) console.log(p1 instanceof Person) console.log(p1 instanceof Object)
|
优点:
- 可以进行类型判断
步骤:
- 内存中创建了新对象
- 分配prototype
- 分配this
- 执行构造器中内部代码
- 返回非空,则返回该对象,如果没有返回对象 则返回this
2.1 构造函数是函数
1 2 3 4 5 6 7 8 9
| let o = new Object() function Person(age) { this.age = age this.sayAge = function(){ console.log(this.age) } } Person.call(o,1) console.log(o.age)
|
2.2 构造函数的问题
1 2 3 4 5
| function Test() { this.test = function () {} }
console.log((new Test()).test === (new Test()).test)
|
3.原型模式
只要创建一个函数,就会按照特定规则创建一个prototype
对象
虽然JS中没有标准的访问prototype
的方式,但是在Chrome和Firefox等实现中可以根据__proto__
属性进行访问
1 2 3 4 5 6 7
| function Person(){} Person.prototype.age = 123 Person.prototype.sayAge = function () {console.log(this.age)} let x = new Person() x.sayAge() console.log(x.__proto__.constructor === Object) Object.getPrototypeOf(x)
|
实例与构造函数之间没有直接联系,但是与构造函数原型之间有直接联系。
3.1. 原型层级
1 2 3 4 5 6 7 8 9
| function Person() {} Person.prototype.age = 128 let p1 = new Person() let p2 = new Person() p2.age = 111 console.log(p1.age) console.log(p2.age) delete p2.age console.log(p2.age)
|
为什么会发生这种现象?因为对p2对象的修改使其修改了age属性,遮蔽了原型链上的age属性,经过遮蔽后,删除该属性,即可恢复链接
3.2.in操作符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function Person() {} Person.prototype.age = 128 let p1 = new Person() let p2 = new Person() p2.age = 111 console.log(p1.age) console.log(p1.hasOwnProperty('age')) console.log('age' in p1) console.log(p2.age) console.log(p2.hasOwnProperty('age')) delete p2.age console.log(p2.age) console.log(p2.hasOwnProperty('age')) console.log(Object.keys(Object.getPrototypeOf(p2))) console.log(Object.keys(p2))
|
面试题
for in 和 for of 区别
for in 遍历出原型的属性怎么办(用hasOwnProperty检测)
数据类型判断
基本数据类型
判断数据的类型,typeof的局限, 如何解决这个局限
instanceof 原理
原型链的理解
new 原理
await使用什么实现(生成器, yield star)
Promise / sleep
bigint int