亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

跟我學習javascript的call(),apply(),bind()與回調

2019-11-20 11:15:49
字體:
來源:轉載
供稿:網友

一、call(),apply(),bind()方法

JavaScript 中通過call或者apply用來代替另一個對象調用一個方法,將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。簡單的說就是改變函數執行的上下文,這是最基本的用法。兩個方法基本區別在于傳參不同。

call(obj,arg1,arg2,arg3); call第一個參數傳對象,可以是null。參數以逗號分開進行傳值,參數可以是任何類型。
apply(obj,[arg1,arg2,arg3]); apply第一個參數傳對象,參數可以是數組或者arguments 對象。
1、語法
先來看看JS手冊中對call的解釋:

call 方法
調用一個對象的一個方法,以另一個對象替換當前對象。

call([thisObj[,arg1[, arg2[,   [,.argN]]]]])
參數

thisObj可選項。將被用作當前對象的對象。
 arg1, arg2,  , arg可選項。將被傳遞方法參數序列。
說明
call 方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。

如果沒有提供 thisObj 參數,那么 Global 對象被用作 thisObj。
說明白一點其實就是更改對象的內部指針,即改變對象的this指向的內容。這在面向對象的js編程過程中有時是很有用的。

2、用法

因為function也是對象,所以每個函數都包含兩個非繼承而來的方法:apply()和call()。這兩個方法的用途都是在特定的作用域中調用函數,實際上等于設置函數體內this 對象的值。首先,apply()方法接收兩個參數:一個是在其中運行函數的作用域,另一個是參數數組。其中,第二個參數可以是Array 的實例,也可以是arguments 對象。例如:

function sum(num1, num2){ return num1 + num2;}function callSum1(num1, num2){ return sum.apply(this, arguments); // 傳入arguments 對象}function callSum2(num1, num2){ return sum.apply(this, [num1, num2]); // 傳入數組}alert(callSum1(10,10)); //20alert(callSum2(10,10)); //20

在上面這個例子中,callSum1()在執行sum()函數時傳入了this 作為this 值(因為是在全局作用域中調用的,所以傳入的就是window 對象)和arguments 對象。而callSum2 同樣也調用了sum()函數,但它傳入的則是this 和一個參數數組。這兩個函數都會正常執行并返回正確的結果。

在嚴格模式下,未指定環境對象而調用函數,則this 值不會轉型為window。除非明確把函數添加到某個對象或者調用apply()或call(),否則this 值將是undefined

3、不同點

call()方法與apply()方法的作用相同,它們的區別僅在于接收參數的方式不同。對于call()方法而言,第一個參數是this 值沒有變化,變化的是其余參數都直接傳遞給函數。換句話說,在使用call()方法時,傳遞給函數的參數必須逐個列舉出來,如下面的例子所示。

function sum(num1, num2){ return num1 + num2;}function callSum(num1, num2){ return sum.call(this, num1, num2);}alert(callSum(10,10)); //20

在使用call()方法的情況下,callSum()必須明確地傳入每一個參數。結果與使用apply()沒有什么不同。至于是使用apply()還是call(),完全取決于你采取哪種給函數傳遞參數的方式最方便。如果你打算直接傳入arguments 對象,或者包含函數中先接收到的也是一個數組,那么使用apply()肯定更方便;否則,選擇call()可能更合適。(在不給函數傳遞參數的情況下,使用哪個方法都無所謂) 。

4、擴充函數運行的作用域

事實上,傳遞參數并非apply()和call()真正的用武之地;它們真正強大的地方是能夠擴充函數
賴以運行的作用域。下面來看一個例子。

window.color = "red";var o = { color: "blue" };function sayColor(){ alert(this.color);}sayColor(); //redsayColor.call(this); //redsayColor.call(window); //redsayColor.call(o); //blue

這個例子是在前面說明this 對象的示例基礎上修改而成的。這一次,sayColor()也是作為全局函數定義的,而且當在全局作用域中調用它時,它確實會顯示”red”――因為對this.color 的求值會轉換成window.color 的求值。而sayColor.call(this)和sayColor.call(window),則是兩種顯式地在全局作用域中調用函數的方式,結果當然都會顯示”red”。但是,當運行sayColor.call(o)時,函數的執行環境就不一樣了,因為此時函數體內的this 對象指向了o,于是結果顯示的是”blue”。使用call()(或apply())來擴充作用域的最大好處,就是對象不需要與方法有任何耦合關系。

在前面例子的第一個版本中,我們是先將sayColor()函數放到了對象o 中,然后再通過o 來調用它的;而在這里重寫的例子中,就不需要先前那個多余的步驟了。

5、bind()方法

最后再來說 bind() 函數,上面講的無論是 call() 也好, apply() 也好,都是立馬就調用了對應的函數,而 bind() 不會, bind() 會生成一個新的函數,bind() 函數的參數跟 call() 一致,第一個參數也是綁定 this 的值,后面接受傳遞給函數的不定參數。 bind() 生成的新函數返回后,你想什么時候調就什么時候調,

window.color = "red";var o = { color: "blue" };function sayColor(){ alert(this.color);}var objectSayColor = sayColor.bind(o);objectSayColor(); //blue

在這里,sayColor()調用bind()并傳入對象o,創建了objectSayColor()函數。object-SayColor()函數的this 值等于o,因此即使是在全局作用域中調用這個函數,也會看到”blue”。

支持bind()方法的瀏覽器有IE9+、Firefox 4+、Safari 5.1+、Opera 12+和Chrome。

二、call(),apply()的繼承和回調

類的繼承

先來看這個例子:

function Person(name,age){ this.name = name;  this.age=age;  this.alertName = function(){  alert(this.name); } this.alertAge = function(){ alert(this.age); }}function webDever(name,age,sex){ Person.call(this,name,age);  this.sex=sex;  this.alertSex = function(){  alert(this.sex);  }}var test= new webDever(“愚人碼頭”,28,”男”);test.alertName();//愚人碼頭test.alertAge();//28test.alertSex();//男

這樣 webDever類就繼承Person類,Person.call(this,name,age) 的 意思就是使用 Person構造函數(也是函數)在this對象下執行,那么 webDever就有了Person的所有屬性和方法,test對象就能夠直接調用Person的方法以及屬性了

用于回調
call 和 apply在回調行數中也非常有用,很多時候我們在開發過程中需要對改變回調函數的執行上下文,最常用的比如ajax或者定時什么的,一般情況下,Ajax都是全局的,也就是window對象下的,來看這個例子:

function Album(id, title, owner_id) { this.id = id; this.name = title; this.owner_id = owner_id;};Album.prototype.get_owner = function (callback) { var self = this; $.get(‘/owners/' + this.owner_id, function (data) { callback && callback.call(self, data.name); });};var album = new Album(1, ‘生活', 2);album.get_owner(function (owner) { alert(‘The album' + this.name + ‘ belongs to ‘ + owner);});

這里

album.get_owner(function (owner) { alert(‘The album' + this.name + ‘ belongs to ‘ + owner);});

中的 this.name就能直接取到album對象中的name屬性了。

三 、回調函數

說起回調函數,好多人雖然知道意思,但是還是一知半解。至于怎么用,還是有點糊涂。網上的一些相關的也沒有詳細的說一下是怎么回事,說的比較片面。下面我只是說說個人的一點理解,大牛勿噴。

定義
回調是什么?
看維基的 Callback_(computer_programming) 條目:

In computer programming, a callback is a reference to a piece of executable code that is passed as an argument to other code.

在JavaScript中,回調函數具體的定義為:函數A作為參數(函數引用)傳遞到另一個函數B中,并且這個函數B執行函數A。我們就說函數A叫做回調函數。如果沒有名稱(函數表達式),就叫做匿名回調函數。

舉個例子:

你有事去隔壁寢室找同學,發現人不在,你怎么辦呢?
    方法1,每隔幾分鐘再去趟隔壁寢室,看人在不
    方法2,拜托與他同寢室的人,看到他回來時叫一下你
前者是輪詢,后者是回調。
那你說,我直接在隔壁寢室等到同學回來可以嗎?
可以啊,只不過這樣原本你可以省下時間做其他事,現在必須浪費在等待上了。
把原來的非阻塞的異步調用變成了阻塞的同步調用。
JavaScript的回調是在異步調用場景下使用的,使用回調性能好于輪詢。
因此callback 不一定用于異步,一般同步(阻塞)的場景下也經常用到回調,比如要求執行某些操作后執行回調函數。

一個同步(阻塞)中使用回調的例子,目的是在func1代碼執行完成后執行func2。

var func1=function(callback){ //do something. (callback && typeof(callback) === "function") && callback();}func1(func2); var func2=function(){}

異步回調的例子:

$(document).ready(callback);$.ajax({ url: "test.html", context: document.body}).done(function() {  $(this).addClass("done");}).fail(function() { alert("error");}).always(function() { alert("complete"); });

回調什么時候執行

回調函數,一般在同步情境下是最后執行的,而在異步情境下有可能不執行,因為事件沒有被觸發或者條件不滿足。另外,最好保證回調存在且必須是函數引用或者函數表達式:

(callback && typeof(callback) === "function") && callback();
我們來看一下一個粗略的一個定義“函數a有一個參數,這個參數是個函數b,當函數a執行完以后執行函數b。那么這個過程就叫回調?!?,這句話的意思是函數b以一個參數的形式傳入函數a并執行,順序是先執行a ,然后執行參數b,b就是所謂的回調函數。我們先來看下面的例子。

 function a(callback){ alert('a'); callback.call(this);//或者是 callback(), callback.apply(this),看個人喜好 } function b(){ alert('b'); } //調用 a(b);

這樣的結果是先彈出 ‘a',再彈出‘b'。這樣估計會有人問了“寫這樣的代碼有什么意思呢?好像沒太大的作用呢!”

是的,其實我也覺得這樣寫沒啥意思,“如果調用一個函數就直接在函數里面調用它不就行了”。我這只是給大家寫個小例子,做初步的理解。真正寫代碼的過程中很少用這樣無參數的,因為在大部分場景中,我們要傳遞參數。來個帶參數的:

function c(callback){ alert('c'); callback.call(this,'d'); }//調用c(function(e){ alert(e);});

這個調用看起來是不是似曾相識,這里e參數被賦值為'd',我們只是簡單的賦值為字符竄,其實也可以賦值為對象。Jquery里面是不是也有個e參數?

回調函數的使用場合

  • 資源加載:動態加載js文件后執行回調,加載iframe后執行回調,ajax操作回調,圖片加載完成執行回調,AJAX等等。
  • DOM事件及Node.js事件基于回調機制(Node.js回調可能會出現多層回調嵌套的問題)。
  • setTimeout的延遲時間為0,這個hack經常被用到,settimeout調用的函數其實就是一個callback的體現
  • 鏈式調用:鏈式調用的時候,在賦值器(setter)方法中(或者本身沒有返回值的方法中)很容易實現鏈式調用,而取值器(getter)相對來說不好實現鏈式調用,因為你需要取值器返回你需要的數據而不是this指針,如果要實現鏈式方法,可以用回調函數來實現
  • setTimeout、setInterval的函數調用得到其返回值。由于兩個函數都是異步的,即:他們的調用時序和程序的主流程是相對獨立的,所以沒有辦法在主體里面等待它們的返回值,它們被打開的時候程序也不會停下來等待,否則也就失去了setTimeout及setInterval的意義了,所以用return已經沒有意義,只能使用callback。callback的意義在于將timer執行的結果通知給代理函數進行及時處理。

當函數的實現過程非常漫長,你是選擇等待函數完成處理,還是使用回調函數進行異步處理呢?這種情況下,使用回調函數變得至關重要,例如:AJAX請求。若是使用回調函數進行處理,代碼就可以繼續進行其他任務,而無需空等。實際開發中,經常在javascript中使用異步調用,甚至在這里強烈推薦使用!

下面有個更加全面的使用AJAX加載XML文件的示例,并且使用了call()函數,在請求對象(requested object)上下文中調用回調函數。

function fn(url, callback){ var httpRequest;    //創建XHR httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :        window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined; //針對IE進行功能性檢測 httpRequest.onreadystatechange = function(){ if(httpRequest.readystate === 4 && httpRequest.status === 200){  //狀態判斷  callback.call(httpRequest.responseXML);  } }; httpRequest.open("GET", url); httpRequest.send();}fn("text.xml", function(){    //調用函數 console.log(this);   //此語句后輸出});console.log("this will run before the above callback.");  //此語句先輸出

我們請求異步處理,意味著我們開始請求時,就告訴它們完成之時調用我們的函數。在實際情況中,onreadystatechange事件處理程序還得考慮請求失敗的情況,這里我們是假設xml文件存在并且能被瀏覽器成功加載。這個例子中,異步函數分配給了onreadystatechange事件,因此不會立刻執行。

最終,第二個console.log語句先執行,因為回調函數直到請求完成才執行。

以上就是本文的全部內容,希望對大家的學習有所幫助。

詳細介紹請查看: 《詳解JavaScript的回調函數》

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产极品jizzhd欧美| 成人亚洲综合色就1024| 久久6精品影院| 成人信息集中地欧美| 最新国产精品拍自在线播放| 国产免费一区视频观看免费| 久久久久五月天| 久久国产天堂福利天堂| 91免费人成网站在线观看18| 国产日韩欧美在线观看| 欧美精品videos另类日本| 国产亚洲欧洲高清一区| 欧美精品999| 精品色蜜蜜精品视频在线观看| 久久人人爽人人爽爽久久| 97碰碰碰免费色视频| 91av在线视频观看| 日韩欧美在线第一页| 亚洲精品一区二区网址| 91爱视频在线| 久久久免费观看| 亚洲综合在线中文字幕| 国内精品久久久久影院优| 日韩中文理论片| 精品久久国产精品| 久久精品91久久香蕉加勒比| 国产一区私人高清影院| 色综合伊人色综合网| 国产精品视频久久久| 色777狠狠综合秋免鲁丝| 欧美专区在线播放| 18久久久久久| 一区二区三区回区在观看免费视频| 久久精品视频一| 啪一啪鲁一鲁2019在线视频| 亚洲精品v欧美精品v日韩精品| 日本国产欧美一区二区三区| 色综合久综合久久综合久鬼88| 日韩在线视频观看正片免费网站| 欧美成人国产va精品日本一级| 91九色视频在线| 午夜精品视频网站| 国产一区二区激情| 91黑丝在线观看| 欧美亚州一区二区三区| 日韩有码在线观看| 97超级碰碰人国产在线观看| 亚洲欧美一区二区三区情侣bbw| 91久久久国产精品| 亚洲福利视频在线| 久精品免费视频| 国产精品久久婷婷六月丁香| 久久激情五月丁香伊人| 麻豆精品精华液| 亚洲免费一级电影| 久久韩国免费视频| 欧美大全免费观看电视剧大泉洋| 欧美亚州一区二区三区| 欧美激情影音先锋| 欧美日韩成人在线视频| 亚洲精品自在久久| 久久久久久国产精品美女| 亚洲最大成人网色| 亚洲精品xxxx| 一本色道久久综合亚洲精品小说| 亚洲2020天天堂在线观看| 国产精品久久久久久久久久久新郎| 日韩69视频在线观看| www高清在线视频日韩欧美| 欧美天天综合色影久久精品| 91精品免费久久久久久久久| 精品国产一区二区三区久久久狼| 欧美激情国产精品| 91精品国产777在线观看| 成人免费观看49www在线观看| 久久综合88中文色鬼| 国产成人精彩在线视频九色| 九九视频直播综合网| 在线国产精品视频| 欧美精品久久久久久久| 毛片精品免费在线观看| 日韩一区二区精品视频| 精品福利在线观看| 高清欧美性猛交| 亚洲成在人线av| 国产精品狼人色视频一区| 日韩精品在线视频观看| 欧美wwwwww| 成人性教育视频在线观看| 久久免费国产精品1| 亚洲精品美女在线观看| 国产欧美精品久久久| 日韩一区二区久久久| 亚洲国产91精品在线观看| 国产精品1区2区在线观看| 日韩人在线观看| 亚洲无线码在线一区观看| 欧美极品在线视频| 久久av红桃一区二区小说| 欧美成人激情图片网| 青青在线视频一区二区三区| 青草青草久热精品视频在线网站| 精品久久久久久久大神国产| 不卡av电影在线观看| 国产精品高潮呻吟久久av无限| 成人午夜激情网| 91社影院在线观看| 久久精品免费电影| 中文字幕自拍vr一区二区三区| 色偷偷av一区二区三区| 亚洲v日韩v综合v精品v| 国产日本欧美在线观看| 欧美天堂在线观看| 国产精品欧美日韩一区二区| 国产亚洲欧美日韩美女| 欧美成人亚洲成人日韩成人| 国产精品吴梦梦| 国产成人啪精品视频免费网| 国产精品视频专区| 欧美性猛交xxxxx免费看| 懂色aⅴ精品一区二区三区蜜月| 亚洲欧美中文日韩在线| 国产在线精品自拍| 国产亚洲精品一区二555| 亚洲人成在线观看| 欧美激情一区二区三区成人| 中文字幕v亚洲ⅴv天堂| 久久精品成人欧美大片古装| 成人国内精品久久久久一区| 91超碰中文字幕久久精品| 亚洲第一黄色网| 精品欧美激情精品一区| 日韩免费观看网站| 色综合久久久久久中文网| 成人妇女免费播放久久久| 一本色道久久88综合亚洲精品ⅰ| 久久亚洲精品小早川怜子66| 在线精品播放av| 久99九色视频在线观看| 亚洲色图av在线| 国产精品黄页免费高清在线观看| 日韩美女视频免费在线观看| 国产亚洲欧洲高清| 欧美日韩一区二区免费在线观看| 午夜精品久久久久久99热| 国产成人综合久久| 亚洲精品动漫100p| 亚洲欧美成人网| 青草成人免费视频| 欧美做爰性生交视频| 日韩av一卡二卡| 日韩最新中文字幕电影免费看| 国产精品视频免费在线观看| 欧美巨大黑人极品精男| xvideos国产精品| 久久久久久久av| 91亚洲人电影| 51午夜精品视频| 国产69久久精品成人看| 久久久亚洲国产| 日韩在线中文字| 国产成人91久久精品| 亚洲系列中文字幕| 亚洲最大av网|