从this指向开始谈谈JavaScript函数的一些内部实现

###** 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],以此类推..........以此达到借用的目的。

转载于:https://my.oschina.net/u/3059741/blog/856636

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值