www.qjdy.com-奇迹赌场 > www.qjdy.com官网 > 由此我们可以首先得出 bind 函数的两个特点

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

浏览次数:169 时间:2019-11-22

JavaScript 深远之bind的模拟完成

2017/05/26 · JavaScript · bind

原稿出处: 冴羽   

bind

一句话介绍 bind:

bind() 方法会成立一个新函数。当以此新函数被调用时,bind() 的首先个参数将用作它运转时的 this,之后的风流浪漫体系参数将会在传递的实参前流传作为它的参数。(来自于 MDN )

透过大家能够率先得出 bind 函数的七个特征:

  1. 回来二个函数
  2. 能够流传参数

归来函数的效仿完成

从第二性子状初阶,大家比如:

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

传参的依葫芦画瓢达成

接下去看第二点,能够流传参数。这几个就有一些令人费解了,笔者在 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));
    }
 
}

构造函数效果的依葫芦画瓢达成

做到了这两点,最难的有的到啊!因为 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深远之从原型到原型链》。

构造函数效果的优化完毕

然则在此个写法中,大家一向将 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

四个符合规律

接下去管理些没万分:

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啦。

终极代码

于是最末尾的代码正是:

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

本文由www.qjdy.com-奇迹赌场发布于www.qjdy.com官网,转载请注明出处:由此我们可以首先得出 bind 函数的两个特点

关键词: ag电子游戏 JavaScript

上一篇:举个例子

下一篇:没有了