Ikuti saya untuk mempelajari kemahiran javascript call(), apply(), bind() dan callback_javascript

WBOY
Lepaskan: 2016-05-16 15:32:16
asal
1213 orang telah melayarinya

1. kaedah panggil(), apply(), bind()

Dalam JavaScript, panggil atau gunakan digunakan untuk memanggil kaedah dan bukannya objek lain, menukar konteks objek fungsi daripada konteks awal kepada objek baharu yang ditentukan oleh thisObj. Ringkasnya, ia adalah untuk menukar konteks pelaksanaan fungsi Ini adalah penggunaan yang paling asas. Perbezaan asas antara kedua-dua kaedah terletak pada parameter berbeza yang diluluskan.

panggilan(obj,arg1,arg2,arg3); Parameter panggilan pertama ialah objek, yang boleh menjadi nol. Parameter dipisahkan dengan koma dan boleh daripada sebarang jenis.
apply(obj,[arg1,arg2,arg3]); Parameter pertama permohonan ialah objek, dan parameter boleh menjadi objek tatasusunan atau argumen.
1. Tatabahasa
Mari kita lihat dahulu penjelasan panggilan dalam manual JS:

kaedah panggilan
Panggil kaedah pada objek untuk menggantikan objek semasa dengan objek lain.

panggil([thisObj[,arg1[, arg2[, [,.argN]]]]])
Parameter

Obj ini adalah pilihan. Objek yang akan digunakan sebagai objek semasa.
arg1, arg2, , arg pilihan. Urutan parameter kaedah akan diluluskan.
Penerangan
Kaedah panggilan boleh digunakan untuk memanggil kaedah bagi pihak objek lain. Kaedah panggilan menukar konteks objek fungsi daripada konteks awal kepada objek baharu yang ditentukan oleh thisObj.

Jika tiada parameter thisObj disediakan, objek Global digunakan sebagai thisObj.
Untuk menjelaskannya, ia sebenarnya bermaksud menukar penunjuk dalaman objek, iaitu, menukar kandungan yang ditunjukkan oleh objek ini. Ini kadangkala berguna dalam pengaturcaraan js berorientasikan objek.

2 Oleh kerana fungsi juga merupakan objek, setiap fungsi mengandungi dua kaedah yang tidak diwarisi: apply() dan call(). Tujuan kedua-dua kaedah ini adalah untuk memanggil fungsi dalam skop tertentu, yang sebenarnya bersamaan dengan menetapkan nilai objek ini dalam badan fungsi. Pertama, kaedah apply() menerima dua parameter: satu ialah skop di mana fungsi dijalankan, dan satu lagi ialah tatasusunan parameter. Antaranya, parameter kedua boleh menjadi contoh Array atau objek argumen. Contohnya:

Dalam contoh di atas, callSum1() meneruskan ini sebagai nilai ini (kerana ia dipanggil dalam skop global, jadi objek tetingkap dihantar masuk) dan objek argumen apabila melaksanakan fungsi sum(). Dan callSum2 juga memanggil fungsi sum(), tetapi ia lulus dalam ini dan tatasusunan parameter. Kedua-dua fungsi akan dilaksanakan secara normal dan mengembalikan hasil yang betul.
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)); //20
alert(callSum2(10,10)); //20
Salin selepas log masuk
Dalam mod ketat, jika fungsi dipanggil tanpa menyatakan objek persekitaran, nilai ini tidak akan ditukar kepada tetingkap. Melainkan fungsi itu ditambah secara eksplisit pada objek atau apply() atau call() dipanggil, nilai ini tidak akan ditentukan

3. Perbezaan

Kaedah call() mempunyai fungsi yang sama dengan kaedah apply() Satu-satunya perbezaan terletak pada cara mereka menerima parameter. Untuk kaedah panggilan(), parameter pertama ialah nilai ini, yang tidak berubah ialah parameter yang selebihnya dihantar terus ke fungsi. Dalam erti kata lain, apabila menggunakan kaedah panggilan(), parameter yang dihantar ke fungsi mesti dihitung satu demi satu, seperti yang ditunjukkan dalam contoh di bawah.

Apabila menggunakan kaedah call(), callSum() mesti secara eksplisit melepasi setiap parameter. Hasilnya tidak berbeza daripada menggunakan apply(). Sama ada untuk menggunakan apply() atau call(), semuanya bergantung pada kaedah menghantar parameter kepada fungsi yang paling sesuai untuk anda. Jika anda bercadang untuk meneruskan objek hujah secara langsung, atau perkara pertama yang diterima dalam fungsi yang mengandungi juga adalah tatasusunan, maka pastinya lebih mudah untuk menggunakan apply(), jika tidak, call() mungkin lebih sesuai. (Tanpa menghantar parameter kepada fungsi, tidak kira kaedah mana yang digunakan).
function sum(num1, num2){
 return num1 + num2;
}
function callSum(num1, num2){
 return sum.call(this, num1, num2);
}
alert(callSum(10,10)); //20
Salin selepas log masuk

4. Kembangkan skop operasi fungsi

Malah, lulus parameter bukanlah penggunaan sebenar apply() dan call(); kuasa sebenar mereka ialah keupayaan mereka untuk melanjutkan fungsi Skop di mana ia beroperasi. Mari kita lihat contoh.


这个例子是在前面说明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
Salin selepas log masuk

在这里,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();//28

test.alertSex();//男

Salin selepas log masuk

这样 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);

});

Salin selepas log masuk

这里

album.get_owner(function (owner) {

 alert(‘The album' + this.name + ‘ belongs to ‘ + owner);

});

Salin selepas log masuk

中的 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(){
}

Salin selepas log masuk

异步回调的例子:

$(document).ready(callback);

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

Salin selepas log masuk

回调什么时候执行

回调函数,一般在同步情境下是最后执行的,而在异步情境下有可能不执行,因为事件没有被触发或者条件不满足。另外,最好保证回调存在且必须是函数引用或者函数表达式:

(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);
Salin selepas log masuk

这样的结果是先弹出 ‘a',再弹出‘b'。这样估计会有人问了“写这样的代码有什么意思呢?好像没太大的作用呢!”

是的,其实我也觉得这样写没啥意思,“如果调用一个函数就直接在函数里面调用它不就行了”。我这只是给大家写个小例子,做初步的理解。真正写代码的过程中很少用这样无参数的,因为在大部分场景中,我们要传递参数。来个带参数的:

function c(callback){
 alert('c');
 callback.call(this,'d');
 }
//调用
c(function(e){
 alert(e);
});
Salin selepas log masuk

这个调用看起来是不是似曾相识,这里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.");  //此语句先输出

Salin selepas log masuk

我们请求异步处理,意味着我们开始请求时,就告诉它们完成之时调用我们的函数。在实际情况中,onreadystatechange事件处理程序还得考虑请求失败的情况,这里我们是假设xml文件存在并且能被浏览器成功加载。这个例子中,异步函数分配给了onreadystatechange事件,因此不会立刻执行。

最终,第二个console.log语句先执行,因为回调函数直到请求完成才执行。

以上就是本文的全部内容,希望对大家的学习有所帮助。

详细介绍请查看: 《详解JavaScript的回调函数》

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!