欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Javascript中函数绑定bind()的实例讲解

程序员文章站 2022-06-14 12:13:51
函数绑定 在前面我们已经知道settimeout()很容易就会丢失this,看下面的例子: let user = { firstname: "john&qu...

函数绑定

在前面我们已经知道settimeout()很容易就会丢失this,看下面的例子:

let user = {
  firstname: "john",
  sayhi() {
    alert(`hello, ${this.firstname}!`);
  }
};

settimeout(user.sayhi, 1000); // hello, undefined!

这里this.firstname的值为undefined,因为settimeout()在接收user.sayhi()时与user对象是隔离的,故this就丢失了。它类似于一下的操作:

let f = user.sayhi;
settimeout(f, 1000); // lost user context

因为在中运行,所以丢失了上下文对象user后,this所指向的对象就是全局对象window,故为undefined

解决方案

(1)使用包装器

let user = {
  firstname: "john",
  sayhi() {
    alert(`hello, ${this.firstname}!`);
  }
};

settimeout(function() {
  user.sayhi(); // hello, john!
}, 1000);

settimeout的第一个参数直接使用user.sayhi(),此时settimeout就会根据词法环境接受user对象作为上下文对象,下面是简写的例子:

settimeout(() => user.sayhi(), 1000); // hello, john!

但是有一个问题要注意的是,如果settimeout要调用的执行函数内容在调度前被修改,那么settimeout触发的执行函数为修改过的内容,例如:

let user = {
  firstname: "john",
  sayhi() {
    alert(`hello, ${this.firstname}!`);
  }
};

settimeout(() => user.sayhi(), 1000);

// ...within 1 second
user = { sayhi() { alert("another user in settimeout!"); } };

// another user in settimeout?!?

为了结果这个问题,我们需要用bind()来绑定上下文对象

(2)bind()

javascript的函数都内置了bind()方法来绑定上下文对象,它的语法如下:

// more complex syntax will be little later
let boundfunc = func.bind(context);

bind()默认返回修改过上下文对象(this=context)的新函数(boundfunc)

看下面的例子:

let user = {
  firstname: "john"
};

function func(phrase) {
  alert(phrase + ', ' + this.firstname);
}

// bind this to user
let funcuser = func.bind(user);

funcuser("hello"); // hello, john (argument "hello" is passed, and this=user)

上述例子中,当我们调用funcuser(...)的时候,它会去调用func()并且修改上下文对象this=context

现在我们尝试绑定对象方法,例如:

let user = {
  firstname: "john",
  sayhi() {
    alert(`hello, ${this.firstname}!`);
  }
};

let sayhi = user.sayhi.bind(user); // (*)

sayhi(); // hello, john!

settimeout(sayhi, 1000); // hello, john!

如果一个对象有许多的方法需要绑定上下文对象,我们可以使用bindall()来绑定所有的方法,或者我们可以遍历对象的所有属性方法来绑定this,例如:

for (let key in user) {
  if (typeof user[key] == 'function') {
    user[key] = user[key].bind(user);
  }
}