手写new、深拷贝、call、bind、apply

131 阅读3分钟

new

new操作符用于生成一个构造函数的实例化对象,可以继承构造函数的所有对象和方法

调用new操作符会发生以下五件事情:
1、首先创建一个新的空对象

    function myNew(fn,...agrs){
        let obj = {}
    }

2、 将这个对象的原型设置为构造函数的prototype对象、这样就能继承到fn里面的所有对象

     function myNew(fn,...agrs){
        let obj = {}
        obj.__proto__ = fn.prototype
    }

3、让构造函数的this指向这个新的对象:这样实例化对象的this就会指向构造函数

     function myNew(fn,...args){
        let obj = {}
        obj.__proto__ = fn.prototype
        fn.call(obj,...args)
    }

4、返回这个新对象

     function myNew(fn,...args){
        let obj = {}
        obj.__proto__ = fn.prototype
        fn.call(obj,...args)
        return obj
    }

深拷贝、浅拷贝

// 需要先理解什么是堆类型和栈类型?
// 栈内存是保存固定大小的基本数据类型,即基础数据类型
   Number Undefined Boolean Null String
// 堆内存即引用数据类型 保存的是内存的地址
   Object Array Function

浅拷贝:一个新对象对已存在对象的对象属性的地址引用即浅拷贝

    // Object.assign()方法
    Object.assign(newObj,obj)
    // 或直接赋值
    let newObj = obj

深拷贝:本质是开辟一个新内存空间 把需要拷贝的对象取过来

    // 通过转换成字符串再转成对象的形式赋值给新对象 
    // 弊端:函数,undefined,则序列化的结果会把函数, undefined丢失
    let newObj = JSON.parse(JSON.stringify(Obj))
    
    
    // 手写递归深拷贝实现
    function MyClone(obj){
        // 先判断传进来的值是不是引用类型 如不是直接返回
        if(!obj instanceof  Object){
            return obj
        }
        // 创建一个新对象
        let newObj = {}
        // 递归把obj的每一个对象赋值给newObj
        for(key in obj){
            newObj[key] = MyClone(obj[key])
        }
        // 返回拷贝好的新对象
        return newObj
    }

call、apply、bind

他们都是改变了函数的this指向、call、apply改变后会立即执行函数、bind需要再次调用

// 如果想函数直接调用需要把函数挂载到Function原型上面
   Function.prototype.MyCall = function(){}
   Function.prototype.MyApply = function(){}
   Function.prototype.MyBind = function(){}
// 手写call
    Function.prototype.MyCall = function (fn,...args){
        // 调用时先判断有没有传对象进来 没有就给window
        fn = fn || window
        // 因为this指向该函数调用者 所有在fn上面新建一个对象保存当前this 
        fn._this = this
        // 调用该this并返回
        let resulte = fn._this(args)
        return resulte 
    }
    
// 手写apply(只有args是不是数组的却别)
    Function.prototype.MyApply = function (fn,...args){
        // 调用时先判断有没有传对象进来 没有就给window
        fn = fn || window
        // 因为this指向该函数调用者 所有在fn上面新建一个对象保存当前this 
        fn._this = this
        // 调用该this并返回
        args = args || []
        let resulte = fn._this(...args)
        return resulte 
    }
    
// 手写 bind(因为需要再次调用 所以里面必定再返回一个函数)
    Function.prototype.MyBind = function (fn,...args1){
        // 调用时先判断有没有传对象进来 没有就给window
        fn = fn || window
         // 返回的函数里面也要接收一个参数
           return function(...args1){
                // 因为this指向该函数调用者 所有在fn上面新建一个对象保存当前this 
                fn._this = this
                // 合并两个参数
                let argsAll = [...args1,...args2]
                // 调用该this并返回
                let resulte = fn._this(...argsAll)
                return resulte 
           }
    }