JavaScript高级部分——第三天

目录

一、工厂模式

二、单例模式

三、垃圾回收机制 

1.原理

2.标记清理

3.引用计数

四、数据劫持

1.浅拷贝

2.深拷贝

3.Object.defineProperty()

4.数据劫持封装

5.Object.defineProperties()

6.数据代理 proxy()


说明一下:高级部分第一天和第二天的内容我直接上传了md文件,感兴趣的可以去资源里面下载,另外我有时间会把前两天的笔记补上的

一、工厂模式

工厂模式:批量创建对象出来(多例模式)

普通的工厂函数:

function person(name, age){
    const obj = new Object()
    obj.name = name
    obj.age = age
    return obj
}
const p1 = person('王成', 18)
const p2 = person('陈洁', 20)

我们可以把工厂模式升级为——构造函数的形式

function Person(name, age){
    this.name = name
    this.age = age
}
const p1 = new Person('王成', 18)
const p2 = new Person('陈洁', 20)

二、单例模式

单例模式:一个类一生中只能有一个子类

单例模式核心代码,你可以给Person构造函数添加一个静态方法

function Person(name, age){
    this.name = name
    this.age = age
}
Person.getInstance = function(name, age){
    // 判断有没有instance这个属性,如果没有这个属性,
    //就把实例化对象赋值给它,如果有就直接返回
    if(!this.instance){
        this.instance = new Person(name, age)
    }
    return this.instance
}
const p1 = Person.getInstance('王成', 18)
console.log(p1)
const p2 = Person.getInstance('崔傑瑜', 20)
console.log(p2)
console.log(p1 === p2)

可以看到,两个实例化对象都是一样的,这就是单例模式

知识点补充:

关于面向对象里面的this:

        如果是实例化对象调用的函数,那么构造函数里面的this指向的就是实例化对象

        如果是把构造函数当成普通函数去调用,那么里面的this指向的是window

        如果是通过构造函数调用的静态方法,那么静态方法里面的this指向的是构造函数

上面是用构造函数的方法写单例模式,现在我们用class的方式写单例模式

class Person{
    constructor(){}
    init(name, age){
        this.name = name
        this.age = age
    }
    // 通过一个关键字static把方法变成静态方法
    static getInstance(name, age){
        if(!this.instance){
            this.instance = new Person(name, age)
        }
        this.instance.init(name, age)
        return this.instance
    }
}
const p1 = Person.getInstance('王成', 18)
console.log(p1)
const p2 = Person.getInstance('陈洁', 28)
console.log(p1 === p2) // true
console.log(p2)

可以看到,这里逐步打印p1和p2,会得到不一样的结果,这是因为在静态方法里面调用了init()函数,但若是把console.log(p1)放到console.log(p2)之后,打印的结果都是与p2的结果一样的

三、垃圾回收机制 

1.原理

js的垃圾回收,是执行环境在运行代码时,同时进行管理的,这为开发者减轻很大的负担.

通过自动内存管理实现内存的分配和闲置资源的回收.

基本思路是这样的:

        确定那个变量不再使用,然后释放其占用的内存,这个回收过程是周期行的,每隔一段时间就会执行一次

当运行一个函数时,栈或堆就会分配空间保存相应的值.当变量使用完成后,就不再被需要,它占用的内存就要被释放,供后面的变量使用.但很多时候变量的使用与否不会这么简单.垃圾回收程序必须标记那个变量还会使用,那个变量不再使用,便于回收

在浏览器发展历史上,有两种标记策略: 标记清理和引用计数.

2.标记清理

垃圾回收程序运行时,会标记内存中存储的所有变量(标记方法有多种).然后他会将所有在作用域的变量,以及被变量引用的变量的标记去掉.在此之后,被标记的变量就等待被删了.随后垃圾回收机制会运行一次,清理标记的值且收回被占用的内存

3.引用计数

它的思路是对每个值都记录它被引用的次数,但是弊端太多已经被放弃

如果两个对象相互引用,尽管他们已不再使用,垃圾回收器不会进行回收,导致内存泄露。

四、数据劫持

1.浅拷贝

浅拷贝:对象的复制只是复制对象的引用,可以改变原始数据的值

常见的浅拷贝的方式:=、...、for in 遍历、

2.深拷贝

深拷贝:彻底复制一个对象,而不是简单的拷贝对象的引用,拷贝后不能修改原始数据的值

最常用的方式是:JSON.parse(JSON.stringify())

注意:单层数据使用 Object.assign() 和ES6的 ... 为深拷贝,多层数据为浅拷贝

3.Object.defineProperty()

数据劫持:在操作对象的时候,可以设置一些限定

这里的限定指的是:对象里面的属性不允许你遍历、对象里面的属性不允许你修改、对象里面的属性不允删除等

配置项:

value: 该属性对应的值

 configurable 该属性是否能被删除

writable: 该属性是否可被重写, 默认是 false

enumerable: 该属性是否可被枚举, 默认是 false

get: 是一个函数, 叫做 getter 获取器, 可以来决定该属性的值:get 函数的返回值, 就是当前这个属性的值

set: 是一个函数, 叫做 setter 设置器, 当你需要修改该属性的值的时候, 会触发该函数

注意: get 不能和 value 和 writable 一起使用, 会报错

Object.defineProperty(参数1,参数2,参数3)

参数1表示你要劫持那个对象,参数2表示要对那个属性做限定,参数3表示的是配置项

// 被劫持的对象
const obj = {}

// 声明一个对象用来给劫持的对象设置值
const objValue = {
    name: '蔡徐坤',
    age:18
}

// 注意点:如果对象里面没有设置这个属性,那么通过劫持属性就相当于设置了一个属性,它的值是通过value配置项设置的,并且优先级更高
Object.defineProperty(obj, 'name', {
    value: '王成',
    configurable: false,
    writable: false,
    enumerable: false
})

//但我们大多数时候倾向于用get和set
Object.defineProperty(obj, 'name', {
    get(){
        return objValue.name
    },
    set(value){
        document.querySelector('h1').innerHTML = `hello,我是<span>${value}</span>,曾经江湖中的传说人物,今天晚上8点钟在直播间不见不散!`
        objValue.name = value
    }
})

4.数据劫持封装

上述的数据劫持每次只能劫持一个属性,当有多个属性的时候比较麻烦,所以我们把他进行了封装

 function property(setData, callback){
    // 声明一个被劫持的对象,一般把这个对象称之为目标对象
    const target = {}
    for(let key in setData){
        Object.defineProperty(target, key, {
            get(){
                 return setData[key]
            },
            set(value){
                setData[key] = value
                callback && callback()
            }
        })
    }
    return target
}

但注意:这种数据劫持的封装只供参考,因为js给我们提供了更好了方法

5.Object.defineProperties()

数据劫持的升级方法,可以劫持多个属性

// 专门用来设置数据的
const setData = {
    name: '张三',
    age: 18
}
// 目标对象,被劫持的对象
const target = {}

Object.defineProperties(target, {
    'name': {
        get(){
            return setData.name
        },
        set(value){
            setData.name = value
        }
    },
    'age': {
        get(){
            return setData.age
        },
        set(value){
            setData.age = value
        }
    }
})

6.数据代理 proxy()

proxy 数据代理,为ES6提供的,就是数据劫持的封装版本的标准语法。不需要你自己去封装了,直接变成标准语法结构,内部你也不需要关注(直接用)

const setData = {name: '王成', age: 18}
const result = new Proxy(setData, {
    // target目标对象(被劫持的对象)
    // property表示被劫持对象要设置的属性(跟咱们封装数据劫持时遍历的key是一样的)
    get(target, property){
         return target[property]
    },
    // value表示你要修改目标对象的属性值
    set(target, property, value){
        target[property] = value
    }
})

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值