继承
function Person() {
this.name = 'QF001'
}
Person.prototype.abc = function () {
console.log('QF002')
}
function Stu() {
this.age = 18
}
const s1 = new Stu()
console.log('实际的对象: ', s1)
const obj = {
name: 'QF001',
age: 18,
abc: function () {console.log('QF002')}
}
console.log('期望得到的对象', obj)
目前我们创建的 Stu 的实例化对象中,只有一个 age 属性
但是如果说 我想拥有 Person 构造函数内 属性, 以及他原型上的方法
那么我们就需要利用继承解决上述问题
如果我们真的得到了期待对象, 那么一定是 Stu 继承了 Person 内的属性和原型上的方法
此时 我们可以说 Stu 是 Person 的子类
Person 是 Stu 的父类
原型继承
在 ES6 正式推出 class 类以及对应的继承之前
我们的开发中某些时候, 可能需要用到继承, 那么此时需要有一种继承的方式就是利用了 原型
所以我们将这个方法称之为 原型继承
这种继承方式是将 自己的原型对象更改为 要继承的 父类的 实例化对象
- 缺点:
- 自己的原型对象消失了
// 父类
function Person() {
this.name = 'QF001'
}
Person.prototype.abc = function() {
console.log('QF002')
}
// 子类
function Stu() {
this.age = 18
}
// 将自身的原型对象, 更改为 要继承的 父类的实例化对象
Stu.prototype = new Person()
// 注意: 原型继承后, 如果需要再 原型上添加方法, 一定要在原型继承后添加, 不要在原型继承前添加
Stu.prototype.qwe = function() {console.log()}
const s1 = new Stu()
console.log('实际的对象: ', s1)
借用继承
借用继承
原型继承得到属性和方法都不在自已对象本身, 而是在在原型对象上
借用继承就是将属性继承到自己身上
这种继承方式 可以将父类所有属性继承到子类对象自身
但是父类的原型上的属性和方法, 跟子类没有任何关系
// 父类
function Person() {
this.name = 'QF001'
this.qwe = 'XF666'
}
Person.prototype.abc = function() {
console.log('QF002')
}
// 子类
function Stu() {
this.age = 18
Person.call(this)
}
cosnt s1 = new Stu()
consoele.log('实际的对象: ', s1)
组合继承
- 原型继承: 能够继承到属性和原型上的方法, 但是继承到的属性不在对象本身
- 借用继承: 能够将父类的属性继承到对象本身, 但是父类原型上的方法继承不到
基于上述的两个方法, 我们将原型继承和借用继承组合起来, 创建了一个 组合 继承
- 优点: 能够继承到所有的属性和原型上的方法, 并且属性能够继承到对象本身
- 缺点: 在原型上会有一套多余的属性
// 父类
funtion Person(name, age){
this.name = name
this.age = age
}
Person.prototype.hihi= funciont(){
console.log('hi')
}
// 子类
funciotn Stu(photo){
this.photo = phone
// 借用构造函数继承
Person.call(this,'张三',111
}
// 1. 原型继承
Stu.prototype = new Person()
cosnt s1 = new Stu(10086)
console.log('实际的对象: ' , s1)
拷贝继承
// 父类
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.hihi = function() {
console.log('hi')
}
// 子类
Stu 形参中的 ...
将第二个位置开始的所有实参收集到一个数组中
Person 实参中的 ...
因为我函数需要两个参数, 而不是一个数组, 所以需要将数组展开
function Stu(phone, ...args) {
this.phone = phone
const p = new Person(...args)
for(let key in p) {
// 将拿到的所有的内容 添加到 当前都早函数的原型对象中
Stu.prototype[key] = p[key]
}
}
const s1 = new Stu(10086, '张三', 18)
console.log('实际的对象: ', s1)
ES6 继承
// 父类
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.hihi = function() {
console.log('')
}
// 子类
在实现 ES6 继承的时候, 书写方式有几个要求
1. class 子类的类名 extends 要继承的父类类名 {}
2. constructor 内部 必须书写 super
他的作用可以在调用的时候对他进行传参, 传递的参数会传递到 父类中
注意: 哪怕父类不需要书写任何参数, 我们的 super 也需要书写
并且需要书写在 constructor 内部的一行
当前的方法只能给 class 类使用
但是可以继承到构造函数中的内容, 也就是说父类是构造函数或者 class 都可以
class Stu extends Person {
constructor (id, ...args) {
super(...args)
this.id = id
}
}
const s1 = new Stu(10086, '张三',18)
console.log('实际的对象: ', s1 )
深浅拷贝
深浅拷贝 (只考虑引用数据类型, 当前案例中 只考虑 数组和对象)
-
赋值
- 因为引用数据在赋值的时候 是将地址传递过去了
- 所以赋值后是将一个地址给到了一个新的变量, 如果你对以这个地址内做任何操作
- 那么两个变量都会互相影响
-
浅拷贝
- 通过浅拷贝复制一个引用数据类型到另一个变量中
- 其中这个数据内的基本数据类型修改的时候不会互相影响
- 但是其中的 引用数据类型在修改的时候会互相影响
-
深拷贝
- 基于原本的数据, 复制出一个一模一样的, 但是内部数据的修改, 不会互相影响
深拷贝(工作版)
const obj = {
name: '我是对象的 obj',
info: {
width: 100,
height: 101
}
arr: [100,200,300]
}
const newObj = JSON.parse(JSON.stringfy(obj))
// 修改基本数据类型
newObj.name = '新的名字'
obj.name = '一个更新的名字'
// 修改引用数据类型
newObj.info.width = 999
obj.arr[0] = 'QF001'
console.log('原对象obj: ', obj)
console.log('深层拷贝后的对象newObj: ', newObj)
深拷贝 (面试版)
const obj = {
name :'是对象 obj',
info: {
width :100,
height: 101
},
arr: [100, 200, 300]
}
const newObj = {}
function deepCopy(target, origin) {
//target 目标对象 origin 原对象
// 当函数执行完毕后, 会基于 origin 创建一个和他一模一样的对象, 放到 target 中
for(let key in origin) {
if(Object.prototype.toString.call(origin[key]) === '[object Object]'){
// 说明当前的值为对象
target[key] = {}
deepCopy(target[key], origin[key])
} else if (Object.prototype.toString.call(origin[key]) === '[object Array]') {
// 说明当前的值是 数组
target[key] = []
deepCopy(target[key], origin[key])
} else {
// 说明当前的值是 基本数据类型
target[key] = origin[key]
}
}
}
deepCopy(newObj, obj)
修改基本数据类型
newObj.name = '新的名字'
obj.name = '一个更新的名字'
修改引用数据类型
newObj.info.width = 999
obj.arr[0] = 'QF001'
console.log('原对象obj: ', obj)
console.log('深拷贝后的对象newObj: ', newObj)
浅拷贝
const obj = {
name: 'QF001',
age: 18,
info: {
width: 200,
height: 300
}
}
// 2.2 通过 对象内部的 一个方法 完成浅拷贝
const newObj = Object.assign({}, obj)
// 基本数据类型不会互相影响
// obj.name = 'QF002'
// newObj.age = 999
// 引用数据类型 会互相影响
obj.info.width = 666
newObj.info.height = 777
console.log('newObj', newObj)
console.log('obj', obj)
// 2.1 通过 for...in 完成浅拷贝
const newObj = {}
for (let key in obj) {
const value = obj[key]
newObj[key] = value
}