JS中call、apply、bind使用指南,帶部分原理。

来源:http://www.cnblogs.com/pssp/archive/2016/08/19/5787116.html
-Advertisement-
Play Games

為什麼需要這些?主要是因為this,來看看this乾的好事。 box.onclick = function(){ function fn(){ alert(this); } fn();}; 我們原本以為這裡面的this指向的是box,然而卻是Window。一般我們這樣解決: box.onclick ...


為什麼需要這些?主要是因為this,來看看this乾的好事。

 

box.onclick = function(){
  function fn(){
    alert(this);
  }
  fn();
};

我們原本以為這裡面的this指向的是box,然而卻是Window。一般我們這樣解決:

box.onclick = function(){
  var _this = this;
  function fn(){
    alert(_this);
  }
  fn();
};


將this保存下來。

 

還有一些情況,有時我們想讓偽數組也能夠調用數組的一些方法,這時call、apply、bind就派上用場了。

 

我們先來解決第一個問題修複this指向。


box.onclick = function(){
  function fn(){
    alert(this);
  }
  fn();
};

改成如下:

 

box.onclick = function(){
  function fn(){
    console.log(this);
  }
  fn.call(this);
};

很神奇吧,call的作用就是改變this的指向的,第一個傳的是一個對象,就是你要借用的那個對象。

 

fn.call(this);

 

  這裡的意思是讓this去調用fn這個函數,這裡的this是box,這個沒有意見吧?如果這個你不清楚,很可能你是javscript的新朋友。box調用fn,這句話非常重要,我們知道this它始終指向一個對象,剛好box就是一個對象。那麼fn裡面的this就是box。

 

box.onclick = function(){
  function fn(){
    console.log(this);
  }
  fn.call(this);
};

 

這句話在某些情況下是可以簡寫的,比如:


box.onclick = function(){
  var fn = function(){
    console.log(this); //box
  }.call(this);
};

 

或者這樣:

 

box.onclick = function(){
  (function(){
    console.log(this);
  }.call(this)); //box
};

 

又或者這樣:


var objName = {name:'JS2016'};
var obj = {
  name:'0 _ 0',
  sayHello:function(){
    console.log(this.name);
  }.bind(objName)
};
obj.sayHello();//JS2016

 

call和apply、bind但是用來改變this的指向的,但也有一些小小的差別。下麵我們來看看它們的差別在哪。

 

function fn(a,b,c,d){
  console.log(a,b,c,d);
}

//call
fn.call(null,1,2,3);

//apply
fn.apply(null,[1,2,3]);

//bind
var f = fn.bind(null,1,2,3);
f(4);

 

結果如下:


1 2 3 undefined
1 2 3 undefined
1 2 3 4

  前面說過第一個參數傳的是一個你要借用的對象,但這麼我們不需要,所有就傳了一個null,當然你也可以傳其他的,反正在這裡沒有用到,除了第一個參數後面的參數將作為實際參數傳入到函數中。

  call就是挨個傳值,apply傳一個數組,bind也是挨個傳值,但和call和apply還有多少不同,使用call和apply會直接執行這個函數,而bind並不會而是將綁定好的this重新返回一個新函數,什麼時候調用由你自己決定。


var objName = {name:'JS2016'};
var obj = {
  name:'0 _ 0',
  sayHello:function(){
    console.log(this.name);
  }.bind(objName)
};
obj.sayHello();//JS2016


這裡也就是為什麼我要用bind的原因,如果用call的話就會報錯了。自己想想這個sayHello在obj都已經執行完了,就根本沒有sayHello這個函數了。

 

這幾個方法使用的好的話可以幫你解決不少問題比如:

 

正常情況下Math.max只能這樣用

Math.max(10,6)

但如果你想傳一個數組的話你可以用apply

var arr = [1,2,30,4,5];
console.log(Math.max.apply(null,arr));

又或者你想讓偽數組調用數組的方法

function fn(){
  [].push.call(arguments,3);
  console.log(arguments); //[1, 2, 3]
}
fn(1,2);

再者:

var arr = ['aaabc'];
console.log(''.indexOf.call(arr,'b')); //3

牛逼不,簡直偷梁換柱,當然還有很多可以利用的,自己盡情花輝去吧。

 

簡單說一下這種偷梁換柱的原理吧,實際上瀏覽器內部根本就不在乎你是誰,它只關心你傳給我的是不是我能夠運行的,如下:

 

正常情況


var str = 'aaabc';
console.log(str.indexOf('b'));

 

而這種情況其實做的事情和上面一模一樣,看我來拆解。

 

var arr = ['aaabc'];
''.indexOf.call(arr);

 

這句話就是說讓arr調用字元串的indexOf方法,前面說過了瀏覽器內部不在乎你是誰,所以誰都可以來調用,但不是100%成功,具體看如下。

 

''.indexOf.call(arr,'b')

這裡的arr就是['aaabc'],內部很可能拆成了'aaabc',因此就成了下麵的這段代碼。

 

'aaabc'.indexOf('b');

這就是它們的秘密。

 

這裡得說一下bind在某些瀏覽器下不相容。我們來模擬一個玩玩。


Function.prototype.$bind = function(obj){
    //保存當前this
  var _this = this;
    //截取除了第一個以外的所有實際參數
  var a = [].slice.call(arguments,1);
    //返回一個新函數
  return function(){
    //讓當前那個調用的函數的this指向obj,並且把實參傳給它,這裡用了concat是因為,我們可能在綁定以後還傳遞參數,所以才把他們合併起來。如f(4)這個是在綁定以後傳的參數,a這個argument是綁定時的。
    _this.apply(obj,a.concat([].slice.call(arguments)));
  };
};

function fn(a,b,c,d){
  console.log(a,b,c,d);
}

var f = fn.$bind(null,1,2,3);
f(4);

 

這個方法和實際上的bind還是差別很大的,如


var arr = ['JSS'];

var index = ''.indexOf.$bind(arr,'S');
console.log(index())

------------------

function fff(){
  [].push.$bind(arguments,1);
  console.log(arguments);
}

fff();

這些都沒法使用,因為技術有限就沒辦法帶大家封裝一個完美的bind了,如果有需要網上搜索一下吧。

 

結束了啊。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 隨著移動設備的普及,移動web在前端工程師們的工作中占有越來越重要的位置。移動設備更新速度頻繁,手機廠商繁多,導致的問題是每一臺機器的屏幕寬度和解析度不一樣。這給我們在編寫前端界面時增加了困難,適配問題在當下顯得越來越突出。記得剛剛開始開發移動端產品的時候向設計MM要了不同屏幕的設計圖,結果可 ...
  • 話說App一般都帶有分享到社交平臺的入口,web網頁的分享也有很不錯的框架,但是隨著HTML5的不斷發展,手機web頁面越來越多的進入到我們的生活中,那如何在我們的手機上完成分享呢?話說各大分享平臺都有針對Android、Ios的SDK,作為開發者,我們只需要將SDK集成的我們的項目中即可,通過提供 ...
  • 標簽頁的切換方式 1、控制tab的顯示與隱藏 2、tab不切換,數據載入 控制tab的顯示與隱藏 前端腳本: 1、jquery實現: 引入jquery文件,代碼簡潔 jquery文件較大,瀏覽器不相容 2、js 實現 無需引入jquery文件代碼量大,需每個標簽添加函數及ID 3、插件實現 無需引入 ...
  • let與塊級作用域 在代碼中,使用var申明的變數在代碼塊外面能被識別,但是let命令卻不能被識別,這樣就實現了js的塊級作用域,我們在使用條件語句 迴圈語句等就會不擔心變數污染的問題了,以下是兩種寫法等對比: es6: es5: 在{}用let聲明的變數只有在{}內是有效的 let不會有變數提升 ...
  • 以下的分享是本人最近幾天學習了margin知識後,大有啟發,感覺以前對margin的瞭解簡直太淺薄。所以寫成以下文章,一是供自己整理思路;二是把知識分享出來,避免各位對margin屬性的誤解。內容可能會有點多,但都是精華,希望大家耐心學習。 以下的分享會分為如下內容: 1.margin 屬性的簡單介 ...
  • 在我電腦屏幕上顯示的 電腦是 1920*1080這是在document.compatMode:css1Compat模式 現在是document.compatMode:BackCompat:頁面沒有!doctype聲明 以上紅色部分就是說document.compatMode模式的區別下的網頁可視區域 ...
  • 定義 JavaScript定義正則表達式有兩種方法。 1.RegExp構造函數 它接收兩個參數:一個是要匹配的字元串模式,另一個是可選的標誌字元串。 2.字面量 正則表達式的匹配模式支持三種標誌字元串: g:global,全局搜索模式,該模式將被應用於所有字元串,而並非搜索到第一個匹配項就停止搜索; ...
  • 插件!插件!天天聽到有人求這個插件,那個插件的,當然,用第三方插件可以大幅提高開發效率,但作為新手,我還是喜歡自己來實現,主要是我有時間! 今天我來給大家分享下用原生JS實現圖片輪播的寫法 前輩們可以無視下麵這段廢話: 在開始之前,先說下我學前端到現在的一點感受。到今天應該有兩個月左右了吧,基本每天 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...