因为关乎到了this指向的问题,call、apply和bind的用法可以说是老生常谈了。这篇文章的主要作用是利用js原生方法对三个方法进行实现,升入了解其中的原理,对相关知识点有更好的掌握。github地址call、apply和bind的原生实现

call与apply

简单介绍:call和apply方法都是使用一个指定的this值和对应的参数前提下调用某个函数或方法。区别则在于call是通过传多个参数的方式,而apply则是传入一个数组。
举个例子:

var obj = {name: 'linxin'
}function func(age, sex) {console.log(this.name,age,sex);
}func.call(obj,12,'女');         // linxin 12 女
func.apply(obj, [18, '女']);        //linxin 18 女

模拟实现

思路:在JavaScript中的this指向说到了:函数还可以作为某个对象的方法调用,这时this就指这个上级对象。也就是我们平时说的,谁调用,this就指向谁。所以实现的方法就是在传入的对象中添加这么一个方法,然后再去执行这个方法。为了保持对象一直,在执行完之后再把这个对象给删除了。是不是很简单^-^。
初体验

Function.prototype.newCall = function(context) {context.fn = this;  // 通过this获取call的函数context.fn();delete context.fn;
}
let foo = {value: 1
}
function bar() {console.log(this.value);
}
bar.newCall (foo); // 1

这样就完成了基础版本的实现,但是如果说有传参数呢?
所以我们可以进行优化一下,因为传入的参数数量是不确定的,所以我们可以从Arguments对象中去获取,这个比较简单。问题是参数是不确定的,我们如何传入到我们要执行的函数中去呢 ? 这里我们有两种选择:一种是通过eval拼接的方式,另一种就要用到es6了。
体验升级(eval版本):

Function.prototype.newCall = function(context) {context.fn = this;var args = [];for(var i = 1, len = arguments.length; i < len; i++) {args.push('arguments[' + i + ']');}eval('context.fn(' + args +')');delete context.fn;
}
let person = {name: 'Abiel'
}
function sayHi(age,sex) {console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

体验升级(ES6版本):

Function.prototype.newCall = function(context) {context.fn = this;  context.fn(...Array.from(arguments).slice(1));delete context.fn;
}
let person = {name: 'Abiel'
}
function sayHi(age,sex) {console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

让然ES6的方法还可以不用到arguments就能实现
ES6版本再升级:

Function.prototype.newCall = function(context, ...parameter) {context.fn = this;  context.fn(...parameter);delete context.fn;
}
let person = {name: 'Abiel'
}
function sayHi(age,sex) {console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

这样我们基本上实现了call的功能,但是还是存在一些隐患和区别。
当对象本身就有fn这个方法的时候,就有大问题了。
当call传入的对象是null的时候,或者其他一些类型的时候,函数会报错。
终极体验:

Function.prototype.newCall = function(context, ...parameter) {if (typeof context === 'object') {context = context || window} else {context = Object.create(null)}let fn = Symbol()context[fn] = thiscontext[fn](...parameter);delete context[fn]
}
let person = {name: 'Abiel'
}
function sayHi(age,sex) {console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

实现了call之后,apply也是同样的思路。
apply实现:

Function.prototype.newApply = function(context, parameter) {if (typeof context === 'object') {context = context || window} else {context = Object.create(null)}let fn = Symbol()context[fn] = thiscontext[fn](parameter);delete context[fn]
}

bind

bind也是函数的方法,作用也是改变this执行,同时也是能传多个参数。与call和apply不同的是bind方法不会立即执行,而是返回一个改变上下文this指向后的函数,原函数并没有被改变。并且如果函数本身是一个绑定了 this 对象的函数,那 apply 和 call 不会像预期那样执行。
初体验:

Function.prototype.bind = function (context) {var me = thisreturn function () { // bind之后得到的函数return me.call(context)  // 执行是改变this执行}
}

加入参数:

Function.prototype.bind = function (context,...innerArgs) {var me = thisreturn function (...finnalyArgs) {return me.call(context,...innerArgs,...finnalyArgs)}
}
let person = {name: 'Abiel'
}
function sayHi(age,sex) {console.log(this.name, age, sex);
}
let personSayHi = sayHi.bind(person, 25)
personSayHi('男')

call、apply和bind的原生实现相关推荐

  1. call,apply,bind的用法与区别

    1.call/apply/bind方法的来源 首先,在使用call,apply,bind方法时,我们有必要知道这三个方法究竟是来自哪里?为什么可以使用的到这三个方法? call,apply,bind这 ...

  2. 深入理解call、apply、bind(改变函数中的this指向)

    在JavaScript中call.apply.bind是Function 对象自带的三个方法,这三个方法的主要作用是改变函数中的 this 指向,从而可以达到`接花移木`的效果.本文将对这三个方法进行 ...

  3. 微信小程序之apply和call ( 附示例代码和注释讲解) apply call  bind

    微信小程序开发交流qq群   173683895 相同点:作用是一样的,它们能劫持另外一个对象的方法,继承另外一个对象的属性: js中的call(), apply()和bind()是Function. ...

  4. apply call bind 简介

    Function.prototype.call(thisArg [, arg1, arg2, ...]) call() 简述 call() 方法 调用一个函数, 其具有一个指定的 this 值和分别地 ...

  5. JavaScript 中 call、apply和bind的用法区别

    ECMAScript 规范给所有函数都定义了 call 与 apply 两个方法,它们的应用非常广泛,它们的作用也是一模一样,只是传参的形式有区别而已. 其实是一个很简单的东西,认真看十分钟就从一脸懵 ...

  6. JavaScript中的call、apply、bind深入理解

    一.函数的三种角色 首先要先了解在函数本身会有一些自己的属性,比如: length:形参的个数: name:函数名: prototype:类的原型,在原型上定义的方法都是当前这个类的实例的公有方法: ...

  7. 方法apply作用于对象sort时失败_浅析call、apply 与 bind

    点击上方蓝色字体轻松关注 前言 经典模式题:call.apply 与 bind的区别.来吧,今天搞一搞. call(thisArgs [,args...]) 该方法可以传递一个thisArgs参数和一 ...

  8. js之call,apply和bind的模拟实现

    了解call,apply和bind对于看一些源码以及封装一些工具有很大的作用. 如果想要了解并熟练使用它..就必须知道他的基本的实现原理. 一,基本用法 使用 let obj = {a: 18 }fu ...

  9. 理解js中的this指向以及call,apply,bind方法

    <script> function a(){var user = "追梦子";console.log(this.user); //undefinedconsole.lo ...

最新文章

  1. jquery ajax 找到数据怎样放到下拉框里_闲话Excel之简易数据动态图表的制作
  2. docker之docker-machine用法
  3. 若川诚邀你加源码共读群,每周一起学源码
  4. 漫画:什么是分布式锁
  5. Python介绍、发展史、安装、变量、注释、输入
  6. rip和ospf vrrp vlan综合实验
  7. UVA12265-Selling Land(细节处理)
  8. 坦克大战之声音处理类(四)
  9. 质控工具之TrimGalore使用方法
  10. springboot relativepath 不存在_MyBatis初级实战之一:Spring Boot集成
  11. 《区块链技术指南》一
  12. C语言易错知识点总结
  13. CH7511BeDP转LVDS显示屏转接板CS5211电路图
  14. 阿里巴巴 CTO 程立:开源是基础软件的源头!
  15. matlab程序阻尼牛顿法,matlab阻尼牛顿法
  16. Bzoj 2563: 阿狸和桃子的游戏 题解
  17. 前端常见面试题及答案
  18. Web前端:Web前端开发工程师工作内容网页案例设计
  19. rand函数和srand函数的用法和区别
  20. 华为鸿蒙新机2k曲面屏,华为5G新旗舰已确认,双曲面屏+升级到鸿蒙2.0,价格很感人...

热门文章

  1. c语言dll注入器,Module Injector-Module Injector(DLL动态库注入器)下载 v1.0--pc6下载站
  2. java函数ao活动对象_Java程序设计10-11试卷A0105答案
  3. php zip 编码,encoding - 用PHP如何检测一个ZIP包内的文件是在何种编码的系统下创建的...
  4. 我的Java设计模式-建造者模式
  5. linux学习笔记(10)fdisk命令
  6. PHP中数组的三种排序方法
  7. [转]JS日期选择控件
  8. c++中.dll与.lib文件的生成与使用的详解
  9. 程序员基本功01数组与内存控制
  10. python包怎么用_python的包怎么应用