「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」
知识讲解
call、apply、bind的功能就是改变this的指向、只是三个函数的参数风格不太一样。
call函数实现
[function].call([this], [param]...),一句话概括:call()
将函数的 this
指定到 call()
的第一个参数值同时将剩余参数指定的情况下调用某个函数或方法。
用测试用例描述
it("测试call方法", () => {
const { call } = require("../index");
Function.prototype.myCall = call;
const obj = { a: 1 };
const f = function (...args) {
return { context: this, args };
};
expect(f.myCall(obj, 1, 2)).toEqual({ context: { a: 1 }, args: [1, 2] });
});
代码实现
exports.call = function (context, ...args) {
// this 为调用方法 例:f.call this = f
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
};
讲解
- f.myCall函数调用时,this上下文其实是f函数。
- 需要的绑定的上下文用参数context传入
- 其余参数使用展开语法表示
- 首先将函数绑定到上下文对象中
- 删除context上线文中的fn方法清理现场
- 返回执行结果
apply的实现
call方法和apply方法类似,两者唯一不同的是,执行参数是是一个数组而不是多个参数
测试用例表示
it("测试apply方法", () => {
const { apply } = require("../index");
Function.prototype.myApply = apply;
const obj = { a: 1 };
const f = function (...args) {
return { context: this, args };
};
expect(f.myApply(obj, [1, 2])).toEqual({ context: { a: 1 }, args: [1, 2] });
});
代码实现
由于变动非常小甚至可以直接调用call函数完成
exports.apply = function (context, args) {
return this.call(context,...args)
};
正经代码是这样
exports.apply = function (context, args) { // 只需要变动一行 ...args => args
// this 为调用方法 例:f.call this = f
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
};
bind函数
bind返回fun的拷贝,并指定了fun的this指向,保存了fun的参数。
测试用例表示
it("测试bind方法", () => {
const { bind } = require("../index");
Function.prototype.myBind = bind;
const obj = { a: 1 };
const f = function (...args) {
return { context: this, args };
};
expect(f.bind(obj, 1, 2)(3, 4)).toEqual({
context: { a: 1 },
args: [1, 2, 3, 4],
});
});
代码实现
exports.bind = function (context, ...args) {
// this 为调用方法 例:f.call this = f
const f = this;
return function F() {
return f.apply(context, [...args, ...arguments]);
};
};
- 实现一个工厂函数
- 使用apply指向函数
- 使用传入的context作为上下文
- 将bind传入的执行参数与执行F()时传入的参数合并作为执行参数
面试攻略
这个就是一道经典的手写代码题。
🔥2022然叔坚持打卡365天
大家一波一键三连和然叔一起呀
Day1 - JS 整数是怎么表示的?
Day2 - 0.1 + 0.2 === 0.3 嘛?为什么?怎么解决?
Day3 - Number() 的存储空间是多大?如果后台发送了一个超过最大限制的数字怎么办?
Day4 - 判断数据类型的方式有哪些?
Day5 - new 一个函数发生了什么?
Day6 - new 一个构造函数,如果函数返回 return {}
、 return null
, return 1
, return true
会发生什么情况?
Day7 - 分析一下箭头语法为什么不能当做构造函数
Day8 - 什么是闭包?如何产生闭包
Day9 - 如何用闭包制造惰性函数?
Day14 - 词法作用域、块级作用域、作用域链、静态动态作用域
Day10 - 闭包与科里化、偏应用函数的关系
Day11 - 谈谈闭包与即时函数的应用
Day12 - 如何利用闭包完成类库封装
Day13 - 如何用闭包完成模块化(Webpack原理)
Day15 - let为什么能够解决循环陷阱
Day16 - 为什么一定要有块级作用域?
Day17 - let是否会造成变量提升
Day18 - 介绍一下this指向4种形式
Day19 - React中的事件绑定与箭头函数
===============