原型模式
原型模式不仅是一种设计模式,它还是一种编程范式(programming paradigm),是 JavaScript 面向对象系统实现的根基。 在 JavaScript 中,我们使用原型模式,并不是为了得到一个副本,而是为了得到与构造函数(类)相对应的类型的实例、实现数据/方法的共享。克隆是实现这个目的的方法,但克隆本身并不是我们的目的。
原型
在 JavaScript 中,每个构造函数都拥有一个prototype属性,它指向构造函数的原型对象,这个原型对象中有一个 constructor 属性指回构造函数;每个实例都有一个__proto__属性,当我们使用构造函数去创建实例时,实例的__proto__属性就会指向构造函数的原型对象。 具体来说,当我们这样使用构造函数创建一个对象时:
javascript
function User(name, age) {
this.name = name;
this.age = age;
}
User.prototype.speak = function() {
console.log('说中国话')
}
const user = new User('Mondo', 30)
原型链
在上面基础上调用方法
javascript
user.speak(); // 说中国话
console.log(user.toString()) // [object Object]
明明没有定义方法,却可以调用成功。这是因为在访问一个 JS 对象或属性时,首先会查找实例自身,当自身没有找到的时候,会在实例的原型对象上去查找,如果还没有查找到,会继续在原型对象的原型对象上去查找,一直查找到 null,这一条查找轨迹就是原型链。
深拷贝
深拷贝没有完美方案,每一种方案都有它的边界 case。
javascript
function deepClone(obj) {
// 如果是 值类型 或 null,则直接return
if(typeof obj !== 'object' || obj === null) {
return obj
}
// 定义结果对象
let copy = {}
// 如果对象是数组,则定义结果数组
if(obj.constructor === Array) {
copy = []
}
// 遍历对象的key
for(let key in obj) {
// 如果key是对象的自有属性
if(obj.hasOwnProperty(key)) {
// 递归调用深拷贝方法
copy[key] = deepClone(obj[key])
}
}
return copy
}
调用深拷贝方法,若属性为值类型,则直接返回;若属性为引用类型,则递归遍历。这就是我们在解这一类题时的核心的方法。