函数的四种调用模式
根据函数内部this的指向不同,可以将函数的调用模式分成4种
- 函数调用模式
- 方法调用模式
- 构造函数调用模式
- 上下文调用模式(借用方法模式)
函数:当一个函数不是一个对象的属性时,我们称之为函数。
方法:当一个函数被保存为对象的一个属性时,我们称之为方法。
函数调用模式
如果一个函数不是一个对象的属性时,就是被当做一个函数来进行调用的。此时this指向了window
function fn(){
console.log(this);//指向window
}
fn();
方法调用模式
当一个函数被保存为对象的一个属性时,我们称之为一个方法。当一个方法被调用时,this被绑定到当前对象
var obj = {
sayHi:function(){
console.log(this);//在方法调用模式中,this指向调用当前方法的对象。
}
}
obj.sayHi();
构造函数调用模式
如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上。
function Person(){
console.log(this);
}
Person();//this指向window
var p = new Person();//this指向p
总结:分析this的问题,主要就是区分函数的调用模式,看函数是怎么被调用的。
几种特殊的this指向
- 定时器中的this指向了window,因为定时器的function最终是由window来调用的。
- 事件中的this指向的是当前的元素,在事件触发的时候,浏览器让当前元素调用了function
上下文调用模式
上下文调用模式也叫方法借用模式,分为apply与call
使用方法: 函数.call() 或者 函数.apply()
call、apply、bind三者的异同
同:
-
call()、apply()和bind()都可以改变this指向
-
call()、apply()用法一样
-
call()、apply()都可以调用函数
-
call()、apply()都可以给函数传实参
异:
-
call()和apply()的传参写法不一样:
-
call(this对象,参数1,参数2,参数3)
-
apply(this对象,[参数1,参数2,参数3])
-
如果传的参数较少且不是数值或者为数组,适合call()
-
如果传的参数是数组或者是位数组,适合apply()
-
bind用法和call()、apply()都不一样,bind会克隆调用它的函数并通过第一个参数改变该函数的this,最后返回一个新函数(this改变),原函数this不变
// var newfn = fn.binde(this对象)
call方法
call方法可以调用一个函数,并且可以指定这个函数的this
指向
//所有的函数都可以使用call进行调用
//参数1:指定函数的this,如果不传,则this指向window
//其余参数:和函数的参数列表一模一样。
//说白了,call方法也可以和()一样,进行函数调用,call方法的第一个参数可以指定函数内部的this指向。
fn.call(thisArg, arg1, arg2, arg2);
- 借用对象的方法
// call()练习:使用数组方法向位数组中添加属性,并且length属性也要相应改变
// 非严格模式下JS中分号是不必的,但在()、{}、[]前面必须有分号
var obj = {
0: "马超",
1: "关羽",
2: "张飞",
length: 3
}
;[].push.call(obj, "黄忠")
console.log(obj);//{0: "马超", 1: "关羽", 2: "张飞", 3: "黄忠", length: 4}
apply方法
apply()
方法的作用和 call()
方法类似,只有一个区别,就是apply()
方法接受的是一个包含多个参数的数组。而call()
方法接受的是若干个参数的列表
call和apply的使用场景:
- 如果参数比较少,使用call会更加简洁
- 如果参数存放在数组中,此时需要使用apply
// apply()练习:求数组中的最大值
var arr = [1, 33, 97, 22, 50, 88]
var res = Math.max.apply([], arr)
console.log(res);
bind方法
bind() 方法创建一个新的函数, 可以绑定新的函数的this
指向
// 返回值:新的函数
// 参数:新函数的this指向,当绑定了新函数的this指向后,无论使用何种调用模式,this都不会改变。
var newFn = fn.bind(window);
// bind()练习
var ff = {
name: "欧皓辰",
lover: "池早早",
sayLove: function () {
// 如果不改变定时器里的this,结果this.lover=undefined,此定时器的this是window
// 方法一:
// var that = this 保存this到that中,定时器使用that(定时器的this改变为that)
// 方法二:
// this ==> ff
// 用bind(this) 方法模式调用,此this是调用该方法的对象
setInterval(function () {
console.log("Dear" + this.lover + ", 我" + this.name + ",非常想你,想你想的睡不着");
}.bind(this), 1000)
}
}
ff.sayLove();//Dear 池早早 , 我欧皓辰,非常想你,想你想的睡不着