柯里化函数
- 把一个接收多个参数的单个函数改成接收单个参数多个参数(化繁为简)
- 每一次函数调用结束之后 会返回一个新的函数(闭包)
- 作用:
- 简化参数 参数复用
- 延迟调用
- 缺点:
设计模式
- 单例模式
- 解决类或者构造函数创建出来的实例只有一份
- 实现:提供一个函数 只要调用这个函数返回一个实例
- 实例放在全局存储
- 使用闭包
- 订阅发布模式(观察者)
- 解决的是一个对象变化所有依赖这个对象的数据都会相应的变化
- 实现:类
- 属性: message
- {类型: [行为,行为]}
- 方法: 订阅on 发布emit
- 属性: message
- v2 v3
垃圾回收机制(GC)
含义: js在运行的时候会自动回收一些废弃数据的内存空间(自动回收)
-
垃圾回收机制运行时机:在程序运行完成之后 所有线程闲置的时候会触发垃圾回收机制
-
垃圾回收机制的算法
- 引用计数法
- 在创建一个数据的时候 该数据引用次数默认为1
- 当我们把这个数据赋值给其他的变量的时候 该数据引用次数会+1
- 当我们把用到某个数据变量置为空 该数据引用次数会-1
- 一直到数据引用次数为0的时候 垃圾回收机制就会回收该数据的存储空间
- 引用计数法会遇到一个循环引用的问题
- 标记-清除法
- 标记
- js会将所有的数据默认为0
- 从根对象去访问每一个对象里面的key,如果可以访问标记为1
- 从根对象去访问每一个对象里面的key,如果不可以访问标记为0
- 清除
- 将内存里面所有的数据对象都遍历一遍 看这个对象上面的标识 如果标识是0 清除这个对象;如果标识是1 保留这个对象
- 标记
- 引用计数法
-
垃圾回收机制对于我们写代码的影响
- 复杂数据如果不用的时候 自己手动清空
- 尽量减少把数据挂载到全局
- 定时器都是挂载到全局 定时器不用的时候记得清除 vue组件里面的定时器在组件销毁的时候记得清除
- 不用的事件处理函数要清空
-
什么是垃圾回收机制
-
垃圾回收机制算法有哪些
-
垃圾回收机制有哪些影响
继承(重灾区)
-
面向对象的三大特征
- 封装
- 继承
- 多态
-
继承
- 含义:子类可以直接使用父类的属性和方法 不需要自己实现
- 类
- es5是没有类这个概念 用构造函数+原型模拟类的功能(面试着重关注点)
- es6提出类的概念 只是一个语法糖(关键字 extends)
-
es5实现继承
- 准备父类 添加属性 原型添加方法
- 借助构造函数实现继承父类的属性
- 做法: 在子类构造函数里面调用父类的构造函数 并且利用call或者apply同时修改父类构造函数里面this的指向,指向到子类的实例
- 借助原型实现继承父类原型的方法
- 做法: 将子类构造函数原型指向父类的某个实例
- 组合继承
- 借助构造函数+借助原型
- 既可以继承父类的属性也可以继承父类原型上面的方法
- construcotr属性
- 每一个实例访问constructor得到就是它的构造函数
-
es6实现继承
- 准备父类和子类
-
继承关系
- js继承关系都是单向继承,父类方法变化 子类会改变;但是子类变化,父类不会变化
-
原型
- 三句话
-
原型链
- 一个对象访问属性和方法的时候会优先在自身查找,自身有就用自身的
- 自身没有就会自动往__proto__上面查找 __proto__有就使用
- __proto__没有会继续往下一级的__proto__上面查找 下一级有就使用
- 下一级没有就继续往下一查找,一直找到原型链最顶层是null
-
js实现继承的方式有哪些?
实例
(以下代码均为课程实例)
(1)引用计数法
<script>
// 计算一个变量(引用的数据类型)使用次数
// 当我们一个变量创建的时候 引用就产生了 obj引用次数+1
var obj = {a:1}
// 当我们把这个变量赋值给另一个变量 obj引用次数+2
// 复杂数据类型赋值方式是引用传递
var obj2 = obj
// 新增一个obj3的应用 obj3引用次数+1
var obj3 = {...obj}
// 当我们把某一个变量置为空null obj引用次数+1
obj = 1
console.log(obj2.a)
// obj引用次数 0
obj2 = 1
// 此段代码运行之后才会触发垃圾回收机制
</script>
(2)循环引用
<script>
function test() {
let A = new Object(); // A对象引用次数+1
let B = new Object(); // B对象引用次数+1
A.pointer = B; // B +2
B.pointer = A; // A +2
A.pointer = null
B.pointer = null
}
// 本来函数test执行结束之后 执行空间会被销毁
//
test();
</script>
(3)标记清除法
<script>
// 标记 从根对象开始 跟对象就是全局对象
//person{a:1,b:2}总共引用次数是多少
// person 可以被访问 标记为可达
var person = {
a:1,
b:2
}
// obj 可以被访问 标记为可达
var obj = {
a: person
}
// obj2 可以被访问 标记为可达
var obj2 = {
a: obj // 不可达
}
function fn(data){
// p也是可达
let p = data
// s也是可达
let s = {
a: p
}
}
fn(obj2)
obj = null
{a:1}
var data = {
a: obj2, // 可达
b: obj, // 不可达
c: person // 可达
}
</script>
(4)垃圾回收机制影响
<body>
<div class="box">
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ipsam placeat inventore autem excepturi unde commodi incidunt, illum quia repellendus porro nemo architecto sint numquam exercitationem libero nobis vero dolor ipsum?
</div>
<script>
function A(){
var a = 1
return function B(){
a++
console.log(a)
}
}
let o = A() // A执行空间不会被销毁
// o()
// o()
// o()
// o()
// o = null // 手动去清除o的引用关系 触发垃圾回收机制
// let o1 = A() // 又创建了一个
// function get(){
// let sum = 10
// sum++
// }
// get()
// console.log(sum)
var box = document.querySelector('.box')
function A(){
console.log('do A..')
}
function B(){
console.log('do B..')
}
box.addEventListener('click', A)
box.addEventListener('click', B)
setTimeout(()=>{
box.removeEventListener('click', B)
B=null
}, 5000)
</script>
</body>
(5)es5继承-继承属性
<script>
/* 借助构造函数实现继承父类的属性 */
// 准备父类
function Person(){
// 添加属性
console.log('Person被调用了')
this.username = 'jack'
this.age = 18
}
// 添加方法
Person.prototype.sayHi = function(){
console.log('person hi...')
}
// 创建父类的实例
var p = new Person()
console.log(p)
// 准备子类
// 让Student称为Person子类
function Student(){
// 本身自己没有添加username属性
console.log('Student被调用了')
// 在子类的构造函数内部手动调用父类的构造函数
// 调用父类构造函数同时 修改父类构造函数内部this指向 指向到子类的实例
// console.log(this)
// this.age = 18
Person.call(this)
}
// 创建子类的实例 希望创建出来的实例由username属性
var s = new Student()
console.log(s)
</script>
(6)es5继承-继承父类原型方法-优化
<script>
// 父类
function Person(){
}
// 添加方法
Person.prototype.sayHi = function(){
console.log('person hi...')
}
Person.prototype.walk = function(){
console.log('person walk...')
}
// 创建父类的实例
// const p = new Person()
// console.log(p)
// p.sayHi()
// p.walk()
// 准备子类
function Student(){
}
// 希望子类构造函数prototype上面有sayHi和walk
// 将子类构造函数prototype指向到父类的某个实例
Student.prototype = new Person()
const s = new Student()
console.log(s)
s.sayHi()
s.walk()
// 给子类原型新增一个方法
Student.prototype.study = function(){
console.log('student study...')
}
const p2 = new Person()
console.log(p2)
// p2.study()
// 给Person的原型添加方法
Person.prototype.eat = function(){
console.log('person eat...')
}
const s2 = new Student()
console.log(s2)
s2.eat()
</script>
(6)es5继承-继承父类原型方法
<script>
// 父类
function Person(){
}
// 添加方法
Person.prototype.sayHi = function(){
console.log('person hi...')
}
Person.prototype.walk = function(){
console.log('person walk...')
}
// 创建父类的实例
const p = new Person()
console.log(p)
p.sayHi()
p.walk()
// 准备子类
function Student(){
}
// 希望子类构造函数prototype上面有sayHi和walk
// 把父类的构造函数的prototype赋值给子类
Student.prototype = Person.prototype
const s = new Student()
console.log(s)
s.sayHi()
s.walk()
</script>
(6)es5继承-继承父类原型方法问题
<script>
// 父类
function Person(){
}
// 添加方法
Person.prototype.sayHi = function(){
console.log('person hi...')
}
Person.prototype.walk = function(){
console.log('person walk...')
}
// 创建父类的实例
const p = new Person()
console.log(p)
p.sayHi()
p.walk()
// 准备子类
function Student(){
}
// 希望子类构造函数prototype上面有sayHi和walk
// 把父类的构造函数的prototype赋值给子类
// 此处就是引用传递
Student.prototype = Person.prototype
// 给子类原型上面添加一个方法
Student.prototype.study = function(){
console.log('student study...')
}
const s = new Student()
console.log(s)
s.sayHi()
s.walk()
s.study()
// 父类实例上面也出现子类的原型方法
const p2 = new Person()
console.log(p2)
p2.study()
// 父类原型上面添加一个方法
Person.prototype.eat = function(){
console.log('person eat...')
}
const s2 = new Student()
console.log(s2)
</script>
(7)原型链
<script>
function Aniaml(){
}
function Person(){
}
Person.prototype = new Aniaml()
Person.prototype.sayHi = function(){
console.log('sayHi..')
}
function Student(){
// this.sayHi = function(){
// console.log('子类自身属性')
// }
}
const p = new Person()
console.log(p)
console.log(p.__proto__)
Student.prototype = p
const s = new Student()
// console.log(s)
// console.log(s.__proto__)
// console.log(Student.prototype = s.__proto__)
// // s.__proto__ == Student.prototype == p
// // s.__proto__.__proto__ === p.__proto__ === Person.prototype
// console.log(s.__proto__ === p)
// console.log(p.__proto__ === Person.prototype)
// console.log(s.__proto__.__proto__)
// s.__proto__.__proto__.sayHi()
// s.sayHi()
console.log(s.__proto__)
console.log(s.__proto__ === Student.prototype)
console.log(s.__proto__.__proto__)
console.log(s.__proto__.__proto__ === Person.prototype)
console.log(s.__proto__.__proto__.__proto__)
console.log(s.__proto__.__proto__.__proto__ === Aniaml.prototype)
console.log(s.__proto__.__proto__.__proto__.__proto__)
console.log(s.__proto__.__proto__.__proto__.__proto__ === Object.prototype)
console.log(s.__proto__.__proto__.__proto__.__proto__.__proto__)
</script>
(8)组合继承
<script>
function Person(username,age){
// 添加属性
this.age = age
this.username = username
}
// 添加方法
Person.prototype.sayHi = function(){
console.log('person hi...')
}
Person.prototype.walk = function(){
console.log('person walk...')
}
// 准备子类
function Student(username, age){
// Person.call(this,username, age)
Person.apply(this,[username, age])
}
// 此处赋值的时候 把constructor覆盖了
// {constructor: Student}
// {username:undefined,age:undefined}
Student.prototype = new Person()
// 修改Student的constructor属性
Student.prototype.constructor = Student
const s = new Student('jack', 18)
console.log(s)
console.log(s.username)
s.sayHi()
// 每一个实例 访问constructor属性 得到是构造函数
console.log(s.constructor)
</script>
(9)es6继承
<script>
// 父类一般行公共的属性和方法
class Person{
constructor(username, age){
this.username = username
this.age = age
}
sayHi(){
console.log('sayHi方法')
}
walk(){
console.log('walk方法')
}
}
// 子类还需要实现自己特有的属性和方法
class Student extends Person{
constructor(username, age, number){
// 在子类构造函数访问this属性之前 调用父类的构造函数
// super代表父类的构造函数名称
super(username,age)
this.studyNo = number
}
// 子类特有的方法
study(){
console.log('学习')
}
}
const s = new Student('jack', 18, '10089')
console.log(s)
class Teacher extends Person{
constructor(username, age, number){
super(username,age)
this.workNo = number
}
// 重写父类的方法
sayHi(){
console.log('teacher重写sayHi')
}
}
const t = new Teacher('tom', 28, '11111')
console.log(t)
t.sayHi()
const p = new Person('jerry', 18)
console.log(p)
</script>
(10)作业1-es5实现
<script>
/*
实现一个父类,父类Car
+ 属性
- brandName
- wheel
- generator
+ 方法
- run
- stop
实现几个子类
+ BWM
- 属性:sat 真皮座椅
- 方法: 一键启动
+ BenChi
- 属性:全景天窗
- 方法: 防抱死 重写stop方法
es5
es6
*/
//es5方法
function Car(brandName, wheel, generator) {
//给父类添加属性
this.brandName = brandName
this.wheel = wheel
this.generator = generator
}
Car.prototype.run = function () {
console.log('run被调用了')
}
Car.prototype.stop = function () {
console.log('stop被调用了')
}
var c = new Car('大众', '四轮', '三缸发动机')
console.log(c)
c.run()
c.stop()
function BMW(sat, brandName, wheel, generator) {
this.sat = sat
Car.apply(this, [brandName, wheel, generator])
}
BMW.prototype.ABS = function () {
console.log('ABS被调用')
}
BMW.prototype = new Car()
BMW.prototype.constructor = BMW
var b = new BMW('真皮座椅','宝马','四轮','六缸发动机')
console.log(b)
b.run()
b.stop()
function BenChi(sat, brandName, wheel, generator) {
this.sat = sat
Car.apply(this, [brandName, wheel, generator])
}
BenChi.prototype.toRun = function () {
console.log('toRun被调用')
}
BenChi.prototype = new Car()
BenChi.prototype.constructor = BenChi
var b = new BenChi('狗皮座椅','奔驰','四轮','四缸发动机')
console.log(b)
b.run()
b.stop()
BenChi.prototype.stop1 = function(){
console.log('stop1方法调用')
}
// c.stop1()
</script>
(11)作业2-es6实现
<script>
/*
实现一个父类,父类Car
+ 属性
- brandName
- wheel
- generator
+ 方法
- run
- stop
实现几个子类
+ BWM
- 属性:sat 真皮座椅
- 方法: 一键启动
+ BenChi
- 属性:全景天窗
- 方法: 防抱死 重写stop方法
es5
es6
*/
class Car{
constructor(brandName, wheel, generator){
this.brandName = brandName;
this.wheel = wheel;
this.generator = generator;
}
run(){
console.log('run...');
}
stop(){
console.log('stop...');
}
}
const car = new Car('比亚迪', '四个轮子', '四缸发动机');
console.log(car);
car.run();
car.stop();
class BMW extends Car{
constructor(brandName, wheel, generator, leatherSeat){
super(brandName, wheel, generator);
this.leatherSeat = leatherSeat;
}
start(){
console.log('start...');
}
}
const bmw = new BMW('宝马', '五个轮子', '五缸发动机', '真皮座椅');
console.log(bmw);
bmw.run();
bmw.stop();
bmw.start();
class BenChi extends Car{
constructor(brandName, wheel, generator, skylight){
super(brandName, wheel, generator);
this.skylight = skylight;
}
stop(){
console.log('obs改写stop...');
}
}
const benchi = new BenChi('奔驰', '六个轮子', '六缸发动机', '全景天窗');
console.log(benchi);
benchi.run();
benchi.stop();
</script>