ES6继承
// 父类
class Person {
constructor (name, age) {
this.name = name
this.age = age
}
sayHi () {
console.log('hi')
}
}
// 继承
class Stu extends Person {
constructor (id, ...args) {
super(...args)
this.id = id
}
}
const s1 = new Stu(10086, '张三', 18)
console.log('实际的对象: ', s1)
-
子类
-
在 实现 ES6 类的继承的时候, 书写方法有几个要求
-
- class 子类的类名 extends 要继承的父类类名 {}
-
- constructor 内部 必须书写 super
- 他的作用可以在调用的时候对他进行传参, 传递的参数会传递到 父类中
-
注意: 哪怕父类不需要任何参数, 我们的 super 也需要书写
- 并且需要书写在 constructor 内部的 第一行
-
当前的方法只能给 class 类使用
- 但是可以继承到构造函数中的内容, 也就是说父类是构造函数或者class都可以
-
-
深浅拷贝 (只考虑引用数据类型, 当前案例中 只考虑 数组和对象)
- 赋值
- 因为引用数据类型在赋值的时候 是将地址传递过去了
- 所以赋值后是将一个地址给到了一个新的变量, 如果你对这个地址内做任何操作
- 那么两个变量都会互相影响
- 浅拷贝
- 通过浅拷贝复制一个引用数据类型到另外一个变量中
- 其中这个数据内的基本数据类型修改的时候不会互相影响
- 但是其中的 引用数据类型再修改的时候会互相影响
- 深拷贝
- 基于原本的数据, 复制出一个一摸一样的, 但是内部数据的修改, 不会互相影响
const obj = {
name: '我是对象obj',
info: {
width: 100,
height: 101
},
arr: [100, 200, 300]
}
// 深拷贝
const newObj = JSON.parse(JSON.stringify(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 中
*/
// 下边两个写法功能一样, 但是 第一行操作的是形参不依赖外界变量, 第二行操作的是全局变量, 需要操作外界的变量
// target.name = '函数内部添加的'
// newObj.name = '12345678'
for (let key in origin) {
// console.log(key, origin[key])
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)
闭包
- 书写闭包, 需要创建一个不会销毁的内容空间
- 需要 直接/间接 返回一个函数
- 内部函数, 需要访问外部函数内创建的局部变量
- 优点: 延长了变量的使用时间
- 缺点: 每一个闭包都会创建一个不会销毁的内存空间
- 如果闭包书写的太多, 那么这个不会被销毁的空间就越来越多
- 就可能会造成页面/程序的卡顿
沙箱模式
-
是 JS 中 利用 闭包 完成的一个设计模式
-
设计模式: 为了解决某一类问题的最优化的写法, 但不是万能
function outter() {
let a = 100
let b = 99
const obj = {
getA() {
return a
},
setA(val) {
a = val
},
getB() {
return b
},
setB(val) {
b = val
}
}
return obj
}
/**
* 此时调用函数会开启一个执行空间 (XF666)
* 内部有对应的局部变量 a 和 b
*
* 所以我们现在 res_1 使用的变量是来自 执行空间 XF666
*/
const res_1 = outter()
console.log(res_1.getA()) // 100
res_1.setA(999)
console.log(res_1.getA()) // 999
/**
* 此时调用函数会开启一个执行空间 (XF777)
* 内部有对应的局部变量 a 和 b
*
* 所以我们现在 res_2 使用的变量来自 执行空间 XF777
*/
const res_2 = outter()
console.log(res_2.getA()) // (999错误) (100正确)
// 当前案例 可以帮助我们思考上述的问题
// const obj_1 = {
// a: 100,
// b: 99
// }
// const obj_2 = {
// a: 100,
// b: 99
// }
// obj_1.a = 999
// console.log(obj_2.a) // ???
// 案例结束位置========================================
沙箱模式语法糖
/**
* 沙箱模式语法糖
*
* 语法糖: 在保证功能不变的情况下, 尽可能的简化我们的代码
*/
// 基础版
function fn1() {
let a = 100
return {
getA () {
return a
},
setA (val) {
a = val
}
}
}
const res1 = fn1()
// console.log(res1)
// console.log(res1.getA()) // 100
// res1.setA(999)
// console.log(res1.getA()) // 999
// 语法糖 优化版
function fn2() {
let a = 1
let b = 'QF001'
return {
/**
* 将来对象中如果有人访问了 属性 a, 那么就会触发 get a 这个方法
* 如果有人修改了 属性a, 那么就会自动触发 set a 这个方法
*/
get a () { return a },
set a (val) { a = val },
get b () { return b }
}
}
const res2 = fn2()
console.log(res2)
// 用了语法糖之后的简化写法
// console.log(res2.a) // 1
// res2.a = 666
// 用了语法糖之后的简化写法
// console.log(res2.a) // 666
console.log(res2.b) // 'QF001'
res2.b = 'QF999' // 当前没有给 属性b 设置 set 方法, 所以修改是无效的
console.log(res2.b) // 'QF001'