apply 接受两个参数,第一个参数指定了函数体内this 对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数:
var func = function( a, b, c ){ alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ] }; func.apply( null, [ 1, 2, 3 ] );
在这段代码中,参数 1、2、3 被放在数组中一起传入func函数,它们分别对应func参数列表中的a、b、c。
call 传入的参数数量不固定,跟apply 相同的是,第一个参数也是代表函数体内的this 指向,从第二个参数开始往后,每个参数被依次传入函数:
var func = function( a, b, c ){ alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ] }; func.call( null, 1, 2, 3 );
当调用一个函数时,JavaScript 的解释器并不会计较形参和实参在数量、类型以及顺序上的区别,JavaScript 的参数在内部就是用一个数组来表示的。从这个意义上说,apply比call的使用率更高,我们不必关心具体有多少参数被传入函数,只要用apply 一股脑地推过去就可以了。call是包装在apply上面的一颗语法糖,如果我们明确地知道函数接受多少个参数,而且想一目了然地表达形参和实参的对应关系,那么也可以用call 来传送参数。
call和apply的用途
1. 改变this 指向
call 和apply 最常见的用途是改变函数内部的this 指向,我们来看个例子:
var obj1 = { name: 'sven' }; var obj2 = { name: 'anne' }; window.name = 'window'; var getName = function(){ alert ( this.name ); }; getName(); // 输出: window getName.call( obj1 ); // 输出: sven getName.call( obj2 ); // 输出: anne
当执行getName.call( obj1 )这句代码时,getName 函数体内的this 就指向obj1 对象,所以此处的
var getName = function(){ alert ( this.name ); };
实际上相当于:
var getName = function(){ alert ( obj1.name ); // 输出: sven };
在实际开发中,经常会遇到this指向被不经意改变的场景,比如有一个div节点,div节点的onclick 事件中的this 本来是指向这个div的:
document.getElementById( 'div1' ).onclick = function(){ alert( this.id ); // 输出:div1 };
假如该事件函数中有一个内部函数func,在事件内部调用func 函数时,func 函数体内的this就指向了window,而不是我们预期的div,见如下代码:
document.getElementById( 'div1' ).onclick = function(){ alert( this.id ); // 输出:div1 var func = function(){ alert ( this.id ); // 输出:undefined } func(); };
这时候我们用call 来修正func 函数内的this,使其依然指向div:
document.getElementById( 'div1' ).onclick = function(){ var func = function(){ alert ( this.id ); // 输出:div1 } func.call( this ); };
2. Function.prototype.bind
大部分高级浏览器都实现了内置的Function.prototype.bind,用来指定函数内部的this 指向,即使没有原生的Function.prototype.bind 实现,我们来模拟一个也不是难事,代码如下:
Function.prototype.bind = function( context ){ var self = this; // 保存原函数 return function(){ // 返回一个新的函数 return self.apply( context, arguments ); // 执行新的函数的时候,会 把之前传入的context // 当作新函数体内的this } }; var obj = { name: 'sven' }; var func = function(){ alert ( this.name ); // 输出:sven }.bind( obj); func();
我们通过Function.prototype.bind 来“包装”func 函数,并且传入一个对象context 当作参数,这个context 对象就是我们想修正的this 对象。
在Function.prototype.bind 的内部实现中,我们先把func 函数的引用保存起来,然后返回一个新的函数。当我们在将来执行func 函数时,实际上先执行的是这个刚刚返回的新函数。在新函数内部,self.apply( context, arguments )这句代码才是执行原来的func 函数,并且指定context对象为func 函数体内的this。
这是一个简化版的Function.prototype.bind 实现,通常我们还会把它实现得稍微复杂一点,
使得可以往func 函数中预先填入一些参数:
Function.prototype.bind = function(){ var self = this, // 保存原函数 context = [].shift.call( arguments ), // 需要绑定的this 上下文 args = [].slice.call( arguments ); // 剩余的参数转成数组 return function(){ // 返回一个新的函数 return self.apply( context, [].concat.call( args, [].slice.call( arguments ) ) ); // 执行新的函数的时候,会把之前传入的context 当作新函数体内的this // 并且组合两次分别传入的参数,作为新函数的参数 } }; var obj = { name: 'sven' }; var func = function( a, b, c, d ){ alert ( this.name ); // 输出:sven alert ( [ a, b, c, d ] ) // 输出:[ 1, 2, 3, 4 ] }.bind( obj, 1, 2 ); func( 3, 4 );
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
call,apply,区别
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 群星《抖音嗨疯-DISCO英文版》[WAV+CUE][1G]
- 群星.1990-情义无价(TP版)【中唱】【WAV+CUE】
- 马兆骏.1990-心情·七月【滚石】【WAV+CUE】
- 方伊琪.1979-沙鸥(LP版)【星岛全音】【WAV+CUE】
- 蔡琴《醇厚嗓音》6N纯银SQCD【WAV+CUE】
- 陈曦《遇见HQCD》[WAV+CUE]
- 大提琴-刘欣欣《爱的问候》HDCD[WAV+CUE]
- 周耀辉/邓慧中《从什么时候开始》[320K/MP3][95.71MB]
- 周耀辉/邓慧中《从什么时候开始》[FLAC/分轨][361.29MB]
- 蒋荣宗《蒋荣宗ZONG x FOCA 夏日马戏节》[320K/MP3][89.28MB]
- 坣娜.1997-你怎么可以不爱我【巨石】【WAV+CUE】
- 群星.1992-暗恋桃花源电影原声带【滚石】【WAV+CUE】
- 林隆璇.1989-愤怒的情歌【巨石】【WAV+CUE】
- 勤琴《海上花》[DTS-WAV分轨]
- 群星《歌声有故事》[DTS-WAV分轨]