IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 手写JavaScript面向对象API底层代码实现 -> 正文阅读

[JavaScript知识库]手写JavaScript面向对象API底层代码实现

注:本篇博客续上一篇“异步编程函数式编程底层代码手写”,因此编号从13开始

13. instanceof操作符的实现

function imitateInstanceof(left, right) {
    // 开启尾调用优化条件
    "use strict";

    // 检查右值是否有[Symbol.hasInstance]属性
    if (right && !right[Symbol.hasInstance])
        throw new TypeError("类型检查函数的第二个参数必须是类")

    // 如果左值不是引用类型,那么不存在原型链,直接返回false
    if(!left || left && typeof left !== "object" && typeof left !== "function")
        return false

    // 初始值设置
    // 如果getPrototypeOf传入一个原始类型,那么会经历装箱,变成引用类型来寻找原型链,所以之前必须检查left是否是原始类型
    let leftProto = Object.getPrototypeOf(left)
    let rightProto = right.prototype;

    // 使用尾调用优化
    return (function check() {
        if(!leftPrototype)
            return false
        else if(leftPrototype === rightPrototype)
            return true
        else {
            leftPrototype = Object.getPrototypeOf(leftPrototype)
            return check()
        }
    })();
}

14.new操作符的实现

function imitateNew(constructor, ...args) {
    if(typeof constructor !== "function")
        throw new TypeError("构造函数必须是函数")

    // 如果是ES6之前,默认使用组合模式创建对象,构造函数的prototype中只允许有方法,不允许有其它非方法的引用类型
    // 第一步:创建一个新对象
    let target = Object.create(constructor.prototype)

    // 第二步:绑定this
    let result = constructor.call(target, ...args)

    // 第三步:绑定prototype
    Object.setPrototypeOf(target, constructor.prototype)

    // 第四步:判断返回值
    return result instanceof Object ? result : target
}

15.对象浅拷贝实现

function copy(obj) {
    // 如果obj不是引用类型,那么进行装箱操作
    obj = obj instanceof Object ? obj : Object(obj)

    // 初始化浅拷贝目标对象和枚举键
    let target = null, key

    // 实现最基础的常见对象类型:”数组,函数和非JavaScript特殊内置对象“的浅拷贝
    if(obj instanceof Array)
        target = []
    else if(obj instanceof Function)
        // 单个函数对象的浅复制没有明确实际意义,这里返回一个相同的引用
        return obj
    else
        target = new Object

    // 将自有可枚举属性复制到浅拷贝目标对象,不包括Symbol
    for([key, target[key]] of Object.entries(obj));

    // 将自有可枚举的Symbol属性复制到浅拷贝目标对象
    for(let p of Object.getOwnPropertySymbols(obj))
        if(Object.getOwnPropertyDescriptor(obj, p).enumerable)
            target[p] = obj[p]

    return target
}

16.Object.assign()实现

Object.$assign = function(target, ...sources) {
    // 处理参数,如果参数不是引用类型,那么进行装箱
    target = target instanceof Object ? target : Object(target)
    sources = sources.map(el => el instanceof Object ? el : Object(el))

    // 下面操作类似于单个对象的浅拷贝
    let key
    sources.forEach(obj => {
        // 自有可枚举属性不包括符号属性复制到目标对象target
        for([key, target[key]] of Object.entries(obj));
        // 自有可枚举符号属性复制到目标对象target
        for(let p of Object.getOwnPropertySymbols(obj))
            if(Object.getOwnPropertyDescriptor(obj, p).enumerable)
                target[p] = obj[p]
    })

    return target
}

17.扩展操作符合并对象实现

Object.$expand = function(target, ...sources) {
    // 处理参数,如果参数不是引用类型,那么进行装箱
    target = target instanceof Object ? target : Object(target)
    sources = sources.map(el => el instanceof Object ? el : Object(el))

    // 扩展操作符会返回一个新对象
    let res = {}

    // 复制操作
    function copy(obj) {
        for(let [key, value] of Object.entries(obj))
            // 扩展操作符复制后不存在访问器属性,在此设置属性特性,使之一定不存在
            Object.defineProperty(res, key, {
                value: value,
                enumerable: true,
                configurable: true,
                writable: true
            })
        // 自有可枚举符号属性复制到目标对象target
        for(let p of Object.getOwnPropertySymbols(target))
            if(Object.getOwnPropertyDescriptor(target, p).enumerable)
                Object.defineProperty(obj, p, {
                    value: target[p],
                    enumerable: true,
                    configurable: true,
                    writable: true
                })
    }

    // 复制源对象
    sources.forEach(copy)

    // 复制目标对象
    copy(target)

    return res
}

18.函数的深复制(实际应用中没有任何意义,实现纯属娱乐)

// 函数的属性都是只读的,在这里重新复制一个函数没什么意义
// 如果考虑构造函数上定义静态方法,还有的考虑,但下面不会考虑这一点
function copyFunction(target) {
    let func = target.toString(), args, body

    // 获取非箭头函数的参数,注意ES6增强写法的函数也没有prototype
    if(target.prototype || func.startsWith(`${target.name}`)) {
        args = func.slice(func.indexOf("(") + 1, func.indexOf(")")).split(",")
        // 获取函数体
        body = func.slice(func.indexOf("{") + 1, func.lastIndexOf("}"))
        // 递归调用时函数名无法使用,将其改为arguments.callee调用递归
        body = body.replaceAll("this." + target.name, "arguments.callee")
    } else {
        if(func.startsWith("("))
            // 箭头函数参数非简写形式
            args = func.slice(func.indexOf("(") + 1, func.indexOf(")")).split(",")
        else
            // 箭头函数单参数简写形式
            args = func.slice(0, func.indexOf("=>")).trim().split(",")

        if(func.endsWith("}"))
            // 箭头函数函数体非简写形式
            // 对象中的箭头函数方法中无法使用函数名调用自己来进行递归,这里不用做递归处理
            body = func.slice(func.indexOf("{") + 1, func.lastIndexOf("}"))
        else
            // 箭头函数函数体简写形式
            // 对象中的箭头函数方法中无法使用函数名调用自己来进行递归,这里不用做递归处理
            body = "return " + func.slice(func.indexOf("=>") + 2).trim()
    }
    // Function只能创建匿名函数
    return new Function(...args, body)
}

19.对象的深复制

// 由于18中提到函数深复制没有意义,所以当类型是函数时设置为递归边界,直接返回就行
function deepClone(obj) {
    let wm = new WeakMap()

    // 深复制非函数属性
    function copy(key, value, target, obj) {
        // 深复制要复制属性的特性
        if (value instanceof Object) {
            let descriptor = Object.getOwnPropertyDescriptor(obj, key)
            // 如果是引用类型,那么就递归继续复制
            descriptor.value = clone(value)
            Object.defineProperty(target, key, descriptor)
        } else
            Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(obj, key))
    }

    function clone(obj) {
        // 深复制函数参数必须是对象
        obj = obj instanceof Object ? obj : Object(obj)

        // JavaScript特殊内置对象处理
        if (obj instanceof Date) return new Date(obj)
        if (obj instanceof RegExp) return new RegExp(obj)

        if (wm.has(obj))
            return wm.get(obj)

        let target
        // JavaScript非特殊对象处理
        if (typeof obj === "object")
            // 保持继承链
            target = new obj.constructor()
        else if (typeof obj === "function")
            return obj
        else if (Array.isArray(obj))
            target = new Array

        // 解决循环引用
        wm.set(obj, target)

        // 复制所有非符号自有可枚举属性及其特性
        Object.entries(obj).forEach(([key, value]) => copy(key, value, target, obj))

        // 复制所有符号自有可枚举属性及其特性
        Object.getOwnPropertySymbols(obj).forEach(key => {
            if (Object.getOwnPropertyDescriptor(obj, key).enumerable)
                copy(key, obj[key], target, obj)
        })

        return target
    }

    return clone(obj)
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-07 13:38:22  更:2022-02-07 13:40:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:48:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码