由此我们可以首先得出 bind 函数的两个特点

JavaScript 深切之bind的模拟完结

2017/05/26 · JavaScript
· bind

初藳出处: 冴羽   

重回函数的萧规曹随达成

从第三个特性此前,我们比如:

var foo = { value: 1 }; function bar() { console.log(this.value); } //
再次回到了一个函数 var bindFoo = bar.bind(foo); bindFoo(); // 1

1
2
3
4
5
6
7
8
9
10
11
12
var foo = {
    value: 1
};
 
function bar() {
    console.log(this.value);
}
 
// 返回了一个函数
var bindFoo = bar.bind(foo);
 
bindFoo(); // 1

有关内定 this 的指向,大家得以接纳 call 也许 apply 完毕,关于 call 和
apply
的模仿完成,能够查看《JavaScript深切之call和apply的模仿完毕》。大家来写第一版的代码:

// 第一版 Function.prototype.bind2 = function (context) { var self =
this; return function () { self.apply(context); } }

1
2
3
4
5
6
7
8
// 第一版
Function.prototype.bind2 = function (context) {
    var self = this;
    return function () {
        self.apply(context);
    }
 
}

多个小标题

接下去管理些不成难点:

1.apply 这段代码跟 MDN 上的稍有两样

在 MDN 中文版讲 bind 的模仿达成时,apply 这里的代码是:

self.apply(this instanceof self ? this : context || this,
args.concat(bindArgs))

1
self.apply(this instanceof self ? this : context || this, args.concat(bindArgs))

多了一个有关 context 是或不是存在的论断,但是这几个是指鹿为马的!

举个例证:

var value = 2; var foo = { value: 1, bar: bar.bind(null) }; function
bar() { console.log(this.value); } foo.bar() // 2

1
2
3
4
5
6
7
8
9
10
11
var value = 2;
var foo = {
    value: 1,
    bar: bar.bind(null)
};
 
function bar() {
    console.log(this.value);
}
 
foo.bar() // 2

如上代码常常意况下会打字与印刷 2,假诺换来了 context || this,这段代码就能够打印1!

据此这里不应该张开 context 的剖断,大家查看 MDN
同样内容的罗马尼亚语版,就空头支票这里个论断!

2.调用 bind 的不是函数如何是好?

丰硕,大家要报错!

if (typeof this !== “function”) { throw new
Error(“Function.prototype.bind – what is trying to be bound is not
callable”); }

1
2
3
if (typeof this !== "function") {
  throw new Error("Function.prototype.bind – what is trying to be bound is not callable");
}

3.自个儿要在线上用

那别忘了做个杰出:

Function.prototype.bind = Function.prototype.bind || function () { …… };

1
2
3
Function.prototype.bind = Function.prototype.bind || function () {
    ……
};

当然最佳是用es5-shim啦。

构造函数效果的优化完结

不过在那些写法中,大家直接将 fbound.prototype =
this.prototype,我们一向更换 fbound.prototype 的时候,也会平昔改变函数的
prototype。这一年,大家能够经过二个空函数来进展转载:

// 第四版 Function.prototype.bind2 = function (context) { var self =
this; var args = Array.prototype.slice.call(arguments, 1); var fNOP =
function () {}; var fbound = function () { var bindArgs =
Array.prototype.slice.call(arguments); self.apply(this instanceof self ?
this : context, args.concat(bindArgs)); } fNOP.prototype =
this.prototype; fbound.prototype = new fNOP(); return fbound; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 第四版
Function.prototype.bind2 = function (context) {
 
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
 
    var fNOP = function () {};
 
    var fbound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        self.apply(this instanceof self ? this : context, args.concat(bindArgs));
    }
    fNOP.prototype = this.prototype;
    fbound.prototype = new fNOP();
    return fbound;
 
}

到此截止,大的主题材料都曾经缓和,给协调贰个赞!o( ̄▽ ̄)d

传参的模仿完结

接下去看第二点,能够流传参数。那一个就有一点点令人费解了,小编在 bind
的时候,是不是能够传参呢?作者在实践 bind
再次回到的函数的时候,行不行传参呢?让大家看个例子:

var foo = { value: 1 }; function bar(name, age) {
console.log(this.value); console.log(name); console.log(age); } var
bindFoo = bar.bind(foo, ‘daisy’); bindFoo(’18’); // 1 // daisy // 18

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var foo = {
    value: 1
};
 
function bar(name, age) {
    console.log(this.value);
    console.log(name);
    console.log(age);
 
}
 
var bindFoo = bar.bind(foo, ‘daisy’);
bindFoo(’18’);
// 1
// daisy
// 18

函数要求传 name 和 age 五个参数,竟然还足以在 bind 的时候,只传一个name,在实践回来的函数的时候,再传另二个参数 age!

那可咋做?不急,大家用 arguments 实行管理:

// 第二版 Function.prototype.bind2 = function (context) { var self =
this; // 获取bind2函数从第二个参数到终极贰个参数 var args =
Array.prototype.slice.call(arguments, 1); return function () { //
这年的arguments是指bind重回的函数字传送入的参数 var bindArgs =
Array.prototype.slice.call(arguments); self.apply(context,
args.concat(bindArgs)); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 第二版
Function.prototype.bind2 = function (context) {
 
    var self = this;
    // 获取bind2函数从第二个参数到最后一个参数
    var args = Array.prototype.slice.call(arguments, 1);
 
    return function () {
        // 这个时候的arguments是指bind返回的函数传入的参数
        var bindArgs = Array.prototype.slice.call(arguments);
        self.apply(context, args.concat(bindArgs));
    }
 
}

终极代码

进而最末尾的代码就是:

Function.prototype.bind2 = function (context) { if (typeof this !==
“function”) { throw new Error(“Function.prototype.bind – what is trying
to be bound is not callable”); } var self = this; var args =
Array.prototype.slice.call(arguments, 1); var fNOP = function () {}; var
fbound = function () { self.apply(this instanceof self ? this : context,
args.concat(Array.prototype.slice.call(arguments))); } fNOP.prototype =
this.prototype; fbound.prototype = new fNOP(); return fbound; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Function.prototype.bind2 = function (context) {
 
    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind – what is trying to be bound is not callable");
    }
 
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
    var fNOP = function () {};
 
    var fbound = function () {
        self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
    }
 
    fNOP.prototype = this.prototype;
    fbound.prototype = new fNOP();
 
    return fbound;
 
}

浓重类别

JavaScript深切类别目录地址:。

JavaScript深切连串揣摸写十五篇左右,目的在于帮大家捋顺JavaScript底层知识,珍视传授如原型、功效域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、承继等困难概念。

假定有不当恐怕不小心翼翼的地点,请必需给与指正,不菲谢。纵然喜欢或许具备启示,款待star,对小编也是一种鞭笞。

本系列:

  1. JavaScirpt 深切之从原型到原型链
  2. JavaScript
    深切之词法效能域和动态成效域
  3. JavaScript 浓郁之实行上下文栈
  4. JavaScript 深入之变量对象
  5. JavaScript 深刻之功能域链
  6. JavaScript 深远之从 ECMAScript 标准解读
    this
  7. JavaScript 深切之试行上下文
  8. JavaScript 浓厚之闭包
  9. JavaScript 深远之参数按值传递
  10. JavaScript
    深切之call和apply的上行下效完成

    1 赞 收藏
    评论

图片 1

构造函数效果的效仿完毕

做到了这两点,最难的部分到啊!因为 bind 还大概有叁个特点,正是

七个绑定函数也能接纳new操作符制造对象:这种表现就好像把原函数当成构造器。提供的
this 值被忽略,同临时候调用时的参数被提须求模拟函数。

也正是说当 bind 重临的函数作为构造函数的时候,bind 时钦赐的 this
值会失效,但传播的参数还是奏效。举例:

var value = 2; var foo = { value: 1 }; function bar(name, age) {
this.habit = ‘shopping’; console.log(this.value); console.log(name);
console.log(age); } bar.prototype.friend = ‘kevin’; var bindFoo =
bar.bind(foo, ‘daisy’); var obj = new bindFoo(’18’); // undefined //
daisy // 18 console.log(obj.habit); console.log(obj.friend); // shopping
// kevin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var value = 2;
 
var foo = {
    value: 1
};
 
function bar(name, age) {
    this.habit = ‘shopping’;
    console.log(this.value);
    console.log(name);
    console.log(age);
}
 
bar.prototype.friend = ‘kevin’;
 
var bindFoo = bar.bind(foo, ‘daisy’);
 
var obj = new bindFoo(’18’);
// undefined
// daisy
// 18
console.log(obj.habit);
console.log(obj.friend);
// shopping
// kevin

在意:就算在大局和 foo 中都声称了 value 值,最终如故再次来到了
undefind,表达绑定的 this 失效了,尽管我们探听 new
的模仿达成,就能够精通那年的 this 已经针对了 obj。

(哈哈,作者那是为自家的下一篇小说《JavaScript深远类别之new的模仿达成》打广告)。

之所以我们得以因此改变再次来到的函数的原型来促成,让大家写一下:

// 第三版 Function.prototype.bind2 = function (context) { var self =
this; var args = Array.prototype.slice.call(arguments, 1); var fbound =
function () { var bindArgs = Array.prototype.slice.call(arguments); //
充作为构造函数时,this 指向实例,self 指向绑定函数,因为上边一句
`fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为
绑定函数的 prototype,此时结果为 true,当结果为 true 的时候,this
指向实例。 // 当做为平常函数时,this 指向 window,self
指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的
context。 self.apply(this instanceof self ? this : context,
args.concat(bindArgs)); } // 修改重返函数的 prototype 为绑定函数的
prototype,实例就能够接二连三函数的原型中的值 fbound.prototype =
this.prototype; return fbound; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 第三版
Function.prototype.bind2 = function (context) {
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
 
    var fbound = function () {
 
        var bindArgs = Array.prototype.slice.call(arguments);
        // 当作为构造函数时,this 指向实例,self 指向绑定函数,因为下面一句 `fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为 绑定函数的 prototype,此时结果为 true,当结果为 true 的时候,this 指向实例。
        // 当作为普通函数时,this 指向 window,self 指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的 context。
        self.apply(this instanceof self ? this : context, args.concat(bindArgs));
    }
    // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承函数的原型中的值
    fbound.prototype = this.prototype;
    return fbound;
}

一旦对原型链稍有疑惑,能够查看《JavaScript深切之从原型到原型链》。

bind

一句话介绍 bind:

bind() 方法会创设三个新函数。当那个新函数被调用时,bind()
的首先个参数将用作它运营时的
this,之后的一体系参数将会在传递的实参前传出作为它的参数。(来自于 MDN
)

透过我们得以率先得出 bind 函数的两性格情:

  1. 回到八个函数
  2. 能够流传参数

相关文章