JS-重写内置的call、apply、bind
let obj = {
fn(x, y) {
console.log(this, x, y);
}
}; obj.fn.call({}, 10, 20); // {}, 10, 20
obj.fn.apply(window, [10, 20]); //window, 10, 20 setTimeout(obj.fn.bind(30, 10, 20), 1000); //Number(30), 10, 20
先试着重写一下bind:
从参数看,首先是传递一个this指向并需要做一下处理,后续还有若干个参数
function bind(context) {
//context可能是null或undefined,需要处理一下
if (context == undefined) {
context = window;
}
//借用数组的slice方法结合arguments获取传递的指定this之后的参数集合
var args = [].slice.call(arguments, 1);
}
bind函数中的this是指最终要执行的函数,而且执行bind的时候会返回一个新的匿名函数,并且在这个新的函数中执行最终要执行的函数也就是this,并且改变其this指向:
function bind(context) {
//context可能是null或undefined,需要处理一下
if (context == undefined) {
context = window;
}
//借用数组的slice方法结合arguments获取传递的指定this之后的参数集合
var args = [].slice.call(arguments, 1);
//需要最终执行的函数
var _this = this;
return function anonymous() {
_this.apply(context, args);
};
}
这个bind函数大体算是写完,但还是有些问题,比如给元素进行事件绑定,div.onclick = obj.fn.bind(window, 10, 20),元素进行点击的时候,会有ev事件对象,相当于在执行bind函数返回的那个匿名函数中也需要传递参数,而且参数个数不确定,当然,最后还需要改写一下原型上的方法:
function bind(context) {
//context可能是null或undefined,需要处理一下
if (context == undefined) {
context = window;
}
//借用数组的slice方法结合arguments获取传递的指定this之后的参数集合
var args = [].slice.call(arguments, 1);
//需要最终执行的函数
var _this = this;
return function anonymous() {
var amArg = [].slice.call(arguments, 0);
_this.apply(context, args.concat(amArg));
};
}
Function.prototype.bind = bind;
这样,这个bind函数的重写算是完成了。
我们用es6改写一下:
function bind(context = window, ...args) {
return (...amArg) => this.call(context, ...args.concat(amArg));
}
代码看上去确实精简不少,当然也可以用apply,但经测试,性能不如call。
接下来看看重写call:
它会有若干个参数,第一个是要指向的this,直接用es6写法:
function call(context = window, ...args) { }
函数中的this就是要调用call方法的函数,想让该函数执行并且其内部this指向传递进来的context,那么形如context.函数可以做到:
function call(context = window, ...args) {
//给context增加一个$fn属性,把当前函数赋给这个属性
context.$fn = this;
//让context.$fn这个方法执行,就是之前this函数执行,并且this指向的是context
let result = context.$fn(...args);
//增加完方法应该删除
delete context.$fn;
return result;
}
Function.prototype.call = call;
apply也就出来了:
function apply(context = window, args) {
context.$fn = this;
let result = context.$fn(...args);
delete context.$fn;
return result;
}
Function.prototype.apply = apply;
这里边还是有两个问题,一是$fn属性没有删除,目前还没想到解决办法,一个就是传进来的context必须是引用类型,但其实可以是基础类型:
function call(context = window, ...args) {
context === null ? context = window : null;
let type = typeof context;
if (type !== "object" && type !== "function" && type !== "symbol") {
//=>基本类型值
switch (type) {
case 'number':
context = new Number(context);
break;
case 'string':
context = new String(context);
break;
case 'boolean':
context = new Boolean(context);
break;
}
}
context.$fn = this;
let result = context.$fn(...args);
delete context.$fn;
return result;
}
apply的判断就不写了,但基本都实现了重写,当然,这几个方法毕竟是js的内置写法,我们只是想大致实现它们的实现原理。
JS-重写内置的call、apply、bind的更多相关文章
- js中内置有对象
statpot:使用mongo+bootstrap+highcharts做统计报表 最近做了一个统计项目,这个统计项目大致的需求是统计接口的访问速度.客户端会调用一个接口来记录接口的访问情况,我的需求 ...
- js arguments 内置对象
1.arguments是js的内置对象. 2.在不确定对象是可以用来重载函数. 3.用法如下: function goTo() { var i=arguments.length; alert(i); ...
- 使用原生js自定义内置标签
使用原生js自定义内置标签 效果图 代码 <!DOCTYPE html> <html lang="en"> <head> <meta ch ...
- js单体内置对象
js单体内置对象:js的内置对象,是ECMAScritp提供的.不依赖于宿主环境的对象,我的理解就是在我们开发之前js里面就已经存在的对象.单体内置对象就是是不需要通过new来实例化的,例如我们的st ...
- 前端面试 js 你有多了解call,apply,bind?
函数原型链中的 apply,call 和 bind 方法是 JavaScript 中相当重要的概念,与 this 关键字密切相关,相当一部分人对它们的理解还是比较浅显,所谓js基础扎实,绕不开这些基础 ...
- js常用内置对象、Dom对象、BOM对象
11.html元素事件属性中,如onclick="",双引号里可以是方法条用,可以是js代码(无需加<script>标签) 12.JavaScript内置 对象.属性和 ...
- JS的内置对象以及JQuery中的部分内容
[js中的数组] 1 数组的概念:可以再内存中连续存储的多个有序元素的结构 元素的顺序:称为下标,通过下标查找对应元素. ...
- js常用内置对象及方法
在js中万物皆对象:字符串,数组,数值,函数...... 内置对象都有自己的属性和方法,访问方法如下: 对象名.属性名称: 对象名.方法名称 1.Array数组对象 unshift( ) 数组开 ...
- js的内置对象
转载: https://www.cnblogs.com/liuluteresa/p/6413988.html 在js里,一切皆为或者皆可以被用作对象.可通过new一个对象或者直接以字面量形式创建变 ...
- JS Error 内置异常类型 处理异常 Throw语句
Exceptional Exception Handling in JavaScript MDN资料 Anything that can go wrong, will go wrong. ...
随机推荐
- 异数OS国产CPU平台移植项目需求分析
异数OS国产CPU平台移植项目需求分析 目录 异数OS国产CPU平台移植项目需求分析 项目立项背景 项目需求分析 异数OS性能指标简介 1.TCP协议栈性能测试 2.异数OS-织梦师-水母 消息队列性 ...
- 美食家App开发日记4
研究了卡片式布局中的Recyclerview的用法,但是调试了很长时间,导入包总是有问题,一到手机上运行就会闪退.还是在网上查了很多方法,很不开心我还是解决不了.
- 11、python模块的导入
前言:本文主要介绍python模块的导入,包括模块的定义.模块的作用.导入方式以及模块的搜索路径. 一.模块的定义 python模块(module),简单来说就是一个python文件,以.py结尾,文 ...
- SIR模型预测新冠病毒肺炎发病数据
大家还好吗? 背景就不用多说了吧?本来我是初四上班的,现在延长到2月10日了.这是我工作以来时间最长的一个假期了.可惜哪也去不了.待在家里,没啥事,就用python模拟预测一下新冠病毒肺炎的数据吧.要 ...
- VScode前端插件推荐
工欲善其事,必先利其器,安利一波前端插件. Chinese (Simplified) Language Pack for Visual Studio CodeVScode汉化插件 Beautify代码 ...
- Web自动化测试项目(五)测试结果通知
一.邮件通知 使用第三方邮件发送库yagmail github地址:https://github.com/kootenpv/yagmail 安装 pip3 install yagmail demo.p ...
- CTF--HTTP服务--SQL注入POST参数-注入HTTP报文
开门见山 1. 扫描靶机 2. 对靶机开放端口进行扫描 3. 扫描全部信息 4. 用nikto -host 探测敏感信息 5. 用dirb探测敏感目录 6. 打开一些目录探测出的网页进行查看 7. 再 ...
- Shell case语法结构解析
case ... esac 与其他语言中的 switch ... case 语句类似,是一种多分枝选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 ...
- C++对于C故有问题的改进
C++继承了所有的C特性,并且提供了更丰富的语法和特性(OOP支持.模板支持等),并且拥有和C语言同样出色的运行效率.针对C语言的固有问题,C++做出了如下的升级: 所有变量都可以在需要使用时再定义( ...
- Python多重继承之菱形继承
继承是面向对象编程的一个重要的方式,通过继承,子类就可以扩展父类的功能.在python中一个类能继承自不止一个父类,这叫做python的多重继承(Multiple Inheritance ). 语法 ...