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

未完待续。。。。。。

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

相关推荐
weixin-a1530030831622 分钟前
vue疑难解答
前端·javascript·vue.js
Bellafu6663 小时前
selenium 常用xpath写法
前端·selenium·测试工具
blackorbird6 小时前
Edge 浏览器 IE 模式成攻击突破口:黑客借仿冒网站诱导攻击
前端·edge
uzong6 小时前
一次慢接口背后,竟藏着40+种可能!你中过几个
后端·面试·程序员
谷歌开发者7 小时前
Web 开发指向标 | Chrome 开发者工具学习资源 (一)
前端·chrome·学习
名字越长技术越强7 小时前
Chrome和IE获取本机ip地址
前端
天***88967 小时前
Chrome 安装失败且提示“无可用的更新” 或 “与服务器的连接意外终止”,Chrome 离线版下载安装教程
前端·chrome
半梦半醒*7 小时前
zabbix安装
linux·运维·前端·网络·zabbix
大怪v8 小时前
【搞发🌸活】不信书上那套理论!亲测Javascript能卡浏览器Reader一辈子~
javascript·html·浏览器
清羽_ls8 小时前
React Hooks 核心规则&自定义 Hooks
前端·react.js·hooks