JavaScript高级部分——第二天

目录

一、沙箱模式

二、函数柯里化(Currying)

1.概念

2.作用

3.示例

三、继承

1.概念

2.常见的继承方式

(1)原型继承

(2)使用构造函数继承

(3)组合继承

(4)ES6的继承

(5)拷贝继承

四、策略模式

1.概念

2.核心思想

3.作用

4.优点

5.例子:计算员工奖金

五、发布订阅模式

1.概念

2.三个角色

3.作用

4.示例:报名某课程


一、沙箱模式

概念:对于 JavaScript 来说,沙箱并非传统意义上的沙箱,沙箱是一种安全机制,把一些不信任的代码运行在沙箱之内,使其不能访问沙箱之外的代码。当需要解析或着执行不可信的 JavaScript 的时候,需要隔离被执行代码的执行环境的时候,需要对执行代码中可访问对象进行限制,通常开始可以把 JavaScript 中处理模块依赖关系的闭包称之为沙箱

简单的说:沙箱模式是一种可以帮助我们保护代码的技术,它可以防止代码中的变量被外部环境所污染。 需要访问和修改私有的代码,必须通过提供专有的方式才能实现


function createSandBox(){
    // 内部的私有代码
    let username = '蔡徐坤'
    // 如果在外边需要获取和修改这个数据,需要提供专门的方法
    return {
        getData(){
            return username
        },
        setData(value){
            username = value
        }
    }
}
const obj = createSandBox()
console.log(obj.getData()) // 蔡徐坤
obj.setData('基尼太美')
console.log(obj.getData()) // 基尼太美

以上就是简单的沙箱模式的实现代码,但我们还可以对以上代码做一些改进,可以利用对象的get 和 set 方法来改进,当获取对象里面属性值时 get 方法会自动执行,当设置属性值的时候 set 方法也会自动执行,且 get 和 set 方法的方法名要和需要操作的属性名一致

function createSandBox(){
    let username = '蔡徐坤'
    return {
        get user(){
            return username
        },
        set user(value){
            username = value
        }
    }
}
const obj = createSandBox()
obj.user = '基尼太美' // 此时set方法被自动调用了
console.log(obj.user) // 此时get方法被自动调用了
console.log(obj)

二、函数柯里化(Currying)

1.概念

柯里化又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术

2.作用

可以固定相同参数,实现函数调用传参的简单化           

可以让参数复用

3.示例

通过传参返回一个完整的网址

知识点补充:一个完整的网站通常包含三部分:

        协议(protocol):http、https

        域名(domain):www.baidu.com

        端口号(port):8080

学习柯里化之前的做法:

function address(protocol, domain, port){
    return protocol + domain + port
}

问题:通过这种形式传递参数,第一个参数其实可以固定化,希望的是传递一次给所有的地址都可以使用,所以使用柯里化的方式去改进

function addCurrying(protocol){
    return function(domain){
        return function(port){
            return protocol + domain + port
        }
    }
}
const currying = addCurrying('https://')
const result1 = currying('www.jd.com')(':8080')

三、继承

1.概念

继承是和构造函数相关的一个应用,是指让一个构造函数去继承另一个构造函数的属性和方法,所以继承一定出现在两个构造函数之间

2.常见的继承方式

(1)原型继承

假如这里有两个构造函数:

// 父类构造函数
function Father(name, age){
    this.name = name
    this.age = age
}
Father.prototype.money = function(){
    console.log('一个小目标!')
}

// 子类构造函数
function Son(name, age){
    this.name = name
    this.age = age
}

怎么让子类构造函数去继承父类构造函数的方法呢?

我们第一想到的就是让子类构造函数的原型对象等于父类构造函数的原型对象,我们可以试试

Son.prototype = Father.prototype

//此时我们再给子类得构造函数原型上面添加一个方法
Son.prototype.love = function(){
    console.log('喜欢谈💑!')
}

//实例化子类对象
let s = new Son('赵三', 20)
s.money() // 一个小目标
s.love() // 喜欢谈💑

// 实例化父类对象
let f = new Father('赵俊骏', 50)
f.love() // 喜欢谈💑

可以看到,当我们给子类的构造函数的原型对象上面添加方法,父类的实例化对象也可以使用,直白点说儿子去谈恋爱了父亲也跟着儿子去了,这是很不合理的,所以这种方式我们是很不推荐的

我们推荐使用这种方式:把父类得实例化对象给子类的原型对象

function Father(name, age){
    this.name = name
    this.age = age
    this.rg = function(){
        console.log('喜欢跑步!')
    }
}
Father.prototype.money = function(){
    console.log('一个小目标!')
}
function Son(name, age){
    this.name = name
    this.age = age
}
Son.prototype = new Father('赵三', 20)
//给子类构造函数的原型上面添加一个方法
Son.prototype.love = function(){
    console.log(this.name + '喜欢谈💑!')
}
//给Son实例化对象
let s = new Son()
s.love() // 喜欢谈💑
s.money() // 一个小目标
s.rg() // 喜欢跑步

可以看到这种继承可以使用父类构造函数的方法和构造函数的原型对象上面的方法,给自己的构造函数添加方法也不会影响父类,这样做有他的好处也有坏处 

优点:构造函数体内和原型上的都可以继承

缺点:一个构造函数的内容,在两个位置传递参数

        继承来的属性不再子类实例的身上

(2)使用构造函数继承

核心代码:Father.call(name,age)

优点:构造函数体内和原型上都可以继承

缺点:一个构造函数的内容,在两个位置传递参数;继承来的属性不在子类实例的身上

function Father(name, age){
    this.name = name
    this.age = age
}
Father.prototype.money = function(){
    console.log('一个小目标')
}
function Son(name, age, sex){
    //call() 改变函数内部的this指向,传递参数就是正常的传递
    //(你给函数怎么传递参数的就怎么传参)
    Father.call(this, name, age)
    this.sex = sex
}
const s = new Son('张三', 18, '男')
(3)组合继承

就是把原型继承和借用构造函数继承两个方式结合在一起

核心代码如下

function Son() {
  Father.call(this)
}
Son.prototype = new Father()

优点:父类构造函数体内和原型上的内容都能继承

        继承下来的属性放在自己身上

        在一个位置传递所有的参数

缺点:当你给子类添加方法的时候,实际上是添加在父类的实例身上

(4)ES6的继承

也就是用extends和super关键字

注意点:ES6的继承方案其实内部的实现依旧是组合继承

class Father{
    constructor(name, age){
        this.name = name
        this.age = age
    }
    money(){
        console.log('一个小目标')
    }
}

class Son extends Father{
    constructor(name, age, sex){
        // 注意点:super() 超级函数必须先调用,再去定义子类的属性
        super(name, age)
        this.sex = sex
    }
}

const s = new Son('王成', 18, '男')
s.money() // 一个小目标
(5)拷贝继承

显而易见,这种继承方式就是把要继承的东西拷贝一份

可以使用...或者循环去拷贝

const obj = {
    name: '张三',
    age: 18,
    say(){
        console.log('hello')
    }
}

//使用循环去拷贝
const data = {}
for(let key in obj){
    data[key] = obj[key]
}

//使用...去拷贝
const datd1 = {
    ...obj
}

四、策略模式

设计模式: 就是别人总结出来的一些解决问题的一些代码方案,遇到一个问题,人家告诉你使用这种方案是最佳的

1.概念

        定义一系列的算法,将他们一个个封装起来,使他们直接可以相互替换。 就是把一些判断的方式转变成一个一个的方式模式

2.核心思想

将相似的行为封装为一个类,并将该类的调用暴露给外部。由于每个类都包含一个不同的行为,因此我们可以在运行时根据需要选择适当的类实例。

3.作用

策略模式可以使代码更加灵活、可维护,并且使我们可以在运行时根据需求选择不同的代码实现。在实际开发中,如果遇到类似多重条件判断的问题,我们可以使用策略模式来简化代码并使其更加易于扩展

4.优点

  • 代码可扩展性:使用if判断时,每次添加新的判断条件都需要修改已有的代码。而策略模式都是一个一个的方法

  • 可维护性:使用if判断导致代码中存在大量的条件分支,使得代码逻辑复杂且难以维护。而使用策略模式可以将不同条件的逻辑分散到各个策略类中,使得代码结构清晰,易于理解和维护。

  • 代码复用性好

5.例子:计算员工奖金

以前的做法是一个个去判断:

function totalMoney(level, price){
    // 之前的方式,肯定需要一个一个去判断
    if(level === 'S'){
        return price * 4
    }
    if(level === 'A'){
        return price * 3
    }
    if(level === 'B'){
        return price * 2
    }
}
const price1 = totalMoney('S', 20000)

现在可以用策略模式的思想去做:

function totalMoney(level, price){
    let bonus = {
        'S': (price)=>{return price * 4},
        'A': (price)=>{return price * 3},
        'B': (price)=>{return price * 2}
    }
    return bonus[level](price)
}
const price1 = totalMoney('S', 20000)

五、发布订阅模式

1.概念

发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。

2.三个角色

        订阅者

        调度中心(平台)

        发布者

订阅者把自己想订阅的 事件 注册到调度中心,当 发布者 发布该 事件调度中心,也就是该事件触发时,由 调度中心 统一调度 订阅者 注册到 调度中心 的处理代码。

3.作用

解决了一个对象方式改变其他对象通知的问题

4.示例:报名某课程

class Dispatch{
    constructor(){
        this.message = {}
    }
    //订阅
    on(type,fn){
        if(!this.message[type]){
            this.message[type] = []
        }
        this.message[type].push(fn)
    }
    //取消订阅
    cancel(type,fn){
        if(!this.message[type]) return
        this.message[type] = this.message[type].filter(item=>item!=fn)
    }
    //通知消息
    emit(type,info){
        if(!this.message[type]) return
        this.message[type].forEach(item => {
            item(info)
        });
    }
}
const bus = new Dispatch()

function handlerA(info){
    console.log('王成报名了大前端课程!'+info)
}
function handlerB(info){
    console.log('张三报名了大前端课程!'+info)
}
function handlerC(info){
    console.log('李思报名了大前端课程!'+info)
}

bus.on('HTML5', handlerA)
bus.on('HTML5', handlerB)
bus.on('HTML5', handlerC)

bus.cancel('HTML5', handlerA)

bus.emit('HTML5', '马上开课了!')

console.log(bus)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值