bind函数源码解析
来源:互联网 发布:淘宝卖家哪个商品好用 编辑:程序博客网 时间:2024/05/22 15:39
bind函数
ES5中原生bind函数是用于绑定this指向的
var obj = { x: 1 } function show(){ console.log(this.x); } var newShow = show.bind(obj); newShow(); // 1
bind方法会创建一个新函数。当这个新函数被调用时,bind的第一个参数将作为它运行时的this,之后的一序列参数将会在传递的实参前传入作为它的参数。
bind返回的绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的this值被忽略,同时调用时的参数被提供给模拟函数
初级实现
我们来实现一个初级的bind函数Polyfill:
Function.prototype.bind = function(context){ //that为调用bind函数的对象 var that = this; //bind函数可能入其他参数,先将参数类数组转化为数组 var argsArray = Array.prototype.slice.call(arguments); return function(){ // slice只传一个参数,返回从参数开始到数组末尾的元素 // slice(1)之后为其他参数 return that.call(context, argsArray.slice(1)) } }
译者注:如果对这个函数有所不理解,我们可以先看一下不改变this的改造
function a(){ console.log(1) }; Function.prototype.bind = function(){ return this; } var b = a.bind(); b(); // 1
进行嗅探增加程序健壮性
其实是一个典型的“Monkey patching(猴子补丁)”,即“给内置对象扩展方法”。所以,如果能进行一下“嗅探”,进行兼容处理,就是锦上添花了。
Function.prototype.bind = Function.prototype.bind || function(context){ //... }
柯里化(curring)实现
我们返回的参数列表里包含:atgsArray.slice(1),他的问题在于存在函数的参数丢失的现象。
Function.prototype.bind = Function.prototype.bind || function (context) { var that = this; //通过bind预先传入的参数 var args = Array.prototype.slice.call(arguments, 1); return function () { //函数调用时传入的参数 var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs); return that.apply(context, finalArgs); } }
但是,我们注意在上边bind方法介绍的第三条提到:bind返回的函数如果作为构造函数,搭配new关键字出现的话,我们的绑定this就需要“被忽略”
构造函数场景下的兼容
直接上代码
Function.prototype.bind = Function.prototype.bind || function (context) { var that = this; var args = Array.prototype.slice.call(arguments, 1); var F = function () {}; F.prototype = this.prototype; var bound = function () { var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs); return that.apply(this instanceof F ? this : context || this, finalArgs); } //把新函数的原型清空 bound.prototype = new F(); return bound; }
更严谨的做法
我们需要调用bind方法的一定要是一个函数,所以可以在函数体内做一个判断:
if (typeof this !== "function") { //使用类型错误 throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); }
一切还没完
es5-shim源码如下所示
bind: function bind(that) { var target = this; if (!isCallable(target)) { throw new TypeError('Function.prototype.bind called on incompatible ' + target); } var args = array_slice.call(arguments, 1); var bound; var binder = function () { if (this instanceof bound) { var result = target.apply( this, array_concat.call(args, array_slice.call(arguments)) ); if ($Object(result) === result) { return result; } return this; } else { return target.apply( that, array_concat.call(args, array_slice.call(arguments)) ); } }; var boundLength = max(0, target.length - args.length); var boundArgs = []; for (var i = 0; i < boundLength; i++) { array_push.call(boundArgs, '$' + i); } bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder); if (target.prototype) { Empty.prototype = target.prototype; bound.prototype = new Empty(); Empty.prototype = null; } return bound; }
0 0
- bind函数源码解析
- bind源码解析(一)
- bind源码解析(二)
- bind源码解析
- bind源码解析(一)
- bind源码解析(二)
- bind()函数 精辟解析
- bind函数解析
- bind源码解析(socket,thread)
- 源码解析: Imread函数
- 源码解析: Imread函数
- sort()函数源码解析
- cvCanny函数源码解析
- bind函数
- bind函数
- bind()函数
- bind函数
- bind函数
- C++中cout位数控制
- C++第三次作业(个人所得税计算器、某月有多少天、计算一个分段函数的值)
- 第2题:Add Two Numbers
- [Selenium With C#基础教程] Lesson-06 单选按钮
- Graphics_Work笔记
- bind函数源码解析
- MySQL数据类型
- 史上最简单的UIScrollView+Autolayout出坑指南
- 从运维角度浅谈MySQL数据库优化
- 蓝桥杯BASIC-2——基础练习 01字串
- 双均线策略
- 二分归并排序之求逆序数
- recycleview
- Nginx+Tomcat搭建高性能负载均衡集群