🔥 JavaScript手写题,脑洞大开,乐趣无限!

不知道有没有跟我一样每次面试前都要去现找一些题去看的小伙伴,基于这一痛点呢我想还是总结一下,这样显得更有效率也更加系统!写这篇文章也是为了准备面试所以也会尽可能写的详细一点

一、手写new方法

使用new生成对象实例总共经历了以下四个步骤:

  1. 创建一个新的对象;
  2. 将新对象的__proto__属性指向构造函数的prototype;
  3. 执行构造函数,并把this指向新创建的对象;
  4. 若有返回值则判断是否为引用类型,如果是则返回引用类型的值,否则返回新创建的对象;
js 复制代码
    function mynew(){
          // 创建一个新的对象
          const obj = {};
          // 从参数中获取构造函数
          const func = [].shift.call(arguments);
          obj.__proto__ = func.prototype;
          // 执行构造函数,并把this指向新创建的对象
          const res = func.apply(obj,[...arguments])
          // 判断返回值类型如果为引用类型则返回对应的引用类型的值,否则返回新创建的对象
          return res instanceof Object ? res : obj
    }
    
    // demo
    function Person(name,age){
        this.name = name;
        this.age = age;
        // return {name:'邓紫棋',age:18}
    }
    Person.prototype.fn = function(){
        console.log("我可以陪你去流浪~~~")
    }
    const p = mynew(Person,'薛之谦',20) // {name:'薛之谦',age:20}
    p.fn(); // 我可以陪你去流浪~~~   如果Person中return的是引用类型则没有fn方法

二、手写instanceof方法

instanceof是用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

js 复制代码
function myInstanceof(obj,constructor){
    // 如果是传入的是基本数据类型直接返回false
    if(typeof obj != 'object' || obj == null)return false;
    let proto = obj.__proto__;
    // 
    while(true){
        // 已经查到了最顶层
        if(proto == null)return false;
        // 说明在原型链上
        if(proto == constructor.prototype)return true;
        // 再查找到顶层对象之前依然没有找到则继续向上查找
        proto = proto.__proto__;
    }
}

console.log(myInstanceof({},Object)); // true
console.log(myInstanceof({},Array)); // false

三、手写call、apply、bind方法

三个方法的作用相同:改变函数运行时的this值。

三个方法的对比:

  1. callbind方法的参数是一个参数列表,apply方法的参数是一个数组
  2. callapply方法会立即执行函数,bind会返回一个新的函数,需要手动调用此函数才会获得执行结果

call

js 复制代码
// 为了让所有函数都能调用到我们自定义的方法,需要把方法定义到Function的原型上
// myCall方法中的this指向fn函数,thisArg指向的是目标对象
Function.prototype.myCall = function(thisArg,...args){
        // 如果传入的目标对象是undefined或null,就将this指向全局对象
        thisArg = thisArg || window
        // 目的是让fn成为目标对象的方法来运行,这样this便指向了目标对象(核心思路:根据谁调用函数this就指向谁的原则)
        thisArg.f = this;
        // 运行这个方法并传入剩余参数
        let result = thisArg.f(...args)
        // 返回值同fn原函数一样
        return result;
        
        
        /**
        * 到这里call的基本功能就完成了,但还存在一些问题:
        * 目标对象上会永远存在我们自定义的f属性,并且如果多个函数调用这个方法,而目标对象也相同,
          则存在目标对象的f属性被覆盖的可能
        * 我们可以通过以下两种方式解决:
        * 1、使用Symbol数据类型来定义对象的唯一属性名
        * 2、使用delete操作符删除对象中的某个属性
        * (一下代码与上面没有关联)
        */
        // 如果传入的目标对象是undefined或null,就将this指向全局对象
        thisArg = thisArg || window
        // 生成唯一属性名,解决覆盖的问题
        const prop = Symbol();
        // 注意这里不能使用.
        thisArg[prop] = this;
        // 运行这个方法,传入剩余参数,同样不能用.
        let result = thisArg[prop](...args);
        // 运行完删除属性
        delete thisArg[prop]
        return result;
}
// demo
function fn(name,age){
    console.log(name,age); // '薛之谦',20
    return '我的心愿是世界和平!'
}
let p = fn.myCall(obj,'薛之谦',20)
console.log(p); // 我的心愿是世界和平!

apply

apply和call的实现思路一样,只是传参方式不同

js 复制代码
Function.prototype.myApply = function (thisArg, args) {
    thisArg = thisArg || window;
    // 判断是否接收参数,若未接收参数,替换为[]
    args = args || []
    const prop = Symbol();
    thisArg[prop] = this;
    let result = thisArg[prop](...args);
    delete thisArg[prop];
    return result;
}

未完待续。。。。。。

时间就像海绵里的水,挤一挤总会有的!

相关推荐
东风西巷2 小时前
PDFgear:免费全能的PDF处理工具
前端·pdf·软件需求
森之鸟2 小时前
Mac电脑上如何打印出字体图标
前端·javascript·macos
mCell3 小时前
GSAP 入门指南
前端·javascript·动效
gnip3 小时前
组件循环引用依赖问题处理
前端·javascript
不要再敲了3 小时前
JDBC从入门到面试:全面掌握Java数据库连接技术
java·数据库·面试
Aotman_4 小时前
el-input textarea 禁止输入中文字符,@input特殊字符实时替换,光标位置保持不变
前端·javascript·vue.js·前端框架·es6
Nan_Shu_6144 小时前
Web前端面试题(1)
前端·面试·职场和发展
EveryPossible4 小时前
选择数据展示
javascript
lypzcgf4 小时前
Coze源码分析-资源库-创建知识库-前端源码-核心组件
前端·typescript·react·coze·coze源码分析·ai应用平台·agent开发平台