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); } }