菜单

有关 bind 你或许得通晓的知识点和使用境况

2018年12月19日 - JavaScript

关于 bind 你恐怕得精通的知识点和利用情形

2016/08/18 · JavaScript
· bind

本文作者: 伯乐在线
韩子迟
。未经作者许可,禁止转载!
欢迎插足伯乐在线 专辑撰稿人

未扣不精通,一看吓一过,已经满一个月份没更新 underscore
源码解读连串著作了。前边大家都完结了 Object ,Array,Collection
上的壮大方法的源码剖析,本文起初来解读 Function 上的扩大方法。

总体的 underscore 源码解读类别作品要走
https://github.com/hanzichi/underscore-analysis,觉得还奢华以之言语,给个
star 鼓励下楼主呗 ^_^

匪看无精晓,一看吓一跳,已经布满一个月份没有革新 underscore
源码解读体系作品了。前面大家曾完成了 Object ,Array,Collection
上之增加方法的源码剖析,本文开端来解读 Function 上之增加方法。

bind 简介

Ok,前日假使讲话的正是 bind。关于 bind,能够预先活动楼主从前写的著作
ECMAScript 5(ES5) 中 bind
方法简介备忘
,有个主导的定义。

bind() 方法会创造一个初函数,当是新函数被调用时,它的 this 值是传递给
bind() 的第一独参数, 它的参数是 bind() 的另参数和该原先的参数。

语法是如此样子的:

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

1
fun.bind(thisArg[, arg1[, arg2[, …]]])

完的 underscore 源码解读体系小说要走
https://github.com/hanzichi/underscore-analysis,觉得还奢华以的语,给个
star 鼓励下楼主呗 \_

参数

bind 的率先只参数会作本函数运行时的 this
指向,不多说;而第二个伊始的参数是可选的,当绑定函数被调用时,这多少个参数加上绑定函数本身的参数会坚守顺序作本函数运行时的参数。怎么了然?

function fn(a, b, c) { return a + b + c; } var _fn = fn.bind(null, 10);
var ans = _fn(20, 30); // 60

1
2
3
4
5
6
function fn(a, b, c) {
  return a + b + c;
}
 
var _fn = fn.bind(null, 10);
var ans = _fn(20, 30); // 60

fn 函数需要多少个参数,_fn 函数将 10
作为默认的率先个参数,所以只有需要传入两单参数即可,倘诺您切莫小心传入了三独参数,放心,也止会取前多少个。

function fn(a, b, c) { return a + b + c; } var _fn = fn.bind(null, 10);
var ans = _fn(20, 30, 40); // 60

1
2
3
4
5
6
function fn(a, b, c) {
  return a + b + c;
}
 
var _fn = fn.bind(null, 10);
var ans = _fn(20, 30, 40); // 60

立马出什么用也?假若某些函数,前几乎独参数就 “内定” 了,咱们虽可用 bind
重回一个新的函数。也就是说,bind()能要一个函数拥有预设的起首参数。这几个参数(即便有言语)作为 bind()的第二单参数和在 this
前边,之后其会于插入到对象函数的参数列表的起初地点,传递给绑定函数的参数会以及当她的末尾。

function list() { return Array.prototype.slice.call(arguments); } var
list1 = list(1, 2, 3); // [1, 2, 3] // Create a function with a preset
leading argument var leadingThirtysevenList = list.bind(undefined, 37);
var list2 = leadingThirtysevenList(); // [37] var list3 =
leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

1
2
3
4
5
6
7
8
9
10
11
function list() {
  return Array.prototype.slice.call(arguments);
}
 
var list1 = list(1, 2, 3); // [1, 2, 3]
 
// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);
 
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

bind 简介

Ok,明日一旦出口的难为 bind。关于 bind,可以优先走楼主往日写的稿子
ECMAScript 5(ES5) 中 bind
方法简介备忘
,有个基本的概念。

bind() 方法会创设一个初函数,当是新函数被调用时,它的 this 值是传递给
bind() 的首先独参数, 它的参数是 bind() 的旁参数和该原的参数。

语法是这样样子的:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

new

运 bind 重返的结果依旧独 function,是个 function 就可以为 new
运算符调用,那么结果吗?规范着说之不可开交领会了,当使用 new
操作符调用绑定函数时,bind 的率先个参数无效。

function Person(name, age) { this.name = name; this.age = age; } var
_Person = Person.bind({}); var p = new _Person(‘hanzichi’, 30); //
Person {name: “hanzichi”, age: 30}

1
2
3
4
5
6
7
function Person(name, age) {
  this.name = name;
  this.age = age;
}
 
var _Person = Person.bind({});
var p = new _Person(‘hanzichi’, 30); // Person {name: "hanzichi", age: 30}

貌似我们不会见去这么用,不过一旦如写单 bind 的
polyfill(http://caniuse.com/#search=bind),仍旧待考虑就此 new
调用的情。

咱啊足以装默认值(参考上一小节),原先提供的那个参数还会叫放置到构造函数调用的前。

function Person(name, age) { this.name = name; this.age = age; } var
_Person = Person.bind(null, ‘hanzichi’); var p = new _Person(30); //
Person {name: “hanzichi”, age: 30}

1
2
3
4
5
6
7
function Person(name, age) {
  this.name = name;
  this.age = age;
}
 
var _Person = Person.bind(null, ‘hanzichi’);
var p = new _Person(30); // Person {name: "hanzichi", age: 30}

参数

bind 的第一独参数会作为本函数运行时的 this
指向,不多说;而第二只初叶之参数是可选的,当绑定函数被调用时,这一个参数加上绑定函数本身的参数会按部就班顺序作本函数运行时之参数。怎么通晓?

function fn(a, b, c) {
  return a + b + c;
}

var _fn = fn.bind(null, 10);
var ans = _fn(20, 30); // 60

fn 函数需要多个参数,_fn 函数将 10
作为默认的第一个参数,所以才待传入两单参数即可,即便你莫小心传入了六只参数,放心,也特相会取前两独。

function fn(a, b, c) {
  return a + b + c;
}

var _fn = fn.bind(null, 10);
var ans = _fn(20, 30, 40); // 60

立即暴发何用吗?假设某些函数,前两只参数就 “内定” 了,我们便足以就此 bind
再次回到一个初的函数。也就是说,bind()能如一个函数拥有预设的起始参数。这多少个参数(假设有些话)作为 bind()的老二个参数与于 this
后边,之后它们会吃插到目标函数的参数列表的启地点,传递让绑定函数的参数会以及当它们的后面。

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

配合 setTimeout

嘿时候容易遗失 this 指向?恩,set提姆eout 是一个情景,很易把 this
指向 window,当然,setInterval 也是同一。当用对象的主意时,需要 this
引用对象,你也许需要显式地将 this 绑定到回调函数以便继续应用对象。

var canvas = { render: function() { this.update(); this.draw(); },
update: function() { // … }, draw: function() { // … } };
window.setInterval(canvas.render, 1000 / 60);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var canvas = {
  render: function() {
    this.update();
    this.draw();
  },
 
  update: function() {
    // …
  },
 
  draw: function() {
    // …
  }
};
 
window.setInterval(canvas.render, 1000 / 60);

于是 canvas
写特效或者开打平常平常碰面遭受类似的题材。下面的代码是来问题的,render
方法被的 this 其实被指向了 window!我们可据此 bind,显式地拿 this
绑定到回调函数以便继续利用该对象。

window.setInterval(canvas.render.bind(canvas), 1000);

1
window.setInterval(canvas.render.bind(canvas), 1000);

好像之情形还有 dom 的轩然大波监听,一不小心可能 this 就给针对了 dom
元素。可以参照下先做 bigrender 时写的即时有的代码
https://github.com/hanzichi/hanzichi.github.io/blob/master/2016/bigrender/js/bigrender.js#L179-L184

new

动 bind 重临的结果依然独 function,是独 function 就好给 new
运算符调用,那么结果吗?规范被说之怪懂了,当用 new
操作符调用绑定函数时,bind 的第一只参数无效。

function Person(name, age) {
  this.name = name;
  this.age = age;
}

var _Person = Person.bind({});
var p = new _Person('hanzichi', 30); // Person {name: "hanzichi", age: 30}

相似大家无会师失掉这样用,可是若如若描绘个 bind 的
polyfill(http://caniuse.com/\#search=bind),如故需要考虑用
new 调用的意况。

我们吧可装默认值(参考上一小节),原先提供的那个参数还会给放置到构造函数调用的先头。

function Person(name, age) {
  this.name = name;
  this.age = age;
}

var _Person = Person.bind(null, 'hanzichi');
var p = new _Person(30); // Person {name: "hanzichi", age: 30}

tip

bind 还是能做片诙谐的作业。

平凡来说,将一个类数组转为数组,我们汇合就此 slice(ie9- 不匡助)。参考
https://github.com/hanzichi/underscore-analysis/issues/14

var slice = Array.prototype.slice; // slice.apply(arguments); //
slice(arguments, 1);

1
2
3
4
var slice = Array.prototype.slice;
 
// slice.apply(arguments);
// slice(arguments, 1);

bind 能于调用变的尤其简便易行。

// same as “slice” in the previous example var unboundSlice =
Array.prototype.slice; var slice =
Function.prototype.call.bind(unboundSlice); // … slice(arguments); //
slice(arguments, 1);

1
2
3
4
5
6
7
8
// same as "slice" in the previous example
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
 
// …
 
slice(arguments);
// slice(arguments, 1);

再推个类似之例证,比如说我们设加上事件及多单节点,for
循环当然没有其他问题,我们尚好 “剽窃” forEach 方法:

Array.prototype.forEach.call(document.querySelectorAll(‘input[type=”button”]’),
function(el){ el.addEventListener(‘click’, fn); });

1
2
3
Array.prototype.forEach.call(document.querySelectorAll(‘input[type="button"]’), function(el){
  el.addEventListener(‘click’, fn);
});

再也进一步,大家得用 bind 将函数封装的重新好:

var unboundForEach = Array.prototype.forEach , forEach =
Function.prototype.call.bind(unboundForEach);
forEach(document.querySelectorAll(‘input[type=”button”]’), function
(el) { el.addEventListener(‘click’, fn); });

1
2
3
4
5
6
var unboundForEach = Array.prototype.forEach
  , forEach = Function.prototype.call.bind(unboundForEach);
 
forEach(document.querySelectorAll(‘input[type="button"]’), function (el) {
  el.addEventListener(‘click’, fn);
});

一致看似之,大家可拿 x.y(z) 变成 y(x,z) 的情势:

var obj = { num: 10, getCount: function() { return this.num; } }; var
unboundBind = Function.prototype.bind , bind =
Function.prototype.call.bind(unboundBind); var getCount =
bind(obj.getCount, obj); console.log(getCount()); // 10

1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
  num: 10,
  getCount: function() {
    return this.num;
  }
};
 
var unboundBind = Function.prototype.bind
  , bind = Function.prototype.call.bind(unboundBind);
 
var getCount = bind(obj.getCount, obj);
console.log(getCount());  // 10

再也推个栗子。每隔一秒在控制台打印 1-5,看起是道考察闭包的经典题目。

for(var i = 1; i <= 5; i++) { !function(i) { setTimeout(function() {
console.log(i); }, i * 1000); }(i); }

1
2
3
4
5
6
7
for(var i = 1; i <= 5; i++) {
  !function(i) {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  }(i);
}

ES6 下能用 let

for(let i = 1; i <= 5; i++) { setTimeout(function() { console.log(i);
}, i * 1000); }

1
2
3
4
5
for(let i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, i * 1000);
}

为得就此 bind,弹指间逼格提高:

for(var i = 1; i <= 5; i++) { setTimeout(console.log.bind(console,
i), i * 1000); }

1
2
3
for(var i = 1; i <= 5; i++) {
  setTimeout(console.log.bind(console, i), i * 1000);
}

配合 setTimeout

哟时便于掉 this 指向?恩,set提姆eout 是一个光景,很容易把 this
指向 window,当然,setInterval 也是同。当用对象的计时,需要 this
引用对象,你或许得显式地拿 this 绑定到回调函数以便继续利用对象。

var canvas = {
  render: function() {
    this.update();
    this.draw();
  },

  update: function() {
    // ...
  },

  draw: function() {
    // ...
  }
};

window.setInterval(canvas.render, 1000 / 60);

因而 canvas
写特效或者开游戏日常日常会面遇上类似之问题。下边的代码是暴发题目标,render
方法吃之 this 其实被指向了 window!我们可用 bind,显式地将 this
绑定到回调函数以便继续利用该目标。

window.setInterval(canvas.render.bind(canvas), 1000);

类之情形还有 dom 的风波监听,一不小心可能 this 就深受针对了 dom
元素。可以参见下先做 bigrender 时写的霎时一部分代码
https://github.com/hanzichi/hanzichi.github.io/blob/master/2016/bigrender/js/bigrender.js\#L179-L184

Read more

有关 bind 的牵线就交此地,下一致首小说以做 underscore 来谈说怎么样促成一个
bind 的 polyfill。

打赏帮忙我形容有重新多好章,谢谢!


打赏作者

tip

bind 仍能举办一些诙谐的作业。

一般性来说,将一个类数组转为数组,我们会就此 slice(ie9- 不帮助)。参考
https://github.com/hanzichi/underscore-analysis/issues/14

var slice = Array.prototype.slice;

// slice.apply(arguments);
// slice(arguments, 1);

bind 能给调用变的愈来愈简便易行。

// same as "slice" in the previous example
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);

// ...

slice(arguments);
// slice(arguments, 1);

还推个近乎之例证,比如说我们只要添加事件到差不多独节点,for
循环当然没有其余问题,大家尚可以 “剽窃” forEach 方法:

Array.prototype.forEach.call(document.querySelectorAll('input[type="button"]'), function(el){
  el.addEventListener('click', fn);
});

重复进一步,我们好为此 bind 将函数封装的又好:

var unboundForEach = Array.prototype.forEach
  , forEach = Function.prototype.call.bind(unboundForEach);

forEach(document.querySelectorAll('input[type="button"]'), function (el) {
  el.addEventListener('click', fn);
});

平等看似之,我们得以用 x.y(z) 变成 y(x,z) 的花样:

var obj = {
  num: 10,
  getCount: function() {
    return this.num;
  }
};

var unboundBind = Function.prototype.bind
  , bind = Function.prototype.call.bind(unboundBind);

var getCount = bind(obj.getCount, obj);
console.log(getCount());  // 10

还推个栗子。每隔一秒在控制台打印 1-5,看起是道考察闭包的经题目。

for(var i = 1; i <= 5; i++) {
  !function(i) {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  }(i);
}

ES6 下能用 let

for(let i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, i * 1000);
}

为足以用 bind,刹那间逼格提升:

for(var i = 1; i <= 5; i++) {
  setTimeout(console.log.bind(console, i), i * 1000);
}

打赏襄助我形容有重新多好章,谢谢!

图片 1

1 赞 7 收藏
评论

Read more

有关 bind 的牵线就交此,下一致首作品以做 underscore 来谈说怎么样兑现一个
bind 的 polyfill。

关于作者:韩子迟

图片 2

a JavaScript beginner
个人主页
·
我之稿子
·
9
·
   

图片 3

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图