###** arguments** 废话很少说,直接先看一段最简单的函数:数组
function getSum(a,b,c,d){ return a+b+c+d }
啥意思?教你求和?app
答案就是求和,你没看错。求4个5个数的和还能够这样写,要是10个呢?a+b+c+d+e.....函数
那要是100个呢?完了,字母都不够用了。其实你能够这样写:this
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等。prototype
除了arguments,函数还有个隐式参数,即this。有函数的地方就会有this,this指向的是函数调用的上下文,上下文?啥意思?记得初中高中作语文阅读题最怕的一句话就是:联系上下文理解某句话或某个词语的意思。code
可是若是咱们明白了函数的四种调用方式,对应this有四种指向,就不怕不清楚this的指向了。对象
1. 函数做为普通函数被调用;作用域
2. 函数做为对象的方法被调用;get
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的做用
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],以此类推..........以此达到借用的目的。