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. ...
随机推荐
- SqlServer分页存储过程(多表查询,多条件排序),Repeater控件呈现数据以及分页
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中,经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出 ...
- Qt Installer Framework翻译(5-2)
创建在线安装程序 联机安装程序获取二进制安装文件中的内容以及存储库描述(Updates.xml).请创建一个存储库,并将其上传到Web服务器.然后在用于创建安装程序的config.xml文件中指定存储 ...
- (分块)Holes CodeForces - 13E
题意 n(n≤105)个洞排成一条直线,第ii个洞有力量值ai,当一个球掉进洞ii时就会被立刻弹到i+ai,直到超出n.进行m(m≤105)次操作: ·修改第i个洞的力量值ai. ·在洞xx上放一个球 ...
- 修改 Apache 的默认端口
修改 Apache 的默认端口修改 Apache 端口的方法是最妥协的方法了,后果是当你开启 Apache 服务器的时候,访问的本机地址将会附带端口号,比如 http://localhost:8888 ...
- 【中文乱码】深入分析 Java Web 中的中文编码问题
深入分析 Java Web 中的中文编码问题 1.几种常见的编码格式 1.1 为什么要编码 在计算机中存储信息的最小单元是 1 个字节,即 8 个 bit, 所以能表示的字符范围是 0 ~ 255 个 ...
- ugui制作伸缩菜单
制作一个类似与这种格式的菜单,可以伸缩滑动的.今天正好项目需要用到类似功能,所以尝试了一下,做出如下的效果 虽然只是一个思路,但是可以扩展.声明一个object物体,为but,通过GetCompone ...
- Python学习,第三课 - 数据类型
前言. 本次针对Python中的数据类型,做详细的总结 1.数字 2 是一个整数的例子. 长整数 不过是大一些的整数. 3.23和52.3E-4是浮点数的例子.E标记表示10的幂.在这里,52.3E- ...
- zbar+opencv检测图片中的二维码或条形码
zbar本身自带检测二维码条形码功能,这里使用opencv只是做一些简单的读取图片,灰度图片以及显示条形码和二维码时用到一些绘制 // barcode-qrcodescanner.cpp: 定义控制台 ...
- MySQL5.6绿色版安装
1.下载 MySQL绿色版安装需下载好三个文件 (1).MySQL5.6版本离线安装包 (2).Microsoft Visual C++ (3).Microsoft .NET Framework 1. ...
- Redhat6.7 切换Centos yum源
转自:http://inlhx.iteye.com/blog/2336729 RedHat 更换Yum源 1.检查yum包 rpm -qa |grep yum 2.删除自带包 rpm -aq | gr ...