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. ...
随机推荐
- influxdb基础那些事儿
InfluxDB是一个开源的时序数据库,使用GO语言开发,特别适合用于处理和分析资源监控数据这种时序相关数据.而InfluxDB自带的各种特殊函数如求标准差,随机取样数据,统计数据变化比等,使数据统计 ...
- Data for the People: How to Make Our Post-Privacy Economy Work for You
等翻译成 chinese在看吧
- SpringBoot配置嵌入式Servlet容器
1).如何定制和修改Servlet容器的相关配置: 1.修改和server有关的配置(ServerProperties[也是EmbeddedServletContainerCustomizer]): ...
- 第一章001-003课程介绍、计算机网络概述、Internet概述
计算机网络概述 课程安排: 第一章:概述 第二章:物理层 第三章:数据链路层 第四章:网络层 第五章:运输层 第六章:应用层 第七章:网络安全 第八章:因特网上的音频/视频服务 第九章:无线网络 第十 ...
- 02--java--环境搭建
第一步,下载JDK 去ORACLE官网http://www.oracle.com下载 有安装版和绿色版,安装版一路下一步,绿色版解压缩压缩包就行了 安装版直接自动配置环境变量,绿色版需要自己配置环境变 ...
- 【WPF学习】第二十五章 日期控件
WPF包含两个日期控件:Calender和DatePicker.这两个控件都被设计为允许用户选择日期. Calendar控件显示日期,在与Windows操作系统中看到的日历(例如,当配置系统日期时看到 ...
- 分享一下我在mysql5.6+mysql8数据库安装过程中的一些坑!
Mysql5.6安装 下载好安装包后,在bin目录下用cmd打开,输入mysqld install [服务名]新建个服务 在windows+r输入services.msc即可查看服务 怎样使用mysq ...
- ios---cocoapods 安装与使用 (AFNetworking为例)
cocoapods 安装与使用 一.CocoaPods是什么? CocoaPods是一个用Ruby写的.负责管理iOS项目中第三方开源库的工具,CocoaPods能让我们集中的.统一管理第三方开源库, ...
- Python变量、方法、类的命名规则
1. 变量命名总结: - 1.单下划线开头变量:protected - 2.双下划线开头变量:private - 3.双下划线开头,双下划线结尾:系统内置变量 2. 函数命名总结: - 1.私有方法: ...
- jenkins 与 gitlab 的持续集成
前言介绍 gitlab与jenkins的安装部署请参考之前的文章:这里介绍一下jenkins与gitlab结合的好处. gitlab可以自己实现CICD功能,jenkins也可以结合其他工具来实现CI ...