###** arguments** 废话不多说,直接先看一段最简单的函数:
function getSum(a,b,c,d){
return a+b+c+d
}
啥意思?教你求和?
答案就是求和,你没看错。求4个5个数的和还可以这样写,要是10个呢?a+b+c+d+e.....
那要是100个呢?完了,字母都不够用了。其实你可以这样写:
function getSum(){
var sum = 0
for(var i=0;i<arguments.length;i++){
sum += arguments[i]
}
return sum
}
console.log(getSum(1,2,3,4)) //输出10
函数内部的arguments是什么?也没有声明,也没有传参。其实它是函数的隐式参数,每个函数都会有,并且arguments是一个伪数组,用来代替不确定个数的参数的,可以用arguments加下标的方式获取传给getSum函数的参数,它还有length属性,这些都与真正的数组相似,但它没有数组的方法,比如push、jion等。
this
除了arguments,函数还有个隐式参数,即this。有函数的地方就会有this,this指向的是函数调用的上下文,上下文?啥意思?记得初中高中做语文阅读题最怕的一句话就是:联系上下文理解某句话或某个词语的意思。
但是如果我们明白了函数的四种调用方式,对应this有四种指向,就不怕不清楚this的指向了。
1. 函数作为普通函数被调用;
2. 函数作为对象的方法被调用;
3. 函数作为构造器被调用;
4. 使用apply()和call()进行调用;
第一种:
var name = "cat"
function fun(){
var name = "dog"
console.log(this.name) //cat
console.log(this==window) //true
}
fun()
函数作为普通函数被调用,this指向全局作用域,即window对象,将这种调用方式与下面第二种会更加清楚。
第二种
var name = "cat"
var obj={
name:"dog",
getName:function(){
console.log(this.name)
}
}
obj.getName() //dog
这种,函数 function ( ){ console.log(this.name) }作为objde方法getName被调用,所以this指向调用对象,即obj,所以this.name就是obj.name。
第三种
function Cat(name){
this.name = name
}
var cat1 = new Cat("小黄")
console.log(cat1.name) //小黄
当Cat函数被运用关键字new调用时,就是被当做构造器调用的,这时会发生:
1.创建一个空对象{ }
2.让this指向这个空对象,那么这个空对象将被增加一个name属性,并且赋值为“小黄”,即{name:"小黄"}
3.最后让cat1指向这个对象,即cat1={name:"小黄"}
4.所以cat1.name值为“小黄”
这种方式this指向的是对象的实例。
第四种
每个函数都有call()或apply()方法,可以运用他们来强制改变this的指向,语法为:函数名.call(指向对象,参数)。比如下面我们可以限制让fun函数中的this指向对象obj或者fun自己。
var name = "cat"
function fun(){
console.log(this.name)
}
var obj={
name:"pig"
}
fun() //cat
改造后为
var name = "cat"
function fun(){
console.log(this.name)
}
var obj={
name:"pig"
}
fun.call(obj) //pig
fun.call(fun) //fun 因为函数都有name属性,函数fun的name就是fun
再看下面的实际例子,或许会更加清楚:
document.getElementById("div").onclick=function(){
console.log(this) //div的DOM对象
function fun(){
console.log(this) //window
}
fun()
}
上面这个例子其实就是第一种和第二种的结合,首先div被点击后,回调函数将被执行,其实在内部这个函数被赋值给了div对象的onclick属性,这就对应第二种,函数被当做对象的方法被调用,所以内部的this执行div对象。 但是其内部又还有一个内部函数fun,它被当做普通函数调用,对应第一种,所以this指向window,但我们有时还想让这时的this指向div对象,可以有两种改造方式,that=this和call或者apply:
document.getElementById("div").onclick=function(){
console.log(this) //div的DOM对象
var that = this
function fun(){
console.log(that) //div的DOM对象
}
fun()
}
document.getElementById("div").onclick=function(){
console.log(this) //div的DOM对象
function fun(){
console.log(this) //div的DOM对象
}
fun.call(this)
}
call和apply
call和apply的作用
1. 如上面所述,call和apply可以用来强制改变this指向
2. 用来借用其他对象的方法
在讲第2个作用之前先来看看call和apply的区别,它们的作用是一样的,唯一区别就在于参数的传递形式。
call传入的参数个数不固定,第一个参数是this的强制指向对象,第二个参数开始往后就是作为参数传给函数:
var fun=function(a,b,c){
console.log([a,b,c])
}
fun.call(null,1,2,3) // [1,2,3]
而apply的参数就是两个,第一个与call一样代表this的强制指向对象,第二个可以为数组,也可以为伪数组arguments:
var fun=function(a,b,c){
console.log([a,b,c])
}
fun.apply(null,[1,2,3]) // [1,2,3]
为什么我们两次传的参数不同,call传1,2,3, apply传[1,2,3],却输出相同的结果,这是因为js函数内部的实现运用了arguments,当运用call时,即为正常情况,函数内部让第一个参数对应arguments[0],第二个参数对应arguments[1],以此类推.......,当运用apply时,函数内部直接让arguments等于数组[1,2,3]。
Math.max()方法用来获取几个数中的最大值,如Math.max(1,2,3)==3,但是不能用于获取数组中的最大值,所以可以利用apply来将这个方法运用于数组:
function getMax(array){
return Math.max.apply(null,array)
}
getMax([1,2,3]) // 3
现在再来看看call和apply的第二个作用:借用别人的方法。 我们想让一个空对象{ }也有数组的push方法,实现如下:
function fnn(){
var obj={}
Array.prototype.push.apply(obj,arguments)
console.log(obj)
}
fnn(1,2,3)
apply和call可以借用别人的方法的秘密就在于:函数内部运用了大量的this和arguments。正常情况下push的用法为
var arr=[ ]
arr.push(1);
push对应的函数,作为方法被空数组arr调用(第二种调用),所以其内部的this指向arr,但是call和apply却可以改变this指向,使得this指向obj,那么此后,arguments[0]将被赋值给obj[0],而不是arr[0],而arguments[1]将被赋值给obj[1],而不是arr[1],以此类推..........以此达到借用的目的。