call、apply、bind
那了解了函数 this 指向的不同场景之后,我们知道有些情况下我们为了使用某种特定环境的 this 引用,这时候时候我们就需要采用一些特殊手段来处理了,例如我们经常在定时器外部备份 this 引用,然后在定时器函数内部使用外部 this 的引用。
然而实际上对于这种做法我们的 JavaScript 为我们专门提供了一些函数方法用来帮我们更优雅的处理函数内部 this 指向问题。
那就是 call、apply、bind 三个函数方法。
call
call()
方法调用一个函数, 其具有一个指定的 this
值和分别地提供的参数(参数的列表)。
注意:该方法的作用和 apply()
方法类似,只有一个区别,就是 call()
方法接受的是若干个参数的列表,而 apply()
方法接受的是一个包含多个参数的数组。
语法:
fun. call ( thisArg[ , arg1[ , arg2[ , ... ] ] ] )
参数:
thisArg
在 fun 函数运行时指定的 this 值 如果指定了 null 或者 undefined 则内部 this 指向 window arg1, arg2, ...
apply
apply()
方法调用一个函数, 其具有一个指定的 this
值,以及作为一个数组(或类似数组的对象)提供的参数。
注意:该方法的作用和 call()
方法类似,只有一个区别,就是 call()
方法接受的是若干个参数的列表,而 apply()
方法接受的是一个包含多个参数的数组。
语法:
fun. apply ( thisArg, [ argsArray] )
参数:
apply()
与 call()
非常相似,不同之处在于提供参数的方式。 apply()
使用参数数组而不是一组参数列表。例如:
fun. apply ( this , [ 'eat' , 'bananas' ] )
apply和call的使用案例
<!DOCTYPE html>
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< title> title</ title>
< script>
//apply和call的使用
//作用:可以改变this的指向
function f1 ( x, y) {
console. log ( "结果是:" + ( x+ y) + this ) ;
return "10000" ;
}
f1 ( 10 , 20 ) ; //函数的调用
console. log ( "========" ) ;
//此时的f1实际上是当成对象来使用的,对象可以调用方法
//apply和call方法也是函数的调用的方式
f1. apply ( ) ;
f1. call ( ) ;
console. log ( "==========" ) ;
f1. apply ( null ) ;
f1. call ( null ) ;
//apply和call方法中如果没有传入参数,或者是传入的是null,那么调用该方法的函数对象中的this就是默认的window
f1. apply ( null , [ 100 , 200 ] ) ;
f1. call ( null , 100 , 200 ) ;
//apply和call都可以让函数或者方法来调用,传入参数和函数自己调用的写法不一样,但是效果是一样的
var result1= f1. apply ( null , [ 10 , 20 ] ) ;
var result2= f1. call ( null , 10 , 20 ) ;
console. log ( result1) ;
console. log ( result2) ;
console. log ( "==============================" ) ;
// function f1(x,y) {
// console.log("这个函数是window对象的一个方法:"+(x+y)+this.sex);
// }
// window.f1(10,20);
// //obj是一个对象
// var obj={
// age:10,
// sex:"男"
// };
//
// window.f1.apply(obj,[10,20]);
// window.f1.call(obj,10,20);
// console.dir(obj);
//apply和call可以改变this的指向
function Person ( age, sex) {
this . age= age;
this . sex= sex;
}
//通过原型添加方法
Person. prototype. sayHi = function ( x, y) {
console. log ( "您好啊:" + this . sex) ;
return 1000 ;
} ;
var per= new Person ( 10 , "男" ) ;
per. sayHi ( ) ;
console. log ( "==============" ) ;
function Student ( name, sex) {
this . name= name;
this . sex= sex;
}
var stu= new Student ( "小明" , "女" ) ;
var r1= per. sayHi. apply ( stu) ;
var r2= per. sayHi. call ( stu) ;
console. log ( r1) ;
console. log ( r2) ;
</ script>
</ head>
< body>
</ body>
</ html>
bind
bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。
当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。
绑定函数被调用时,bind() 也接受预设的参数提供给原函数。 一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
语法:
fun. bind ( thisArg[ , arg1[ , arg2[ , ... ] ] ] )
参数:
thisArg
当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用new 操作符调用绑定函数时,该参数无效。 arg1, arg2, …
当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
返回值:
返回由指定的this值和初始化参数改造的原函数拷贝。
示例1:
this . x = 9 ;
var module = {
x: 81 ,
getX: function ( ) { return this . x; }
} ;
module. getX ( ) ; // 返回 81
var retrieveX = module. getX;
retrieveX ( ) ; // 返回 9, 在这种情况下,"this"指向全局作用域
// 创建一个新函数,将"this"绑定到module对象
// 新手可能会被全局的x变量和module里的属性x所迷惑
var boundGetX = retrieveX. bind ( module) ;
boundGetX ( ) ; // 返回 81
示例2:
function LateBloomer ( ) {
this . petalCount = Math. ceil ( Math. random ( ) * 12 ) + 1 ;
}
// Declare bloom after a delay of 1 second
LateBloomer. prototype. bloom = function ( ) {
window. setTimeout ( this . declare. bind ( this ) , 1000 ) ;
} ;
LateBloomer. prototype. declare = function ( ) {
console. log ( 'I am a beautiful flower with ' +
this . petalCount + ' petals!' ) ;
} ;
var flower = new LateBloomer ( ) ;
flower. bloom ( ) ; // 一秒钟后, 调用'declare'方法
小结
call 和 apply 特性一样
都是用来调用函数,而且是立即调用 但是可以在调用函数的同时,通过第一个参数指定函数内部 this
的指向 call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可 apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递 如果第一个参数指定了 null
或者 undefined
则内部 this 指向 window bind
可以用来指定内部 this 的指向,然后生成一个改变了 this 指向的新的函数 它和 call、apply 最大的区别是:bind 不会调用 bind 支持传递参数,它的传参方式比较特殊,一共有两个位置可以传递
在 bind 的同时,以参数列表的形式进行传递 在调用的时候,以参数列表的形式进行传递 那到底以谁 bind 的时候传递的参数为准呢还是以调用的时候传递的参数为准 两者合并:bind 的时候传递的参数和调用的时候传递的参数会合并到一起,传递到函数内部