何为对象
对象是包含着键值对的无序散列表
关于属性
- 数据属性
const obj = {} Object.defineProperty(obj, 'name', { configurable: true, enumerable: true, write: true, value: 'Daniel' })
- 访问器属性
const obj = {} Object.defineProperty(obj, 'age', { configurable: true, enumerable: true, get: function () { return this._age }, set: function (value) { this._age = value < 18 ? value : 18 } }) obj.age = 16 console.info('obj.age: ', obj.age) // 16 obj.age = 25 console.info('obj.age: ', obj.age) // 18
- 批量设置属性
const obj = {} Object.defineProperties(obj, { name: { value: 'Daniel', }, age: { get: function() { return 25 } }, })
- 获取属性描述符
Object.getOwbPropertyDescriptor(obj, key)
创建对象
1. 工厂模式
function createPerson(name, age) {
const o = Object()
o.name = name
o.age = age
return o
}
const person = createPerson('Daniel', 25) // { name: 'Daniel', age: 25 }
2. 构造函数模式
new 操作符
function Person(name, age) {
this.name = name
this.age = age
}
const person = new Person('Daniel', 25) // { name: 'Daniel', age: 25 }
3. 原型模式
function Person() {}
Person.prototype = {
constructor: Person,
name: 'Daniel',
sayName: () => console.info(this.name)
}
const person = new Person()
番外篇:啥是原型对象
Function.prototype 对象:
- prototype 对象拥有所有实例共享的属性和方法
- prototype 对象的
constructor
属性指向函数自身
缺点:
- 构造函数不可传参
- 引用属性共享可被每个实例更新
4. 组合模式
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function () {
console.info(`Hi, My name is ${this.name}`)
}
const person = new Person('Daniel', 25)
person.sayHello() // Hi, My name is Daniel
5. 动态原型模式
一些面向对象开发人员不习惯将方法的声明放在构造器外部,所以有了下面这样的声明:
function Person(name) {
this.name = name
if (typeof this.sayHi !== 'function') {
Person.prototype.sayHi = function () {
console.info(`Hi, My name is ${this.name}`)
}
}
}
6. 寄生构造函数模式
可用于扩展已有对象
function Enhanced(array) {
const enhancedArray = Array.isArray(array) ? array : []
enhancedArray.combineValue = function () {
return enhancedArray.reduce((total, curr) => total + curr)
}
return enhancedArray
}
const hanced = new Enhancd([1, 2, 3])
hanced.combineValue() // 6
Tip:这种情况下创建的实例与构造函数间没有任何关系哦,因为返回的其它类型的实例
7. 稳妥构造函数模式
比较极端的场景
特点:
- 无公共属性
- 方法中不引用 this 对象
function Person(name) {
const o = new Object()
o.sayHi = function() {
console.info(`Hi, My name is ${name}`)
}
return o
}
const person = new Person('Daniel')
person.sayHi() // Hi, My name is Daniel
继承
核心点:通过 原型链 共享属性和方法 实现继承
首先理一下 函数(构造函数)、原型对象 和 实例 之前的关系:
1. 通过原型链继承
function SubType() {}
SubType.protptype = new SuperType()
缺点
- 实例会共享原型链上的引用属性
2. 借用构造函数
function SubType(name) {
SuperType.call(this)
this.name = name
}
优点
- 继承父类的实例属性
- 构造函数可传参
缺点
- 木有继承父类原型上的共享属性与方法,伐开心
3. 组合继承
function SubType(name) {
SuperType.call(this)
this.name = name
}
SubType.prototype = new SuperType()
优点
- 父类实例属性和原型属性、方法 全都要
缺点
- 继承过程中调用了两次 父类 构造函数,父类表示不开心
- 解决方案在 寄生组合式继承 里
4. 原型式继承
function object(o) {
function F() {}
F.prototype = o
return new F()
}
原型式继承同样会有引用类型属性共享的问题,ES5 通过 Object.create()
方法规范了原型式继承
5. 寄生式继承
寄生式继承是在原型式继承上的扩展,可用于增强对象:
function createAnother(original) {
const clone = object(original)
clone.sayHi = function () {
console.info('Hi')
}
return clone
}
6. 寄生组合式继承
其背后思路是:用寄生式继承来继承父类的原型,再将结果指定给子类型的原型
function inheritPrototype(SubType, SuperType) {
const prototype = object(SuperType.prototype)
prototype.constructor = SubType
SubType.prototype = prototype
}
function SubType(name) {
this.name = name
}
inheritPrototype(SubType, SuperType)
SubType.prototype.sayHi = function() {
console.info(`Hi, My name is ${this.name}`)
}
完·End