分享一个基础面试题---手写call

分享一个基础面试题---手写call

  • 手写call笔记
    • 第一步
    • 第二步
    • 第三步

手写call笔记

call():在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法。

let foo = {value:1
};
function bar(){console.log(this.value);
}
bar.call(foo);//1

注意两点:

  1. call改变了this的指向,指向到foo;
  2. bar 函数执行了;

第一步

上述方式等同于:

let foo = {value:1;bar:function(){console.log(this.value)}
};
foo.bar();//1

这个时候this就指向了foo,但是这样却给foo对象本身添加了一个属性,所以我们用delete再删除它即可。
所以我们模拟的步骤可以分为:

  1. 将函数设为对象的属性;
  2. 执行该函数;
  3. 删除该函数;

以上个例子为例,就是:

//第一步
//fn 是对象的属性名,反正最后也要删除它,所以起什么名字都可以。
foo.fn = bar
//第二步
foo.fn()
//第三步
delete foo.fn

根据上述思路,提供一版:

//第一版
//将foo作为context参数传递
Function.prototype.call2 = function(context){//首先要获取调用call的函数,用this可以获取//将函数设为对象的属性context.fn = this;//执行该函数context.fn();//删除该函数delete context.fn;
}

第二步

call除了可以指定this,还可以指定参数

var foo = {value:1
};
function bar(name,age){console.log(name);console.log(age);console.log(this.value);
}
bar.call(foo,'ken',18);

可以从Arguments对象中取值,取出第二个到最后一个参数,然后放到一个数组里。
上述代码的Arguments中取第二个到最后一个参数。

//以上个例子为例,此时的arguments为:
// arguments = {
//		0:foo,
//		1:'ken',
//		2:18,
//		length:3
//}
//因为arguments是类数组对象,所以可以用for循环
var args = [];
for(var i = 1,len = arguments.length;i<len;i++){args.push('arguments['+i+']');
}
//执行后args 为["arguments[1]","arguments[2]","arguments[3]"]

接下来使用eval拼接成一个函数

eval('context.fn('+args+')')

考虑到目前大部分浏览器在console中限制eval的执行,也可以使用rest
此处代码为:

//第二版
Function.prototype.call2 = function(context){context.fn = this;let arg = [...arguments].slice(1);context.fn(...arg);delete context.fn;
}
//测试一下
var foo = {value:1
};
function bar(name,age){console.log(name);console.log(age);console.log(this.value);
}
bar.call2(foo,'ken',18)
//ken
//18
//1

第三步

  1. this参数可以传null,当为null的时候,视为指向window
    举个例子:
var value = 1;
function bar(){console.log(this.value);
}
bar.call(null);//1
  1. 针对函数,可以实现返回值
var obj = {value:1
};
function bar(name,age){return{value:this.value,name:name,age:age}
}
console.log(bar.call(obj,'ken',18));
//Object{
//		value:1,
//		name:'ken',
//		age:18
//}

第三版:

Function.prototype.call3=function(context){//1.this为null,也可以写为=>context ?? window 或者 context=context??windowvar context = context || window;context.fn = this;let arg = [...arguments].slice(1)let result = context.fn(...arg)delete context.fn//2.有返回值return result
}
//测试一下
var value = 2;
var obj = {value:1
}
function bar(name,age){console.log(this.value);return{value:this.value,name:name,age:age}
}
bar.call3(null);//2
console.log(bar.call3(obj,'ken',18));//1
//Object{
//		value:1,
//		name:'ken',
//		age:18
//}

这边给出的简化写法:

Function.prototype.call3 = function(context,..args){//判断是否是undefined和nullif (typeof context === 'undefined' || context === null){context = window}//每个从Symbol()返回的symbol值都是唯一的let fnSymbol = Symbol()context[fnSymbol] = this//入参...args === [...arguments].slice(1);let fn = context[fnSymbol](...args)//删除目的是不污染原来数据delete context[fnSymbol]return fn
}

可能会有新手宝宝们看完觉得还是很晦涩,可以动手写一遍试试,不行再多写两遍,好记性不如烂键盘,脑子再快也不如肌肉记忆哈哈哈~
当然也可以留言讨论啦~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/255447.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序开发之原生小程序开发和uniapp开发的区别,两种开发方式语法上的区别

目前小程序开发有两种形式&#xff0c;分别是原生小程序开发和使用uniapp开发&#xff0c; uniapp和小程序原生开发都有各自的优缺点&#xff0c;开发者可以根据具体需求选择合适的开发方式。 一、两者区别如下&#xff1a; 编程语言&#xff1a;uniapp使用Vue语法编写应用程序…

内测分发平台支持应用的异地容灾的重要性

大家好&#xff0c;我是咕噜-凯撒&#xff0c;随着网络社会的发展&#xff0c;人们对于应用程序的依赖程度越来越高。无论是企业用户还是个人用户&#xff0c;都希望能够随时随地访问到需要使用的应用。所以对于内测分发平台来说保证应用的连续性和可靠性是非常的关键。内侧分发…

惠普台式机如何关闭UEFI

惠普台式机如何关闭UEFI 1、开机一直按按ESC&#xff0c;出现以下界面后&#xff0c;再按F10进入BIOS。 2.选择安全–>安全引导配置–>按F10接受 3.把旧支持 启用&#xff0c;安全引导 禁用 按F10接受 4.保存并退出更改 5.重启后看一下引导顺序&#xff0c;如果旧引导源已…

[MySQL] MySQL中的内置函数

本篇文章主要是对MySQL中常见的内置函数进行了详细解释。例如有日期类函数、字符串类函数、数学类函数等等。希望本篇文章会对你有所帮助。 文章目录 一、日期类函数 1、1 使用详解 1、2 实例演示 二、字符串函数 2、1 使用详解 2、2 实例演示 三、数学函数 四、其他函数 &…

Java 实现TCP一对一聊天,UDP协议实现群聊

用TCP编程实现一对一式聊天&#xff0c;并用多线程解决了处于同一线程中的问题。 客户端代码&#xff1a;mport java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.ut…

python深浅拷贝

【 一 】Python 深拷贝和浅拷贝概念理解 个人见解&#xff1a; 浅拷贝&#xff0c;指的是重新分配一块内存&#xff0c;创建一个新的对象&#xff0c;但里面的元素是原对象中各个子对象的引用。 深拷贝&#xff0c;是指重新分配一块内存&#xff0c;创建一个新的对象&…

Axure动态面板控制

首先创建一个项目&#xff0c;拖拽几个矩形喝一个动态面板 然后双击动态面板添加状态state1,state2,state3 然后分别在state1,state2,state3编辑导航对应的内容。 接下来就是添加交互事件&#xff0c;将不同导航对应不同的state. 点击“交互”->鼠标点击->进入交互编辑…

数组常用方法

1、filter 筛选 筛选数组中带有某个id的对象 let list[{id:1,name:111},{id:2,name:222},{id:3,name:333},]; let alist.filter((item)>{return item.id1 }); console.log(a)2、findIndex var idx list.findIndex((item) > {return item 2;});返回的idx是该元素在数组…

Vellum —— Vellum Solver

目录 Solver Collision Forces Advanced Secondary Constraint Pass Multi-Pass Solve Motion Sleeping Grain Collisions Fluids Minimal Solver Vellum Solver SOP是DOP的封装&#xff0c;以简化vellum的解算&#xff1b;第一个端口是geometry&#xff0c;第二个…

软件系统应用开发安全指南

2.1.应用系统架构安全设计要求 2.2.应用系统软件功能安全设计要求 2.3.应用系统存储安全设计要求 2.4.应用系统通讯安全设计要求 2.5.应用系统数据库安全设计要求 2.6.应用系统数据安全设计要求 全资料获取进主页。

Java多线程:代码不只是在‘Hello World‘

Java线程好书推荐 概述01 多线程对于Java的意义02 为什么Java工程师必须掌握多线程03 Java多线程使用方式04 如何学好Java多线程写在末尾&#xff1a; 主页传送门&#xff1a;&#x1f4c0; 传送 概述 摘要&#xff1a;互联网的每一个角落&#xff0c;无论是大型电商平台的秒杀…

汽车电子 -- CAN文件格式ASC

Vector提供了两种记录数据格式的格式规范&#xff1a;BLF和ASC。 先讲讲ASC。 参看&#xff1a;图文详解CAN Log文件 - ASC文件格式 一、ASC文件格式 在Vector提供的 CAN_LOG_TRIGGER_ASC_Format.pdf 提取码&#xff1a;ltjv 文件中&#xff0c;规定了CANoe/CANalyzer ASC记…