🔥 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;
}

未完待续。。。。。。

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

相关推荐
kyriewen18 分钟前
我受够了复制报错去问 AI,花一下午给控制台做了个调试助手
前端·javascript·ai编程
Scabbards_1 小时前
面试Leetcode - Heap 堆
java·leetcode·面试
IT_陈寒1 小时前
Redis的DEL命令竟然没删掉数据?我踩的这个坑你得知道
前端·人工智能·后端
anOnion1 小时前
构建无障碍组件之Menu and Menubar Pattern
前端·html·交互设计
黄敬峰1 小时前
🐳 Docker 从入门到实战:一次搞定容器化 + Nginx 反向代理
面试
JavaGuide1 小时前
我用 Claude Code/ZCode+GLM-5.3 从零做了一款 Agent 游戏!
前端·后端
Eason_Lou2 小时前
vue flow使用注意事项
前端·vue.js
程序员清风2 小时前
专业再升级!程序员专属显示器明基RD280UG上手实测!
java·后端·面试
JJJennie7772 小时前
Gemini 3.7 Flash 上线,Google 想让 AI 多干活
开发语言·javascript·ecmascript
小赵同学WoW2 小时前
1-2 TypeScript 中的 `any` 与 `unknown`
前端