人生就像一列開往墳墓的列車,路途上會有很多站,很難有人至始至終陪你走完全程,當陪你的人要下車時,即便不舍,也要心存感激,然后揮手告別。---sunnyhuang
在es5很多新手可能對于this感覺到很迷惑,看見有些大神對this靈活運用,心里很是羨慕,不要緊,這篇文章讓你徹底明白什么是this
函數(shù)的四種調用
- func(p1,p2) 直接調用
- obj.child.method(p1,p2) 對象的方法調用
- func.call(null,p1,p2) 通過call調用
- func.apply(null,[p1,p2]) 通過apply調用
我們一般都使用的是第一種和第二種調用,但是正規(guī)的函數(shù)調用是第三種和第四種。
func.call(context,p1,p2) this就是這個context的值,后面的是傳入的參數(shù),在不嚴格模式下,context等于null或undefined的時候會自動指向為window對象,同時值為原始值(數(shù)字,字符串,布爾值)的 this 會指向該原始值的自動包裝對象。
面試題運用
你可能遇到過這樣的題目
var obj={
sum: function(){
console.log(this)
}
}
var bar=obj.sum;
obj.sum() //輸出的是obj
bar() //輸出的確實window
我們不通過第一種或者第二種調用函數(shù),通過第三種來調用函數(shù)上述代碼的變換
obj.sum() --->obj.sum.call(obj) //obj就是context
bar() ---->bar.call(undefined) 可以簡寫bar.call() //window就是context
數(shù)組的運用
猜猜如果數(shù)組中的元素調用函數(shù),this指向誰呢?
function fn(){console.log(this)}
function fn1(){console.log(this+"fn2")}
var arr=[fn,fn1]
arr[0]() >---你可以意淫成arr.0.call(arr)
小試牛刀
var a = {
name:"zhang",
sayName:function(){
console.log("this.name="+this.name);
}
};
var name = "ling";
function sayName(){
var sss = a.sayName;
sss(); //this.name = ? >--sss.call(undefined) window.name
a.sayName(); //this.name = ? >--a.sayname.call(a) a.name
(a.sayName)(); //this.name = ? >--只是對于a進行了一層包裝,a.sayname.call(a) a.name
(b = a.sayName)();//this.name = ? >--先進行b的復制,然后再執(zhí)行 b() b.call() window.name
}
sayName();
// ling
// zhang
// zhang
// ling
變形
var name = "ling";
function sayName(){
var a = {
name:"zhang",
sayName:getName
};
function getName(){
console.log(this.name);
}
getName(); //this.name = ? >--getName.call() window.name
a.sayName(); //this.name = ? >--a.sayName.call(a) a.name
getName.call(a);//this.name = ? 它直接轉換了,所以是a.name
}
sayName();
//ling
// zhang
//zhang
繼續(xù)變形,我看你能翻出天
var name = "ling";
var obj = {
name:"zhang",
sayName:function(){
console.log("this.name="+this.name);
},
callback:function(){
var that = this; //2. 所以這里的this值是obj that=this
return function(){
var sayName = that.sayName; //3. 這里就相當于是obj.sayName
that.sayName(); //this.name = ? //4. obj.sayName.call(obj) obj.name
sayName();//this.name = ? // sayName.call() window.name
}
}
}
obj.callback()() //1. 首先里面有一個this被復制給that 先轉換這個obj.callback.call(obj)()
// zhang
//ling
讓我們更加加深轉換代碼
- fun()
- obj.child.call(obj)
- arr.push(1)
- arr.push.call(arr,3)
- obj1.obj2.sum()
仰天抬頭看看世界,思考1分鐘人生,然后看題
1. fun.call()
2. obj.child()
3. arr.push.call(arr,1) //記住1是參數(shù)
4. arr.push(3)
5. obj1.obj2.sum.call(obj2)
挑戰(zhàn)升級
理解Array的原型調用
如果你是一個看mdn的小baby,就會在數(shù)組上面經(jīng)??吹紸rray函數(shù)的原型上面調用函數(shù)實現(xiàn)某種效果
1. 在es5的時候實現(xiàn)一個數(shù)組push另一個數(shù)組
var arr1=[1,2,3],arr2=[4,5,6]
Array.prototype.push.apply(arr1,arr2) //arr1=[1,2,3,4,5,6]
剛開始,由于自己沒有開發(fā)過api,我也不是怎么理解這個的原理,下面我來分解一下
- 如果我想給arr1后面添加一個數(shù)據(jù)
arr1.push(1) - 用我們剛剛的進行轉換
arr1.push.call(arr,1)>--變成applyarr1.push.apply(arr1,[1]) - 我們把[1]變成arr2
arr1.push.apply(arr1,arr2) - 由于數(shù)組的提供的api,不可能每一個都是arr1,所以統(tǒng)一調用
Array.prototype。我們把arr1換成Array.prototype
試試理解 Math.max.apply(null,[1,2,3])
ES6的擴展語句
arr1.push(...arr2)
Math.max(...arr1)