手写源码之Js中的 call() apply() bind()

news/2024/11/9 1:57:44/

说多无益, 直接上代码, 肯定还有一些不完善的地方, 我参考了一下
原生js源码之JavaScript的call方法,自己来实现

call()

'use strict'var person = {name: "Tom",sayHi(a, b) {// console.log('a', a)// console.log('b', b)// return this.name + " 在向你问好!" + a + breturn this.name + " 在向你问好!" + a.name + b.name;}
}var pig = {name: 'Jerry'
}/*** 只处理了 参数为 string, number, object 的情况* @returns any*/
Function.prototype.myCall = function() {if (arguments.length === 0) {return this()} else {// 第一个参数作为上下文let context = arguments[0]// 这两行判断写不写都行其实, 严格模式下不管怎样都会报错的if (context === null || context === undefined) return this()if (typeof context !== 'object') context = {}// this 是传入进来的函数, this.name 是函数名, 给传进来的 context 添加方法context[this.name] = thislet func = this.name + '('let arglet myArgs = []for (let i = 1; i < arguments.length; i++) {arg = arguments[i]console.log('arg', arg)if (typeof arg === 'string') {if (i === 1) {func += `'${arg}'`} else {func += `,'${arg}'`}} else if (typeof arg === 'number') {if (i === 1) {func += arg} else {func += "," + arg}} else if (typeof arg === 'object') {myArgs.push(arg)if (i === 1) {func += `myArgs[${i - 1}]`} else {func += `,myArgs[${i - 1}]`}}}func += ')'console.dir(func)// 拿到执行后的结果const result = eval('context.'+ func)// 删除新增的属性delete context[this.name]// 返回执行后的结果return result}
}// console.log(person.sayHi.myCall(pig, 1, 2))
console.log(person.sayHi.myCall(pig, { name: 'c' }, { name: 'd' }))
console.log(pig)

apply()

其实和 call() 没区别, 只是换了一下参数传入的形式

'use strict'var person = {name: "Tom",sayHi(a, b) {// console.log('a', a)// console.log('b', b)return this.name + " 在向你问好!" + a + b// return this.name + " 在向你问好!" + a.name + b.name;}
}var pig = {name: 'Jerry'
}/*** 只处理了 参数为 string, number, object 的情况* @returns any*/
Function.prototype.myApply = function() {if (arguments.length === 0) {return this()} else {// 第一个参数作为上下文let context = arguments[0]// 这两行判断写不写都行其实, 严格模式下不管怎样都会报错的if (context === null || context === undefined) return this()if (typeof context !== 'object') context = {}// this 是传入进来的函数, this.name 是函数名, 给传进来的 context 添加方法context[this.name] = thislet func = this.name + '('let arglet myArgs = []for (let i = 0; i < arguments.length; i++) {arg = arguments[1][i]console.log('arg', arg)if (typeof arg === 'string') {if (i === 0) {func += `'${arg}'`} else {func += `,'${arg}'`}} else if (typeof arg === 'number') {if (i === 0) {func += arg} else {func += "," + arg}} else if (typeof arg === 'object') {myArgs.push(arg)if (i === 0) {func += `myArgs[${i}]`} else {func += `,myArgs[${i}]`}}}func += ')'console.dir(func)// 拿到执行后的结果const result = eval('context.'+ func)// 删除新增的属性delete context[this.name]// 返回执行后的结果return result}
}console.log(person.sayHi.myApply(pig, [1, 2]))
// console.log(person.sayHi.myApply(pig, [{ name: 'c' }, { name: 'd' }]))
console.log(pig)

bind()

只是需要返回一个函数了

'use strict'var person = {name: "Tom",sayHi(a, b) {// console.log('a', a)// console.log('b', b)// return this.name + " 在向你问好!" + a + breturn this.name + " 在向你问好!" + a.name + b.name;}
}var pig = {name: 'Jerry'
}/*** 只处理了 参数为 string, number, object 的情况* @returns any*/
Function.prototype.myBind = function() {if (arguments.length === 0) {return this} else {let context = arguments[0]// 这两行判断写不写都行其实, 严格模式下不管怎样都会报错的if (context === null || context === undefined) return this()if (typeof context !== 'object') context = {}context[this.name] = thisconst that = thisreturn function() {let arglet func = that.name + '('let myArgs = []for (let i = 0; i < arguments.length; i++) {arg = arguments[i]if (typeof arg === 'string') {if (i === 0) {func += `'${arg}'`} else {func += `,'${arg}'`}} else if (typeof arg === 'number') {if (i === 0) {func += arg} else {func += "," + arg}} else if (typeof arg === 'object') {myArgs.push(arg)if (i === 0) {func += `myArgs[${i}]`} else {func += `,myArgs[${i}]`}}}func += ')'console.dir(func)const result = eval('context.' + func)delete context[that.name]return result}}
}console.log(person.sayHi.myBind(pig)({ name: 'c' }, { name: 'd' }))
// console.log(person.sayHi())

http://www.ppmy.cn/news/85143.html

相关文章

最全面的ETL工具选型指南

什么是ETL? ETL是数据仓库和数据集成领域常用的缩写&#xff0c;代表Extract, Transform, Load&#xff08;提取、转换、加载&#xff09;三个步骤。它是一种数据处理过程&#xff0c;用于从不同的数据源中提取数据、对数据进行转换和清洗&#xff0c;并将处理后的数据加载到…

【Ansys Fluent】All cell zones in Fluent may be automatically set to Fluid.

一、问题背景 在ansys meshing中保存划分完网格之后的结果时&#xff0c;弹出警报——All cell zones in Fluent may be automatically set to Fluid. 如果你忽视这个警报&#xff0c;打开fluent时。 接着就会将你想要设置为solid的区域识别成flow&#xff0c;从而生成一些错…

【MyBatisPlus框架】

文章目录 MyBatisPlus1.概述1.1 简介1.2特性1.3支持数据库1.4框架结构 2.入门案例2.1 创建数据库以及表2.2 创建工程2.2.1引入依赖 2.3编写代码 3.基本CRUD3.1BaseMapper3.2插入3.3删除3.4修改3.5查询3.6通用Service 4.常用注解4.1TableName4.1.1问题4.1.2通过TableName解决上述…

ChatGLM:清华开源本地部署(2023/05/06更新)

文章首发及后续更新&#xff1a;https://mwhls.top/4500.html&#xff0c;无图/无目录/格式错误/更多相关请至首发页查看。 新的更新内容请到mwhls.top查看。 欢迎提出任何疑问及批评&#xff0c;非常感谢&#xff01; 服务部署汇总 本来这篇是为了打比赛写的&#xff0c;写着写…

px rem em rpx 区别 用法

任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1em16px。那么12px0.75em,10px0.625em。为了简化font-size的换算&#xff0c;需要在css中的body选择器中声明Font-size62.5%&#xff0c;这就使em值变为 16px*62.5%10px, 这样12px1.2em, 10px1em, 也就是说只需要…

spring练习1

1、练习网站案例 1、建好相应的java类 package spring;public class Player {public int getId() {return id;}public void setId(int id) {this.id id;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getPosit…

Jmeter连接不同类型数据库语法

Jmeter连接不同类型数据库语法 添加&#xff1a;配置原件->JDBC Connection Configuration variable name for created pool&#xff1a;自定义一个线程池变量名database Connection Configuration database URL: 填写数据库ip、端口、dbname等&#xff0c;但是不同数据库…

分享50个AI绘画prompt的关键词,让你的AI绘画更贴近想法

我们在使用AI绘画工具时&#xff0c;最关键的就是prompt,但是我们不能总是拾人牙慧&#xff0c;总是用别人写出的现成的prompt,那样的话&#xff0c;最终画出来的画&#xff0c;也是别人画出来的&#xff0c;并不能完全生成自己想要的效果。所以&#xff0c;我们需要学习编写pr…