一. call和apply

1. 代码完整实现

Function.prototype.mycall = function (context, ...argus) {
if (typeof this !== 'function') {
throw new TypeError('not funciton')
}
const fn = this
let result = null context = context || window
context.fn = fn
result = context.fn(...argus)
delete context.fn return result
} Function.prototype.myapply = function (context, ...argus) {
if (typeof this !== 'function') {
throw new TypeError('not funciton')
}
const fn = this
let result = null context = context || window
argus = argus && argus[0] || []
context.fn = fn
result = context.fn(...argus)
delete context.fn return result
}

2. 先来溜溜

  • 案例一
class Member {
constructor (options) {
const {name, sex, age} = options
this.name = name
this.sex = sex
this.age = age
} introduce () {
console.log(`I'm ${this.name}, ${this.age}, ${this.sex}`)
}
} const member1 = new Member({
name: 'gina',
sex: 'girl',
age: 23
}) const member2 = new Member({
name: 'gun',
sex: 'boy',
age: 24
}) member2.introduce.mycall(member1) // I'm gina, 23, girl
member2.introduce.myapply(member1) // I'm gina, 23, girl

  

  • 案例二
Math.max.myapply(null, [1,2,3,4]) // 4
Math.max.mycall(null, 1,2,3,4) // 4

  

3. 注意要点

  • 开头需要做一个类型判断:
if (typeof this !== 'function') {
throw new TypeError('not funciton')
}
  • 获取原始函数: 比如执行Math.max.mycall(null, 1,2,3,4)的时候,mycall函数内部的this指向了Math.max函数,所以我们可以通过const fn = this获取到要执行的函数,然后将该函数绑定到传入的context对象(context.fn = fn),然后再把它删除掉delete context.fn

总体来说,call和apply的实现还是比较简单的。

二. bind

1. 完整代码实现

Function.prototype.mybind = function (context, ...argus) {
if (typeof this !== 'function') {
throw new TypeError('not funciton')
}
const fn = this
const fBound = function (...argus2) {
return fn.apply(this instanceof fBound ? this : context, [...argus, ...argus2])
}
fBound.prototype = Object.create(this.prototype)
return fBound
}

  

2. 边溜边说

  • 案例一
const foo = {
v: 1
}; function bar() {
return this.v;
} const bindFoo = bar.mybind(foo); bindFoo() // 1

bind 函数返回的是一个可执行函数,所以return了一个函数。此刻返回的函数,按正常来说,在执行的时候,this是指向执行处的当前上下文。但该案例中, mybind 需要满足bar在执行中返回值时,this依然是指向 foo,所以我们在mybind返回的函数中需要使用fn.apply来保持上下文和执行mybind的时候一致。

  • 案例二
const foo = {
v: 1
}; function bar(name, age) {
console.log(this.v);
console.log(name);
console.log(age); } const bindFoo = bar.bind(foo, 'daisy');
bindFoo('18');
// 1
// daisy
// 18

mybind 需要做到可以接受传参,并且将参数给到bar函数,后面再执行bindFoo再传的参数,会接在之前传参的后面。所以mybind源码中使用了[...argus, ...argus2]来进行参数整合。

  • 案例三
const value = 2;

const foo = {
value: 1
}; function bar(name, age) {
this.habit = 'shopping';
console.log(this.value);
console.log(name);
console.log(age);
} bar.prototype.friend = 'kevin'; const bindFoo = bar.bind(foo, 'daisy'); const obj = new bindFoo('18');
// undefined
// daisy
// 18
console.log(obj.habit);
console.log(obj.friend);
// shopping
// kevin

在执行const obj = new bindFoo('18')这一 new操作的时候,此刻this应该指向当前对象obj。所以mybindfn.apply的第一个参数,做了这样的判断this instanceof fBound ? this : context

const obj = new bindFoo('18')内部执行到this instanceof fBound ? this : context时,此刻this指向objfBound其实也就是bindFoothis instanceof fBound判断了obj是不是继承自bindFoo,也就是进行了构建函数new操作。

  • 案例4
function bar() {}

bar.prototype.value = 2

const bindFoo = bar.mybind(null);

bindFoo.prototype.value = 1;

console.log(bar.prototype.value) // 2

mybind 执行后返回的函数fBound修改prototype的时候,不应该影响到fn.prototype,两者应该是独立的。所以源码使用了fBound.prototype = Object.create(this.prototype), 而不是fBound.prototype = this.prototype

总得来说,bind的实现考虑的点还是比较多的。

参考:

https://github.com/mqyqingfeng/Blog/issues/12

js深入之call、apply和bind的更多相关文章

  1. js里function的apply vs. bind vs. call

    js里除了直接调用obj.func()之外,还提供了另外3种调用方式:apply.bind.call,都在function的原型里.这3种方法的异同在stackoverflow的这个答案里说的最清楚, ...

  2. js中call、apply、bind那些事

    前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call.apply.bind的问题,比如- 怎么利用call.apply来求一个数组中最大或者最小值 如何利用call.apply来做继承 ...

  3. js中call、apply、bind那些事2

    前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call.apply.bind的问题,比如… 怎么利用call.apply来求一个数组中最大或者最小值 如何利用call.apply来做继承 ...

  4. js中call、apply和bind到底有什么区别?

    介绍 在js中,每个函数的原型都指向Function.prototype对象(js基于原型链的继承).因此,每个函数都会有apply,call,和bind方法,这些方法继承于Function. 它们的 ...

  5. JS中call、apply、bind使用指南,带部分原理。

    为什么需要这些?主要是因为this,来看看this干的好事. box.onclick = function(){ function fn(){ alert(this); } fn();}; 我们原本以 ...

  6. js中call、apply、bind到底有什么区别?bind返回的方法还能修改this指向吗?

     壹 ❀ 引 同事最近在看angularjs源码,被源码中各种bind,apply弄的晕头转向:于是他问我,你知道apply,call与bind的区别吗?我说apply与call是函数应用,指定thi ...

  7. JS中call()和apply()以及bind()的区别

    一.方法定义: apply:调用一个对象的一个方法,用另一个对象替换当前对象.例如:B.apply(A, arguments);即A对象应用B对象的方法. call:调用一个对象的一个方法,用另一个对 ...

  8. JS中call()、apply()、bind()的用法

    其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例1 obj.objAge;  //17 obj.myFun()  //小张年龄undefined 例2 shows( ...

  9. js中call、apply和bind的区别

    在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢.在说区别之前还是先总结一下三者的相似之处:1.都是用来改变函数的this对象的指向的.2.第一个参数都是this要指向的对 ...

  10. js中call,apply,bind方法的用法

    call .apply.和bind 以上这三个方法都是js function函数当中自带的方法,用来改变当前函数this的指向. call()方法 语法格式: fun.call(thisArg[,ar ...

随机推荐

  1. Android零基础入门第34节:Android中基于监听的事件处理

    原文:Android零基础入门第34节:Android中基于监听的事件处理 上一期我们学习了Android中的事件处理,也详细学习了Android中基于监听的事件处理,同时学会了匿名内部类形式,那么本 ...

  2. Dependency Injection 筆記 (2)

    续上集,接着要说明如何运用 DI 来让刚才的范例程序具备执行时期切换实现类型的能力. (本文摘自電子書<.NET 依賴注入>) 入门范例—DI 版本 为了让 AuthenticationS ...

  3. 使用 acl 编写 UDP 网络程序(UDP 重传及可靠性机制)

    在当今网络世界,虽然大部分网络应用都是基于 TCP 的,但有时 UDP 的网络通信也有用武之处.acl 的网络库中不仅提供了基于 TCP 的网络套接字流,同时也提供了 UDP 的网络库(目前 acl ...

  4. JS基本类型特性总结

    本文代码测试环境: win7 32位,chrome 版本如下: 一,JS基本数据类型:Undefined, Null, Boolean, Number, String, Object六种. 1,Und ...

  5. 如何打造VUCA时代的敏捷型组织?

    王明兰 --原华为.微软创新与转型教练.华为云SaaS产品总监,著名精益&敏捷转型专家 VUCA最早来源于冷战时期,在现代世界意指商业世界越来越不确定性,越来越易变,越来越不可预测,我们已经进 ...

  6. 关于linux网卡消失的问题

    首先我也是一名学生,在学习的过程Linux的过程中,因为老师要求配置hadoop集群所以就匆匆忙忙的上手了,但是在配置网络的问题时遇到了网卡消失的问题 我在网上询问了许多的人,但是还是没有找到一个很好 ...

  7. 音视频技术“塔尖”之争,网易云信如何C位出道?

    音视频技术“塔尖”之争,网易云信如何C位出道? 社交+美颜.抖音短视频.在线狼人杀.直播竞答.子弹短信……,过往两三年间,互联网新产品和新玩法层出不穷,风口不断切换.这些爆红的网络应用背后,都有一些共 ...

  8. 给 Windows 的终端配置代理

    初衷 由于项目开发使用go,所以经常要用到go get,但是吧,terminal下根本没办法下载啊,经常下载三个小时包,写代码一个小时 迫于无奈,只好找个方式可以在terminal下使用ss cmd下 ...

  9. html更改弹窗样式(原创,转载需声明)

    代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <tit ...

  10. Mac和Windows以及Linux上WingIDE Pro激活

    写这篇文章的原因,主要是网上的很多激活方式都不适用最新版的软件.要么要你付费下载别人破解好的内容,要么各种文章你抄我,我抄你,根本没有自己实践过. 本篇文章合适Mac.Windows.Linux平台, ...