你知道如何自定义call和bind吗?(内附代码)

你知道如何自定义call和bind吗?(内附代码)相信大家对于 call bind 都不陌生 他们都可以动态改变函数执行时 this 指向 先来看看两个方法在 MDN 官网上的语法定义 call function call thisArg arg1 arg2 bind function

大家好,欢迎来到IT知识分享网。

相信大家对于call、bind都不陌生,他们都可以动态改变函数执行时this指向,先来看看两个方法在MDN官网上的语法定义。

call:function.call(thisArg, arg1, arg2, …)bind:

function.bind(thisArg[, arg1[, arg2[, …]]])

call方法接收多个参数,第一个为函数上下文即this,其余为函数本身参数。

bind方法接收多个参数并返回一个新函数,第一个为函数上下文即this,其余参数作为返回函数的参数。

const obj = {foo: ‘bar’};

const fn = function(name) {

console.log(this.foo, name);

};

fn.call(obj, ‘ada’); // bar ada

fn.bind(obj, ‘ada’)(); // bar ada

你知道如何自定义call和bind吗?(内附代码)

图片源于网络,侵删

1. call方法的实现

call的特点:

第一个参数为要绑定的this,剩余参数为函数的实参。

那我们怎样改更改this的绑定呢?

我们知道当我们以对象的方法调用一个普通函数时,this始终指向当前调用的对象。

var value = 1;

function foo(x, y) {

console.log(this.value);

};

var obj = {

value: 2

};

foo.call(obj, 3, 4); // 2

// 相当于

obj.foo(3, 4);

思路:

  • 返回当前函数执行后的结果。
  • 删除该对象上的属性。
  • 通过 对象 . 方法 执行这个函数。
  • 将函数作为要更改this绑定的对象的一个属性。也就是把函数作为call方法中第一个参数中的一个属性。

特点:

  • 当第一个参数(要更改的this绑定的对象)为null或者undefined时,this绑定为window(非严格模式)。如果为严格模式,均为第一个参数的值。
  • 当call方法中第一个参数为除null和undefined外的基本类型(String,Number,Boolean)时,先对该基本类型进行”装箱”操作。

/

* @description: 实现call方法

* @param : context this要绑定的值

* @param : args 除第一个参数外的参数集合

* @return: 函数返回值

*/

Function.prototype.myCall = function(context, …args) {

let handler = Symbol();// 生成一个唯一的值,用来作为要绑定对象的属性key,储存当前调用call方法的函数

if(typeof this !== ‘function’) {

//调用者不是函数

throw this + ‘.myCall is not a function’

};

// 如果第一个参数为引用类型或者null

if(typeof context === ‘object’ || typeof context === ‘function’) {

// 如果为null 则this为window

context = context||window;

} else {

// 如果为undefined 则this绑定为window

if(typeof context === ‘undefined’) {

context = window;

} else {

// 基本类型包装 1 => Number{1}

context = Object(context);

};

};

// this 为当前调用call方法的函数。

context[handler] = this;

// 执行这个函数。这时这个函数内部this绑定为cxt,储存函数执行后的返回值。

let result = context[handler](…args);

// 删除对象上的函数

delete context[handler];

// 返回返回值

return result;

};

2. bind的实现

bind与call区别还是很大的,首先让我们通过以下代码来观察一下bind方法的使用:

var obj = {

name: ‘erdong’

};

function foo(name,age) {

this.age = age;

console.log(this.name + ‘:’+ age + ‘岁’);

};

var bar = foo.bind(obj,’chen’);

bar(18); // erdong:18岁

var b = new bar(27); // undefined:27岁

console.log(b.age); // 27

思路

  • 调用bind方法会创建一个新函数,我们称呼它为绑定函数(boundF)。
  • 当我们直接调用boundF函数时,内部this被绑定为bind方法的第一个参数。
  • 当我们把这个boundF函数当做构造函数通过new关键词调用时,函数内部的this绑定为新创建的对象。(相当于bind提供的this值被忽略)。
  • 调用bind方法时,除第一个参数外的其余参数,将作为boundF的预置参数,在调用boundF函数时默认填充进boundF函数实参列表中。

特点:

  • 当第一个参数(要更改的this绑定的对象)为null或者undefined时,this绑定为window(非严格模式)。
  • 当call方法中第一个参数为除null和undefined外的基本类型(String,Number,Boolean)时,先对该基本类型进行”装箱”操作。
  • 我们根据上述的bind方法的特点,一步一步实现bind方法。

// 第一步 返回一个函数

/

* @description: 实现bind方法

* @param : context this要绑定的值

* @param : args 调用bind方法时,除第一个参数外的参数集合,这些参数会被预置在绑定函数的参数列表中

* @return: 返回一个函数

*/

Function.prototype.myBind = function(context,…args) {

// 这里的this为调用bind方法的函数。

let thisFunc = this;

let boundF = function() {

};

return boundF;

};

第一步:实现了myBind方法返回一个函数。没错就是这就是利用了闭包。

// 第二步

/

* @description: 实现bind方法

* @param : context this要绑定的值

* @param : args 调用bind方法时,除第一个参数外的参数集合,这些参数会被预置在绑定函数的参数列表中

* @return: 返回一个函数

*/

Function.prototype.myBind = function(context, …args) {

// 这里的this为调用bind方法的函数。

let thisFunc = this;

let boundF = function() {

thisFunc.call(context, …args);

};

return boundF;

};

第二步:当调用boundF方法时,原函数内部this绑定为bind方法的第一个参数,这里我们利用了call来实现。

// 第三步

/

* @description: 实现bind方法

* @param : context this要绑定的值

* @param : args 调用bind方法时,除第一个参数外的参数集合,这些参数会被预置在绑定函数的参数列表中

* @return: 返回一个函数

*/

Function.prototype.myBind = function(context,…args) {

// 这里的this为调用bind方法的函数。

let thisFunc = this;

let boundF = function() {

let isUseNew = this instanceof boundF;

thisFunc.call(isUseNew? this:context,…args);

};

return boundF;

};

第三步:先判断boundF是否通过new调用,也就是判断boundF内部的this是否为boundF的一个实例。如果是通过new调用,boundF函数的内部this绑定为当前新创建的对象,因此调用call方法时把当前新创建的对象当作第一个参数传递。

// 第四步

/

* @description: 实现bind方法

* @param : context this要绑定的值

* @param : args 调用bind方法时,除第一个参数外的参数集合,这些参数会被预置在绑定函数的参数列表中

* @return: 返回一个函数

*/

Function.prototype.myBind = function(context, …args) {

// 这里的this为调用bind方法的函数。

let thisFunc = this;

let boundF = function() {

let boundFAgrs = arguments;

let totalAgrs = […args, …arguments];

let isUseNew = this instanceof boundF;

thisFunc.call(isUseNew? this.context, …totalAgrs);

};

return boundF;

};

第四步:通过闭包的特性我们知道,boundF函数可以访问到外部的args变量,将它与boundF函数中的参数合并。然后当作调用原函数的参数。

完整版

到此我们完整版的bind已经显示完毕,下面测试:

Function.prototype.myBind = function(context,…args) {

// 这里的this为调用bind方法的函数。

let thisFunc = this;

let boundF = function() {

let boundFAgrs = arguments;

let totalAgrs = […args,…arguments];

let isUseNew = this instanceof boundF;

thisFunc.call(isUseNew? this.context,…totalAgrs);

};

return boundF;

};

var obj = {

name: ‘erdong’

};

function foo(name,age) {

this.age = age;

console.log(this.name+’:’+age+’岁’);

};

var bar = foo.myBind(obj,’chen’);

bar(18); // erdong:18岁

var b = new bar(27); // undefined:27岁

console.log(b);

console.log(b.age); // 27

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/115911.html

(0)
上一篇 2025-12-01 10:26
下一篇 2025-12-01 10:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信