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

未完待续。。。。。。

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

相关推荐
中微子42 分钟前
React状态管理最佳实践
前端
烛阴1 小时前
void 0 的奥秘:解锁 JavaScript 中 undefined 的正确打开方式
前端·javascript
小兵张健1 小时前
武汉拿下 23k offer 经历
java·面试·ai编程
中微子1 小时前
JavaScript 事件与 React 合成事件完全指南:从入门到精通
前端
Hexene...1 小时前
【前端Vue】如何实现echarts图表根据父元素宽度自适应大小
前端·vue.js·echarts
初遇你时动了情1 小时前
腾讯地图 vue3 使用 封装 地图组件
javascript·vue.js·腾讯地图
dssxyz1 小时前
uniapp打包微信小程序主包过大问题_uniapp 微信小程序时主包太大和vendor.js过大
javascript·微信小程序·uni-app
爱莉希雅&&&1 小时前
技术面试题,HR面试题
开发语言·学习·面试
天天扭码2 小时前
《很全面的前端面试题》——HTML篇
前端·面试·html
xw52 小时前
我犯了错,我于是为我的uni-app项目引入环境标志
前端·uni-app