ES5中bind()函数要点

ES5中bind函数的特性: 权威参考MDN

语法:fun.bind(thisArg[,arg1[,arg2[,...]]])
参数:
thisArg:当绑定函数被调用时,该参数会作为原函数运行时的this指向。当使用new操作符调用时绑定函数时,该参数无效。
arg1,arg2,...:当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
返回值:返回由指定的this值和初始化改造的原函数拷贝


  1. 不同于call和apply只是单纯的设置this的值后传参,它还会将所有bind()方法中的实参(第一个参数之后的参数)与this一起绑定。
    eg1:

    var sum = function(x,y){
        return x+y;
    }
    var succ = sum.bind(null,1) //让this指向null,其后的实参也会作为实参传入被绑定的函数sum
    succ(2); //输出3,可以看到1绑定了sum函数中的x
    

    eg2:

    var copy = function(){
        var args = Array.prototype.slice.call(arguments);
        console.log(args.join());
    }
    copy("hi","friends")   //输出   hi,friends
    var after = copy.bind(null,"hi","welcome");
    after("dear","friend");   //输出 hi,welcome,dear,friends
    
  2. bind()方法所返回的函数的length(形参数量)等于原函数的形参量减去传入bind()方法中的实参数量(除去第一个表示左右域的参数),因为传入到bind中的实参都会绑定到原函数的形参
    eg:

    function func(a,b,c,d,e){...}  //func.length = 5
    var after = func.bind(null,1,2); //这里传入两个实参绑定到了func函数的a,b
    console.log(after.length)  //输出为3
    
    注意:这里bind()方法的第一个参数为null,是因为func()函数内部没有任何与上下文相关的代码,所以不需要传递上下文对象
  3. 当bind()所返回的函数用作构造函数时,传入bind()的this将被忽略,实参会全部传入原函数
    eg:

   var person=function(y){
       this.name="Amy",
       this.printName=function(){console.log(this.name+" "+y)}
   }
   var anotherPerson={
       name:"Bob"
   }
   var Test = person.bind(anotherPerson,"Jack");
   var test = new Test();  //或者var test = new(Test);
   console.log(test.name)  //输出 "Amy"
   console.log(test.printName())  // 输出"Amy Jack"
   ```
   可以看到,Test为一个绑定函数,传入了anotherPerson作为上下文对象,传入了“Jack”作为预设参数,使用new调用Test时,传入的this完全被忽略,但是预设的实参能够被传入  

4. bind()方法返回的是一个带有固定作用域的新函数,以后不管在哪儿调用这个新函数,都不用担心作用域的问题,**即使是之后在使用call函数作用于这个新函数,也不会改变函数执行的上下文对象**  
   eg:
   ```
   var name = "Global";
   var student = {
       name:"John"
   }
   var person = {
       name:"Amy",
       sayName:function(){console.log(this.name)}
   }
   var one={
       name:"Bob"
   }
   var sayName = person.sayName;
   var bindSayName = person.sayName.bind(student);
   console.log(person.sayName())  // "Amy"
   console.log(sayName())       // "Global"
   console.log(bindSayName())  //"John"
   console.log(bindSayName.call(one))  //"John"
   ```
   此时bindSayName这个函数已经绑定到了student这个上下文,接下来用call调用它也不会改变上下文对象

5. 配合setTimeout和setInterval函数使用
一般在函数或类的实例中使用setTimeout和setInterval函数时,this会默认指向window对象,所以这时需要显示的绑定this对象  
   eg:
   ```
   var name = "Global";
   var person = {
       name:"Amy",
       sayName:function(){console.log(this.name)},
       printName:function(){
           setTimeout(this.sayName,1000);
       }
   }
   console.log(person.printName())   //"Global"
   ```
   出现上述问题的原因是setTimeout把person的printName函数放到全局函数作用域中执行去了,所以打印的是全局作用域中的name变量,故而需要手动的在setTimeout函数中绑定this对象,改进如下:
   ```
   var name = "Global";
   var person = {
       name:"Amy",
       sayName:function(){console.log(this.name)},
       printName:function(){
           setTimeout(this.sayName.bind(this),1000);
       }
   }
   console.log(person.printName())  //"Amy"
   ```
6. 兼容性问题:
bind()是在ES5中加入的新特性,所以无法在所用浏览器上运行,例如IE6、7、8都不支持,因此需要手动的实现bind()函数  
   ##### 贴出polyfill官方文档上的实现:
   ```
   if (!Function.prototype.bind) {
     Function.prototype.bind = function (oThis) {
       if (typeof this !== "function") {
         // closest thing possible to the ECMAScript 5
         // internal IsCallable function
         throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
       }
   
       var aArgs = Array.prototype.slice.call(arguments, 1), //(1)
           fToBind = this,  //(3)
           fNOP = function () {},
           fBound = function () {
             return fToBind.apply(this instanceof fNOP? this: oThis ||this,
                   aArgs.concat(Array.prototype.slice.call(arguments))); //(2)
           };
   
       fNOP.prototype = this.prototype;  //(4)
       fBound.prototype = new fNOP(); //(5)
   
       return fBound;
     };
   }
   ```
   理解:
   **以1中的eg2举个例子:**
   ```
   var copy = function(){
       var args = Array.prototype.slice.call(arguments);
       console.log(args.join());
   }
   copy("hi","friends")   //输出   hi,friends
   var after = copy.bind(null,"hi","welcome");
   after("dear","friend");   //输出 hi,welcome,dear,friends
   ```
   (1) `aArgs`是定义bind函数时传入的除第一个参数oThis之外的预设参数,在eg2中为["hi","welcome"]  
   (2) 这里的`arguments`是bind绑定后返回的函数`after`调用时传入的参数,其是类数组对象,调用Array.prototype.slice.call(arguments)后转化为数组,在eg2中为["dear","friends"]   
   (3) 这里的fToBind就是被绑定的原来的函数"copy"  
   (4) 本来`fBound.prototype = fToBind.prototype`就可以让新函数`after`继承原来函数`copy`的所有属性,但这样新函数和原来被绑定的函数指向同一个地方,对新函数的任何修改会影响到原来被绑定的那个函数,不符合要求,所以引入fNOP这个函数作为中转,让bind绑定后返回的函数fBound指向继承了被绑定的函数fToBind的所有属性的一个新的函数fNOP,此时之后对fBound函数做的修改只会影响fNOP这个函数,而与fToBind没有任何关系
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容