hn-failte's blog hn-failte's blog
首页
  • 前端文章

    • JavaScript
    • Vue
    • React
    • Webpack
    • 混合开发
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《React》笔记
    • 《TypeScript 从零实现 axios》
    • 《Git》学习笔记
    • TypeScript笔记
    • JS设计模式总结笔记
  • HTML&CSS
  • HTML
  • CSS
  • CSS预处理
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 算法
  • 数据库
  • 操作系统
  • 工具
  • 学习
  • 面试
  • 心情杂货
  • 前端相关
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

hn-failte

前端cv仔
首页
  • 前端文章

    • JavaScript
    • Vue
    • React
    • Webpack
    • 混合开发
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《React》笔记
    • 《TypeScript 从零实现 axios》
    • 《Git》学习笔记
    • TypeScript笔记
    • JS设计模式总结笔记
  • HTML&CSS
  • HTML
  • CSS
  • CSS预处理
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 算法
  • 数据库
  • 操作系统
  • 工具
  • 学习
  • 面试
  • 心情杂货
  • 前端相关
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Webpack

  • React

  • JavaScript

    • new命令原理
    • ES5面向对象
    • ES6面向对象
    • 多种数组去重性能对比
    • JS随机打乱数组
    • 判断是否为移动端浏览器
    • 将一维数组按指定长度转为二维数组
    • 防抖与节流函数
    • JS获取和修改url参数
    • 比typeof运算符更准确的类型判断
    • 三级目录

    • JavaScript

      • JavaScript之函数尾调用与函数尾递归
      • 一种实现call、apply、bind的方法
        • 实现bind
        • 实现call
        • 实现apply
        • 使用
        • 测试
        • github地址
      • 实现call、apply、bind
      • JavaScript闭包详解
      • 窗口间的通信与iframe跨域
      • JavaScript逻辑运算符“&&”和“||”短路原则的应用
      • Object原型梳理
      • JavaScript设计模式之发布&订阅模式
      • JavaScript核心:两链一包
      • JavaScript之正则
      • 字符串拼接性能优化
      • JavaScript变量转换
  • Vue

  • 混合开发

  • 学习笔记

  • 微信小程序

  • 前端
  • JavaScript
  • JavaScript
hn-failte
2019-04-16

一种实现call、apply、bind的方法

# 一种实现call、apply、bind的方法

面试官:请你手动实现一个call、apply、bind

!!!什么?

# 实现bind

module.exports = function(Tcontext, ...args) {
  let globalThis = typeof window === "undefined" ? global : window;
  let context = typeof Tcontext === "undefined" ? globalThis : Tcontext;
  let withArgs = args.length != 0; //是否传参
  if (!!this.prototype && typeof context === "object" && context !== null) {
    //context是有效对象
    return withArgs
      ? () => Object.assign(context, new this(...args)) //若带参,返回的函数不需要处理接收参数
      : (...args) => Object.assign(context, new this(...args)); //若不带参,返回的函数需要处理接收参数
  } else {
    return withArgs
    ? ()=>this(...args)
    : (...args)=>this(...args)
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 实现call

在实现了bind后,只需要将call转换给bind处理就可以了

module.exports = function(context, ...args){
    return this.newBind(context, ...args)()
}
1
2
3

# 实现apply

实现了call后,只需要处理下参数,转换给call处理就可以了

module.exports = function(context, args){
    return args instanceof Array?this.newCall(context, ...args):this.newCall(context)
}
1
2
3

# 使用

const newBind = require("./bind")
const newCall = require("./call")
const newApply = require("./apply")

Function.prototype.newBind = newBind //将bind挂载到Function原型,使得任何实例可以像使用bind一般使用newBind
Function.prototype.newCall = newCall //将call挂载到Function原型,使得任何实例可以像使用call一般使用newCall
Function.prototype.newApply = newApply //将apply挂载到Function原型,使得任何实例可以像使用apply一般使用newApply
1
2
3
4
5
6
7

在挂载到原型上后,就可以正常使用了

# 测试

1、bind的测试

require(".") //导入模块

const obj = {
    q: "1"
}

const Parent = function(a, b){
    this.a = a;
    this.b = b
}

//一、使用bind的函数是构造函数,context是有效对象
//测试bind带参,执行函数不带参的情况
try {
    console.log(Parent.newBind(obj,3,2)())
} catch (error) {
    if(error.toString()=="Illegal context") console.log("err")
    else console.log("Failed")
}

//测试bind带参,执行函数带参的情况 => 执行函数的参数不生效
try {
    console.log(Parent.newBind(obj,3,2)(3,4))
} catch (error) {
    if(error.toString()=="Illegal context") console.log("err")
    else console.log("Failed")
}

//测试bind不带参的情况,执行函数不带参的情况 => 执行函数的参数应为undefined
try {
    console.log(Parent.newBind(obj)())
} catch (error) {
    if(error.toString()=="Illegal context") console.log("err")
    else console.log("Failed")
}

//测试bind带参,执行函数带参的情况 => 执行函数的带参应生效
try {
    console.log(Parent.newBind(obj)(3,4))
} catch (error) {
    if(error.toString()=="Illegal context") console.log("err")
    else console.log("Failed")
}


//二、使用bind的函数是构造函数,context是无效对象
//测试bind带参,执行函数不带参的情况
console.log(Parent.newBind(null,3,2)())

//测试bind带参,执行函数带参的情况
console.log(Parent.newBind(null,3,2)(3,4))

//测试bind不带参的情况,执行函数不带参的情况
console.log(Parent.newBind(null)())

//测试bind带参,执行函数带参的情况
console.log(Parent.newBind(null)(3,4))

//三、使用bind的函数不是构造函数
console.log(Math.pow.newBind(obj, 3, 2)())
console.log(Math.pow.newBind(null, 3, 2)())
console.log(Math.pow.newBind(1, 3, 2)())
console.log(Math.pow.newBind(null)(2,3))


console.log("测试完成")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

2、call的测试

require(".") //导入模块

const obj = {
    q: "1"
}

const Parent = function(a, b){
    this.a = a;
    this.b = b
}

//一、使用call的函数是构造函数,context是有效对象
//测试call带参
try {
    console.log(Parent.newCall(obj,3,2))
} catch (error) {
    if(error.toString()=="Illegal context") console.log("err")
    else console.log("Failed")
}


//测试call不带参的情况 => 执行函数的参数应为undefined
try {
    console.log(Parent.newCall(obj))
} catch (error) {
    if(error.toString()=="Illegal context") console.log("err")
    else console.log("Failed")
}

//二、使用call的函数是构造函数,context是无效对象
//测试call带参
console.log(Parent.newCall(null,3,2))

//测试call不带参的情况
console.log(Parent.newCall(null))

//三、使用call的函数不是构造函数
console.log(Math.pow.newCall(obj, 3, 2))
console.log(Math.pow.newCall(null, 3, 2))
console.log(Math.pow.newCall(1, 3, 2))


console.log("测试完成")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

3、apply的测试

require(".") //导入模块

const obj = {
    q: "1"
}

const Parent = function(a, b){
    this.a = a;
    this.b = b
}

//一、使用apply的函数是构造函数,context是有效对象
//测试apply带参
try {
    console.log(Parent.newApply(obj,[3,2]))
} catch (error) {
    if(error.toString()=="Illegal context") console.log("err")
    else console.log("Failed")
}


//测试apply不带参的情况 => 执行函数的参数应为undefined
try {
    console.log(Parent.newApply(obj))
} catch (error) {
    console.log(error);
    if(error.toString()=="Illegal context") console.log("err")
    else console.log("Failed")
}

//二、使用apply的函数是构造函数,context是无效对象
//测试apply带参
console.log(Parent.newApply(null,[3,2]))

//测试apply不带参的情况
console.log(Parent.newApply(null))

//三、使用apply的函数不是构造函数
console.log(Math.pow.newApply(obj, [3, 2]))
console.log(Math.pow.newApply(null, [3, 2]))
console.log(Math.pow.newApply(1, [3, 2]))
console.log(Math.pow.newApply(1, 3, 2)) //第二个参数不为数组,结果应异常


console.log("测试完成")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

经过测试,实现call、apply、bind基本功能是ok的

# github地址

源码 (opens new window)

编辑 (opens new window)
#Polyfill
上次更新: 2021/08/05, 12:37:41
JavaScript之函数尾调用与函数尾递归
实现call、apply、bind

← JavaScript之函数尾调用与函数尾递归 实现call、apply、bind→

最近更新
01
基于 Taro 的微信小程序优化指南
02-16
02
搭建一个极简混合开发架构
08-03
03
使用State Hook
04-06
更多文章>
Theme by Vdoing | Copyright © 2017-2023 hn-failte | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式