js深入之call、apply和bind
一. 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。所以mybind在fn.apply的第一个参数,做了这样的判断this instanceof fBound ? this : context。
在const obj = new bindFoo('18')内部执行到this instanceof fBound ? this : context时,此刻this指向obj,fBound其实也就是bindFoo,this 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的更多相关文章
- js里function的apply vs. bind vs. call
js里除了直接调用obj.func()之外,还提供了另外3种调用方式:apply.bind.call,都在function的原型里.这3种方法的异同在stackoverflow的这个答案里说的最清楚, ...
- js中call、apply、bind那些事
前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call.apply.bind的问题,比如- 怎么利用call.apply来求一个数组中最大或者最小值 如何利用call.apply来做继承 ...
- js中call、apply、bind那些事2
前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call.apply.bind的问题,比如… 怎么利用call.apply来求一个数组中最大或者最小值 如何利用call.apply来做继承 ...
- js中call、apply和bind到底有什么区别?
介绍 在js中,每个函数的原型都指向Function.prototype对象(js基于原型链的继承).因此,每个函数都会有apply,call,和bind方法,这些方法继承于Function. 它们的 ...
- JS中call、apply、bind使用指南,带部分原理。
为什么需要这些?主要是因为this,来看看this干的好事. box.onclick = function(){ function fn(){ alert(this); } fn();}; 我们原本以 ...
- js中call、apply、bind到底有什么区别?bind返回的方法还能修改this指向吗?
壹 ❀ 引 同事最近在看angularjs源码,被源码中各种bind,apply弄的晕头转向:于是他问我,你知道apply,call与bind的区别吗?我说apply与call是函数应用,指定thi ...
- JS中call()和apply()以及bind()的区别
一.方法定义: apply:调用一个对象的一个方法,用另一个对象替换当前对象.例如:B.apply(A, arguments);即A对象应用B对象的方法. call:调用一个对象的一个方法,用另一个对 ...
- JS中call()、apply()、bind()的用法
其实是一个很简单的东西,认真看十分钟就从一脸懵B 到完全 理解! 先看明白下面: 例1 obj.objAge; //17 obj.myFun() //小张年龄undefined 例2 shows( ...
- js中call、apply和bind的区别
在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢.在说区别之前还是先总结一下三者的相似之处:1.都是用来改变函数的this对象的指向的.2.第一个参数都是this要指向的对 ...
- js中call,apply,bind方法的用法
call .apply.和bind 以上这三个方法都是js function函数当中自带的方法,用来改变当前函数this的指向. call()方法 语法格式: fun.call(thisArg[,ar ...
随机推荐
- Android零基础入门第55节:ImageSwitcher和TextSwitcher使用
原文:Android零基础入门第55节:ImageSwitcher和TextSwitcher使用 上一期我们了解了ViewAnimator组件和ViewSwitcher组件的使用,你都掌握了吗?本期一 ...
- missing equal sign
"UPDATE TB_BOOKINGSET REC_LOC_CODE = ?,CUSTOMER_ADDR?WHERE BOOKING_NO=? AND TRANSPORT_MODE=? &q ...
- 深度网络中的Tricks
数据增强(Data augmentation) 预处理(Pre-processing) 初始化(Initializations) 训练中的Tricks 激活函数(Activation function ...
- Qt中实现单例模式(SingleTon),大约有3种办法
Qt中实现单例模式(SingleTon) 单例模式分为“饥汉”和“饿汉”两种版本,也正是线程安全问题使得原本简单的单例模式变得复杂.由于单例模式很常用,Boost库中有强大的泛型单例实现,我也利用Qt ...
- 用node.js(socket.io)实现数据实时推送
在做商品拍卖的时候,要求在商品的拍卖页面需要实时的更新当前商品的最高价格.实现的方式有很多,比如: 1.setInterval每隔n秒去异步拉取数据(缺点:更新不够实时) 2. AJAX轮询方式方式推 ...
- modelform组件以及ChoiceField属性
一. Forms组件补充 1.__init__() 如果继承forms.Form的类中的每一个字段,或者大部分字段都做了相同的约束,可以将该约束放到__init__中编写 实例:每一个字段都需要添加f ...
- echarts 中国地图标注所在点
达到的效果: 1.本身是个中国地图‘ 2.直接通过经纬度标注 3.标注点可以是其他样子(比如:五角星) 4.标注点具有提示框并且鼠标可以进入 5.提示框里的链接可点击(可以添加为链接事件): 所需要技 ...
- java基础(1)-几种获取类的扩展方式
摘要 在日常开发过程中经常需要获取类的扩展集.即获取类的子类集(抽象类),或者接口实现类.比如说状态模式中,状态构建类,策略模式中的,策略构造方式.本文介绍几种获取方式. 实现 以策略模式为例 定义了 ...
- 【练习题】proj1 判断二叉树子树和是否为指定的值
#include <stdio.h> #include <vector> #include <list> #include<iostream> usin ...
- java编程思想之面向对象
面向对象和面向过程 面向对象(Object Oriented),简称OO,是软件开发方法的一种,我们都知道java是基于面向对象开发的,但是说到面向对象,我们不得不提一提面向过程开发,面向过程,又称结 ...