<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                在`JavaScript`中,如果想要改變當前函數調用的上下文對象的時候,我們都會聯想到`call、apply和bind`。 ~~~ var name = 'window name'; var obj = { name: 'call_me_R' }; function sayName(){ console.log(this.name); } sayName(); // window name sayName.call(obj); // call_me_R ~~~ ``` 有兩種方法可以講arguments轉換成數組,其實原理是一樣的。 Array.prototype.slice.call(arguments) [].slice.call(arguments) Array.from()`是個非常推薦的方法,其可以將所有類數組對象轉換成數組。 ``` ## 三者的共同之處: 1. 都是用來改變函數的this對象的指向 2. 第一個參數都是this要指向的對象 3. 都可以利用后續參數進行傳參 ## 說下區別: 1. 第二個參數開始不同,apply是傳入帶下標的集合,數組或者類數組,apply把它傳給函數作為參數,call從第二個開始傳入的參數是不固定的,都會傳給函數作為參數。 2. call比apply的性能要好,平常可以多用call, call傳入參數的格式正是內部所需要的格式, 3. 尤其是es6 引入了 Spread operator (延展操作符) 后,即使參數是數組,可以使用 call ~~~js let params = [1,2,3,4] xx.call(obj, ...params) ~~~ 4. `call`方法傳參是傳一個或者是多個參數,第一個參數是指定的對象,如開篇的`obj`。 ~~~js func.call(thisArg, arg1, arg2, ...) ~~~ 5. `apply`方法傳參是傳一個或兩個參數,第一個參數是指定的對象,第二個參數是一個數組或者類數組對象。 ~~~js func.apply(thisArg, [argsArray]) ~~~ 6. `bind`方法傳參是傳一個或者多個參數,跟`call`方法傳遞參數一樣。 ~~~js func.bind(this.thisArg, arg1, arg2, ...) ~~~ 簡言之,`call`和`bind`傳參一樣;`apply`如果要傳第二個參數的話,應該傳遞一個類數組。 ## 調用后是否立執行 **call和apply**在函數調用它們之后,會立即執行這個函數;而函數調用**bind**之后,會返回調用函數的引用,如果要執行的話,需要執行返回的函數引用。 變動下開篇的`demo`代碼,會比較容易理解: ~~~js var name = 'window name'; var obj = { name: 'call_me_R' }; function sayName(){ console.log(this.name); } sayName(); // window name sayName.call(obj); // call_me_R sayName.apply(obj); // call_me_R console.log('---divided line---'); var _sayName = sayName.bind(obj); _sayName(); // call_me_R ~~~ `call, apply 和 bind`的區分點主要是上面的這兩點 ## 手寫call, apply, bind方法 #### call方法實現 在上面的了解中,我們很清楚了`call`的傳參格式和調用執行方式,那么就有了下面的實現方法: ~~~js Function.prototype.call2 = function(context, ...args){ context = context || window; // 因為傳遞過來的context有可能是null context.fn = this; // 讓fn的上下文為context const result = context.fn(...args); delete context.fn; return result; // 因為有可能this函數會有返回值return } ~~~ 我們來測試下: ~~~js var name = 'window name'; var obj = { name: 'call_me_R' }; // Function.prototype.call2 is here ... function sayName(a){ console.log(a + this.name); return this; } sayName(''); // window name var _this = sayName.call2(obj, 'hello '); // hello call_me_R console.log(_this); // {name: "call_me_R"} ~~~ #### apply方法實現 `apply`方法和`call`方法差不多,區分點是`apply`第二個參數是傳遞數組: ~~~ Function.prototype.apply2 = function(context, arr){ context = context || window; // 因為傳遞過來的context有可能是null context.fn = this; // 讓fn的上下文為context arr = arr || []; // 對傳進來的數組參數進行處理 const result = context.fn(...arr); // 相當于context.fn(arguments[1], arguments[2], ...) delete context.fn; return result; // 因為有可能this函數會有返回值return } ~~~ 同樣的,我們來測試下: ~~~js var name = 'window name'; var obj = { name: 'call_me_R' }; // Function.prototype.apply2 is here ... function sayName(){ console.log((arguments[0] || '') + this.name); return this; } sayName(); // window name var _this = sayName.apply2(obj, ['hello ']); // hello call_me_R console.log(_this); // {name: "call_me_R"} ~~~ #### bind方法實現 `bind`的實現和上面的兩種就有些差別,雖然和`call`傳參相同,但是`bind`被調用后返回的是調用函數的指針。那么,這就說明`bind`內部是返回一個函數,思路打開了: ~~~js Function.prototype.bind2 = function(context, ...args){ var fn = this; return function () { // 這里不能使用箭頭函數,不然參數arguments的指向就很尷尬了,指向父函數的參數 fn.call(context, ...args, ...arguments); } } ~~~ 測試一下: ~~~js var name = 'window name'; var obj = { name: 'call_me_R' }; // Function.prototype.bind2 is here ... function sayName(){ console.log((arguments[0] || '') + this.name + (arguments[1] || '')); } sayName(); // window name sayName.bind2(obj, 'hello ')(); // hello call_me_R sayName.bind2(obj, 'hello ')('!'); // hello call_me_R! ~~~ ## call的性能會比apply好 在我們平時的開發中其實不必關注call和apply的性能問題,但是可以盡可能的去用call,特別是es6的reset解構的支持,call基本可以代替apply,可以看出lodash源碼里面并沒有直接用Function.prototype.apply,而是在參數較少(1-3)個時采用call的方式調用(因為lodash里面沒有超過4個參數的方法,PS如果一個函數的設計超過4個入參,那么這個函數就要考慮重構了) ## 參考文章 1. [談談JavaScript中的call、apply和bind](https://github.com/reng99/blogs/issues/29) 2. [call 和 apply 的區別是什么,哪個性能更好一些](https://muyiy.vip/question/js/48.html) 3. [call和apply的性能對比](https://github.com/noneven/__/issues/6)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看