面试官: 请你手写一份 Call()源码,看完此篇不用担心!

前言

一盏茶的功夫带你掌握烦人的this指向问题

在上篇文章中,我们讲到了this的五种绑定规则,了解了这五种绑定规则对this的指向问题可以不用再害怕,对this或是五种绑定规则不太熟悉的小伙伴,建议先去看看我的上篇文章,文章链接已放在上面,配合本章食用效果更佳~

今天我们要讲的是显示绑定中的一种方法,call()方法的源码,我们在面试的过程中,面试官大大有时会叫我们手写一个call()的源码,这时候有些小伙伴就会慌了,其实call()就是靠隐式绑定实现的,我们先来复习一下隐式绑定规则显式绑定规则

隐式绑定

如果函数被一个对象作为方法所调用时,那么this就会指向该对象。我们来看一个例子:

js 复制代码
function foo() {
    console.log(this.a);
  }
  var obj = {
    a: '来颗奇趣蛋',
    func: foo
}
obj.func()

调用 objfunc 方法,在这一步,func 方法被作为 obj 对象的方法调用,因此隐式绑定规则会将 this 绑定到 obj。因此,this.a 将打印出 obj 对象的属性 a 的值:

我们来看看输出结果:

显示绑定 ---call, apply, bind

显示绑定是我们通过call,apply,bind,改变this的指向,我们一起来看看例子:

js 复制代码
function foo() {
    console.log(this.a);
}

var obj = {
    a: 2
}

foo()

如果这样调用foo(),那么就是this默认绑定,this指向全局,那么输出undefined,那么我们怎么让this指向obj,输出2呢?

1。 使用call()

js 复制代码
function foo() {
    console.log(this.a);
}

var obj = {
    a: 2
}

foo.call(obj)

call的作用就是强行把foo中的this指向obj,我们来输出以下来看看:

我们今天就主要讲讲call(),对另外两种方法感兴趣的小伙伴们可以点击链接去那篇文章看看。

call()源码

func.call(obj)为什么可以将函数functhis指向绑定的对象obj,这是因为call()干了一个操作,它先将函数func放进obj里面,然后obj.func(),使函数作为对象的方法调用,达成隐式绑定的规则,这样就成功使函数func中的this指向obj,之后再将对象object内部的func给删除。我们用伪代码来看一下:

js 复制代码
{
    func: func
}
obj.func()
delete obj.func

这样大家是不是了解一些call()方法的底层逻辑了呢?它就是通过隐式绑定规则,将函数中的this指向对象obj中。

自己打造一份call()源码

在面试过程中,面试官有时会叫我们自己打造一份call(),功能需要跟call()一样,我们一起来看看怎么实现吧:

js 复制代码
Function.prototype.myCall = function (context) {
    if (!this instanceof Function) {
        throw new TypeError('myCall is not a function')
    }
    context.fn = this
    context.fn()
    delete context.fn
}

这段代码是一个简化版的 call 方法的自定义实现,添加到 Function 原型上,可以用 myCall 来模拟 call 方法。让我逐步解释这段代码:

js 复制代码
Function.prototype.myCall = function (context) {
    if (!this instanceof Function) {
        throw new TypeError('myCall is not a function');
    }
    context.fn = this;
    context.fn();
    delete context.fn;
};
  1. Function.prototype.myCall: 这一行将一个自定义的 myCall 方法添加到 Function 的原型上。这样一来,所有的函数对象都可以调用这个方法。
  2. throw new TypeError('myCall is not a function'): 如果检测到 this 不是函数,抛出一个类型错误。
  3. context.fn = this: 在传入的 context 对象上创建一个名为 fn 的属性,并将其值设置为调用 myCall 方法的函数(this)。
  4. context.fn():context 上调用 fn 方法,即调用了原始函数,并且此时 this 就是 context 对象。
  5. delete context.fn: 删除 context 上的 fn 属性,以防止给 context 对象添加了不必要的属性。

我们来验证一下此函数有没有实现call()的功能:

js 复制代码
var obj = {
    a: 1,
}
function foo(x, y) {
    console.log(this.a);
}    

Function.prototype.myCall = function (context) {
    if (!this instanceof Function) {
        throw new TypeError('myCall is not a function')
    }
    context.fn = this
    context.fn()
    delete context.fn
}

foo.myCall(obj)

我们来输出一下:

可以看到,输出了 1,说明函数中的this已经指向了对象obj,我们这个手写函数也算是实现了call()的功能啦。

不过,我们在实际项目中,应使用原生的 call 方法,因为它已经经过严格的测试和优化。

相关推荐
2分钟速写快排30 分钟前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60611 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角2 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!2 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰3 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
Interview Aid1123 小时前
Walmart Global Tech SDE 三轮面经|基础、并发、压力面
面试·职场和发展
mayaairi4 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen5 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马5 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu5 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss