bind、call、apply 区别?如何实现一个bind?

巴拉米 等级 390 0 0

一、作用

callapplybind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向

那么什么情况下需要改变this的指向呢?下面举个例子

var name="lucy";  
const obj={  
    name:"martin",  
    say:function () {  
        console.log(this.name);  
    }  
};  
obj.say(); //martin,this指向obj对象  
setTimeout(obj.say,0); //lucy,this指向window对象  

从上面可以看到,正常情况say方法输出martin

但是我们把say放在setTimeout方法中,在定时器中是作为回调函数来执行的,因此回到主栈执行时是在全局执行上下文的环境中执行的,这时候this指向window,所以输出luck

我们实际需要的是this指向obj对象,这时候就需要该改变this指向了

setTimeout(obj.say.bind(obj),0); //martin,this指向obj对象  

二、区别

下面再来看看applycallbind的使用

apply

apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入

改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

function fn(...args){  
    console.log(this,args);  
}  
let obj = {  
    myname:"张三"  
}  

fn.apply(obj,[1,2]); // this会变成传入的obj,传入的参数必须是一个数组;  
fn(1,2) // this指向window  

当第一个参数为nullundefined的时候,默认指向window(在浏览器中)

fn.apply(null,[1,2]); // this指向window  
fn.apply(undefined,[1,2]); // this指向window  

call

call方法的第一个参数也是this的指向,后面传入的是一个参数列表

apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

function fn(...args){  
    console.log(this,args);  
}  
let obj = {  
    myname:"张三"  
}  

fn.call(obj,1,2); // this会变成传入的obj,传入的参数必须是一个数组;  
fn(1,2) // this指向window  

同样的,当第一个参数为nullundefined的时候,默认指向window(在浏览器中)

fn.call(null,[1,2]); // this指向window  
fn.call(undefined,[1,2]); // this指向window  

bind

bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)

改变this指向后不会立即执行,而是返回一个永久改变this指向的函数

function fn(...args){  
    console.log(this,args);  
}  
let obj = {  
    myname:"张三"  
}  

const bindFn = fn.bind(obj); // this 也会变成传入的obj ,bind不是立即执行需要执行一次  
bindFn(1,2) // this指向obj  
fn(1,2) // this指向window  

小结

从上面可以看到,applycallbind三者的区别在于:

  • 三者都可以改变函数的this对象指向

  • 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefinednull,则默认指向全局window

  • 三者都可以传参,但是apply是数组,而call是参数列表,且applycall是一次性传入参数,而bind可以分为多次传入

  • bind是返回绑定this之后的函数,applycall 则是立即执行

三、实现

实现bind的步骤,我们可以分解成为三部分:

  • 修改this指向

  • 动态传递参数

// 方式一:只在bind中传递函数参数  
fn.bind(obj,1,2)()  

// 方式二:在bind中传递函数参数,也在返回函数中传递参数  
fn.bind(obj,1)(2)  
  • 兼容new关键字

整体实现代码如下:

Function.prototype.myBind = function (context) {  
    // 判断调用对象是否为函数  
    if (typeof this !== "function") {  
        throw new TypeError("Error");  
    }  

    // 获取参数  
    const args = [...arguments].slice(1),  
          fn = this;  

    return function Fn() {  

        // 根据调用方式,传入不同绑定值  
        return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments));   
    }  
}  
收藏
评论区

相关推荐

Netty之旅三:Netty服务端启动源码分析,一梭子带走!
Netty服务端启动流程源码分析 前记 哈喽,自从上篇《Netty之旅二:口口相传的高性能Netty到底是什么?》后,迟迟两周才开启
Go Mmap 文件内存映射简明教程
1 mmap 简介 In computing, mmap is a POSIXcompliant Unix system call t
What the f*ck JavaScript?
What the fck JavaScript? 一个有趣和棘手的 JavaScript 示例列表。 JavaScript 是一种很好的语言。
call、apply、bind三者为改变this指向的方法。
共同点: 第一个参数都为改变this的指针。若第一参数为null/undefined,this默认指向window 差异点如下: 1.call(无数个参数) 第一个参数:改变this指向 第二个参数:实参 使用之后会自动执行该函数 function fn(a,b,c){ console.log(this,abc); // this指
bind、call、apply 区别?如何实现一个bind?
一、作用 call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向 那么什么情况下需要改变this的指向呢?下面举个例子 var name"lucy"; const obj{     name:"martin",     say:function () {         co
vue 自定义指令-----文字提示气泡
实现一个简单的 鼠标滑过出现文字提示。啥也不说 上代码 包括了 指令类容更新 import Vue from 'vue' Vue.directive('mouse', { // 初始化 bind: function(el, binding, vnode) { }, // 被插入 inserted:function(el,
干掉nginx 403 forbidden报错
目录问题解决1. 设置启动用户owner2. 切换管理员模式3. 开放访问目录权限4. 明确index索引文件 问题按照网上的教程,我们顺利启动了默认80端口的nginx服务。具体安装教程可以参考:https://liuzhen.blog.csdn.net/article/details/83898155接下来,我们开始将它修改成自己的静态服务,但是遇到
JS 手撕-经典面试题
引言首先出这篇文章,一方面是为了记录巩固我所学的知识,明白面试的高频考点。不鼓励大家背题的,初衷是希望总结的一些面试题能帮助你查漏补缺,温故知新。这些题并不是全部,如果你还想看得更多,可以访问,目前已经有552道大厂真题了,涵盖各类前端的真题,欢迎加入我们一起来讨论~函数 call 语法:fn.call(obj,...args) 功
新手学习 React 迷惑的点
网上各种言论说 React 上手比 Vue 难,可能难就难不能深刻理解 JSX,或者对 ES6 的一些特性理解得不够深刻,导致觉得有些点难以理解,然后说 React 比较难上手,还反人类啥的,所以我打算写两篇文章来讲新手学习 React 的时候容易迷惑的点写出来,如果你还以其他的对于学习 React 很迷惑的点,可以在留言区里给我留言。为什么要引入 Reac
Binder Driver缺陷导致定屏的案例
本文讲解异步binder call是如何阻塞整个系统的,通过ramdump信息以及binder通信协议来演绎并还原定屏现场。 一、背景知识点解决此问题所涉及到的基础知识点有:Trace、CPU调度、Ramdump推导、Crash工具、GDB工具、Ftrace, 尤其深入理解binder IPC机制。 1.1 工具简介 Trace:分析死锁
Vue.js——60分钟快速入门
是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的。相比于Angular.js,Vue.js提供了更加简洁、更易于理解的API,使得我们能够快速地上手并使用Vue.js。
日常必备的JS工具函数大全
为元素添加on方法 Element.prototype.on Element.prototype.addEventListener; NodeList.prototype.on function (event, fn) 、 []['forEach'].call(this, function (el) el.on(ev
JavaScript 和 Node.js 中事件循环
1.JavaScript中事件循环可以参考《JavaScript忍者秘籍第二版》第十三章,讲解的很好。JavaScript中事件循环,主要就在理解宏任务和微任务这两种异步任务。宏任务(macrotask): setTimeOut 、 setInterval 、 setImmediate 、 I/O 、 各种callback、 UI渲染 、messageCh
搬迁声明
我的博客即将同步至 OSCHINA 社区,这是我的 OSCHINA ID:helloworld开发者社区,邀请大家一同入驻:https://www.oschina.net/sharingplan/apply
React事件绑定的几种方式
一、React事件是什么在react应用中,事件名都是用小驼峰格式进行书写,例如onclick要改写成onClick最简单的事件绑定如下:class ShowAlert extends React.Component   showAlert()      console.log("Hello World");      render()