关于绑定首先要说下this的指向问题。

我们都知道:

函数调用时this指向window

对象调用函数时this指向对象本身

看下面得例子:

// 1
function test(){
const name = 'test1';
console.log(this.name)
}
constname = 'test2'
test() // test2
// 当前函数调用指向了window,所以打印的为test2 // 2
var obj = {
name:'test1',
get(){
console.log(this.name)
}
}
var name = 'test2';
obj.get() // test1
// 当前通过对象调用。this指向obj,打印test1 // 3
var obj = {
name:'test1',
get(){
console.log(this.name)
}
}
var name = 'test2';
var fn = obj.get;
fn() // test2
// 将obj.get作为值赋值给fn,执行fn,这时候相当于通过函数执行,this重新指向

那如何将this指向到我们指定的对象中呢?

js提供改变this指向的三种方法:call、apply、bind

其中call和apply执行改变this的同时会执行函数,bind是会返回一个函数。

而call与apply的区别在于参数,call可以传多个参数,而apply传一个数组作为参数。下面来看看实现:

模拟实现call

Function.prototype.myCall = function(thisArg, ...argumentArr){
if(typeof this !== 'function') {
throw new TypeError(`${this} is not function`)
};
if(thisArg === undefined || thisArg === null){
thisArg = window;
}
  //生成一个对象
var obj = Object.create(thisArg)
obj['fn'] = this;
  // 通过对象执行函数将this指向该对象
var result = obj['fn'](...argumentArr)
delete obj['fn'];
return result
} var obj = {
name:'test1',
get(data1, data2){
console.log(this.name, data1, data2)
}
}
obj.get.myCall({name: 'test2'}, 1, 2, 3) // test2,1,2 // 原理就是通过传入的新的对象来执行这个函数,就是通过对象调用函数的方式

模拟实现apply

Function.prototype.myApply = function(thisArg, argumentArr){
if(typeof this !== 'function') {
throw new TypeError(`${this} is not function`)
};
if(thisArg === undefined || thisArg === null){
thisArg = window;
}
if(argumentArr === undefined || argumentArr === null){
argumentArr = []
}
var obj = Object.create(thisArg)
obj['fn'] = this;
var result = obj['fn'](...argumentArr)
delete obj['fn'];
return result
} var obj = {
name:'test1',
get(data1, data2){
console.log(this.name, data1, data2)
}
}
obj.get.myApply({name: 'test2'}, [1, 2, 3]) // test2,1,2 // 我们发现与call唯一的不同就是入参,call使用rest 参数,将多余的参数整合成argument形式,而apply入参直接是数组

模拟实现bind

Function.prototype.myBind = function(thisArg, ...argumentArr){
if(typeof this !== 'function') {
throw new TypeError(`${this} is not function`)
};
if(thisArg === undefined || thisArg === null){
thisArg = window;
}
var self = this
var bindfn = function(){
return self.call(thisArg, ...argumentArr)
}
bindfn.prototype = self.prototype
return bindfn
} var obj = {
name:'test1',
get(data1, data2){
console.log(this.name, data1, data2)
}
}
const fn = obj.get.myBind({name: 'test2'}, 1, 2, 3)
fn() // test2,1,2 // 相比于前两个bind会有不一样,bind使用到了闭包,
// 我们之前知道函数执行this是指向window,但是这里我们执行却指向了我们的目标对象,实现这样的方式就是闭包的原因

如果我们没有赋值操作执行var self = this,而是直接使用this执行的话

this.call(thisArg, ...argumentArr)

这个时候this是指向window的,这个时候会报this.call is not a function。当我们进行赋值给self ,那么这个时候self 就形成了返回的函数fn的专属背包而不被销毁,每当我们执行fn的时候取到的this都是obj.get方法

手把手教你实现三种绑定方式(call、apply、bind)的更多相关文章

  1. v-bind绑定属性样式——class的三种绑定方式

    1.布尔值的绑定方式 <div id="demo"> <span v-bind:class="{‘class-a‘:isA ,‘class-b‘:isB ...

  2. js this详解,事件的三种绑定方式

    this,当前触发事件的标签 在绑定事件中的三种用法: a. 直接HTML中的标签里绑定 onclick="fun1()"; b. 先获取Dom对象,然后利用dom对象在js里绑定 ...

  3. Dom事件的三种绑定方式

    1.事件 2.  onclick, onblur, onfocus, 需求:请写出一个行为,样式,结构,相分离的页面.   JS,   CSS,  HTML, 示例1,行为结构样式粘到一起的页面: & ...

  4. Binding 中 Elementname,Source,RelativeSource 三种绑定的方式

    在WPF应用的开发过程中Binding是一个非常重要的部分. 在实际开发过程中Binding的不同种写法达到的效果相同但事实是存在很大区别的. 这里将实际中碰到过的问题做下汇总记录和理解. 1. so ...

  5. JavaScript三种绑定事件的方式

    JavaScript三种绑定事件的方式: 1. <div id="btn" onclick="clickone()"></div> // ...

  6. AutoLayout的三种设置方式之——NSLayoutConstraint代码篇

    AutoLayout是从IOS 6开始苹果引入来取代autoresizing的新的布局技术,该技术有三种设置方式,等下我来为大家一一叙述一下. 在说三种设置方式前,我们先简单的说一下autolayou ...

  7. JavaScript 三种绑定事件方式之间的区别

    JavaScript三种绑定事件的方式: 1. <div id="btn" onclick="clickone()"></div> // ...

  8. Asp.Net中的三种分页方式

    Asp.Net中的三种分页方式 通常分页有3种方法,分别是asp.net自带的数据显示空间如GridView等自带的分页,第三方分页控件如aspnetpager,存储过程分页等. 第一种:使用Grid ...

  9. Service组件 总结 + 绑定理Service三种实现方式 Messager + Binder + AIDL

    在Android中进程按优先级可以分为五类,优先级从高到低排列: - 前台进程 该进程包含正在与用户进行交互的界面组件,比如一个Activity - 可视进程 该进程中的组件虽然没有和用户交互,但是仍 ...

随机推荐

  1. 1-web 服务器 框架。

    1.静态网页与动态网页 1.静态网页:无法与服务器进行交互的网页. 2.动态网页:能够与服务器进行交互的网页. 2.web与服务器 1.web:网页(HTML,CSS,JS) 2.服务器:能够给用户提 ...

  2. php 不定参数的传递

    相关函数 func_get_args func_num_args <?php function more_args(){ $args = func_get_args(); for($i=0;$i ...

  3. flex 弹性盒模型的一些例子;

    1.垂直居中 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  4. RF-获取body

    一个很简单的场景:GET方法获取某URL的body信息,直接读取即可,不做处理 *** Test Cases *** GetToken Create HTTP Context host=192.168 ...

  5. 【Vue】Vue学习(一)-Vue指令

    1.v-text v-text主要用来更新文本,等同于JS的text属性 <span v-text="msg"></span> 这两者等价 <span ...

  6. hdu3786 Floyd或搜索 水题

    题意: 找出直系亲属 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  7. hdu4975 行列和构造矩阵(dp判断唯一性)

    题意:       和hdu4888一样,只不过是数据加强了,就是给你行列的和,让你构造一个矩阵,然后判断矩阵是否唯一. 思路:       构造矩阵很简单,跑一次最大流就行了,关键是判断矩阵的唯一性 ...

  8. Linux运维比较常用的一些脚本

    目录 一.根据PID过滤进程所有信息 二.根据进程名过滤进程信息 三.根据用户名查询该用户的相关信息 四.加固系统的一些配置 五:实现磁盘分区的 六.使用一整块硬盘创建逻辑卷 七.将一块硬盘分区,然后 ...

  9. 『动善时』JMeter基础 — 8、JMeter主要元件介绍

    目录 1.测试计划(Test Plan) 2.线程组 3.取样器(sampler) 4.逻辑控制器(Logic Controller) 5.配置元件(Config Element) 6.定时器(Tim ...

  10. 【Bootstrap5】精细学习记录

    [Bootstrap5]精细学习记录 Bootstrap模板 <!DOCTYPE html> <html> <head> <title>Bootstra ...