手写 实现bind()

本文详细介绍了如何逐步实现JavaScript中的bind()方法,包括无参数版、带参数版以及如何处理原函数作为构造函数的情况。通过理解这些实现,可以深入掌握bind()的工作原理以及在不同场景下的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

逐步实现js的bind方法

  1. 原函数无参数版 bind
  2. 原函数带参数版 bind
  3. 区分原函数是否作为构造函数
一. 原函数无参数版 bind
  1. 原函数作为新_context对象内的属性,在对象中调用,即可使用_context的作用域
  2. 根据 bind 要求返回闭包
  1. ES6之前

    Function.prototype.myBind = function(_context){
    	// _context检测
    	_context = _context? _context: window;
    	let that = this;
    	// 按要求返回闭包(函数)
    	return function(){
    		// 函数挂入_context内
    		_context.__fn = that;
    		// 函数调用
    		let result = _context.__fn();
    		// 删除_context内的新函数
    		delete _context.__fn;
    		return result;
    	}
    }
    
  2. ES6之后

    Function.prototype.myBind = function(_context){
    	// _context检测
    	_context = _context? _context: window;
    	// 按要求返回闭包(函数)
    	return () => {
    		// 函数挂入_context内
    		let fnKey = Symbol();
    		_context[fnKey] = this;
    		// 函数调用
    		let result = _context[fnKey]();
    		// 删除_context内的新函数
    		delete _context[fnKey];
    		return result;
    	}
    }
    
二、原函数带参数版 bind

原函数的参数可能在bind时指定,也可能在调用绑定新作用域后的新函数中指定,也可能都有。

  1. bind 中接收参数,并在闭包中于闭包参数合并为完整参数,再一起提供给新函数。
  2. ES6之前没有解构语法,使用 恶魔方法 eval 进行函数调用
  1. ES6之前

    Function.prototype.myBind = function(_context){
    	// _context检测
    	_context = _context? _context: window;
    	let that = this;
    	// 参数获取
    	let outerArgs = [];
    	let argumentsOut = arguments;	// 与闭包中的arguments区分开
    	for(let i=1, len=arguments.length; i<len; i++){
    		outerArgs.push('argumentsOut[' + i + ']');
    	}
    	// 按要求返回闭包(函数)
    	return function(){
    		// 参数补充
    		let innerArgs = [];
    		for(let i=0, len=arguments.length; i<len; i++){
    			innerArgs.push('arguments[' + i + ']');
    		}
    		let args = outerArgs.concat(innerArgs);
    		// 函数挂入_context内
    		_context.__fn = that;
    		// 函数调用
    		let result = eval('_context.__fn(' + args + ')');
    		// 删除_context内的新函数
    		delete _context.__fn;
    		return result;
    	}
    }
    
  2. ES6之后(箭头函数获取函数参数

    Function.prototype.myBind = function(_context, ..._args){
    	// _context检测
    	_context = _context? _context: window;
    	// 参数获取
    	let outerArgs = _args? _args: [];
    	// 按要求返回闭包(函数)
    	return (..._args) => {
    		// 参数补充
    		let args = _args? outerArgs.concat(_args): outerArgs;
    		// 函数挂入_context内
    		let fnKey = Symbol();
    		_context[fnKey] = this;
    		// 函数调用
    		let result = _context[fnKey](...args);
    		// 删除_context内的新函数
    		delete _context[fnKey];
    		return result;
    	}
    }
    
三、区分原函数是否作为构造函数

当原函数作为构造函数时,bind() 用于绑定作用域的第一个参数将会失效,后续参数将继续作为构造函数的参数继续被使用。

function F(_arg1){
	this.x = _arg1;
	this.fn = function(){
		console.log(this.x)
	}
}
let Func = F.bind({x: 100}, 1);
let fo = new Func();
fo.fn();		// 1
  1. 新增原函数是否作为构造函数的判断
    注:箭头函数不能作为构造函数
  1. ES6之前

    Function.prototype.myBind = function(_context){
    	// _context检测
    	_context = _context? _context: window;
    	let that = this;
    	// 参数获取
    	let outerArgs = [];
    	let argumentsOut = arguments;	// 与闭包中的arguments区分开
    	for(let i=1, len=arguments.length; i<len; i++){
    		outerArgs.push('argumentsOut[' + i + ']');
    	}
    	// 按要求返回闭包(函数)
    	return function F(){
    		// 参数补充
    		let innerArgs = [];
    		for(let i=0, len=arguments.length; i<len; i++){
    			innerArgs.push('arguments[' + i + ']');
    		}
    		let args = outerArgs.concat(innerArgs);
    		
    		if(this instanceof F) {
    			// 构造函数
    			return eval('new that(' + args + ')');
    		}
    		
    		// 函数挂入_context内(这里最好做个键备份)
    		_context.__fn = that;
    		// 函数调用
    		let result = eval('_context.__fn(' + args + ')');
    		// 删除_context内的新函数
    		delete _context.__fn;
    		return result;
    	}
    }
    
  2. ES6之后

    Function.prototype.myBind = function(_context, ..._args){
    	// _context检测
    	_context = _context? _context: window;
    	// 参数获取
    	let outerArgs = _args? _args: [];
    	// 按要求返回闭包(函数)
    	return function F(..._args) {	// 箭头函数不能作为构造函数
    		// 参数补充
    		let args = _args? outerArgs.concat(_args): outerArgs;
    		
    		if(this instanceof F){
    			// 构造函数
    			return new that(...args);
    		}
    		
    		// 函数挂入_context内
    		let fnKey = Symbol();
    		_context[fnKey] = that;
    		// 函数调用
    		let result = _context[fnKey](...args);
    		// 删除_context内的新函数
    		delete _context[fnKey];
    		return result;
    	}
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值