最近的文章基本都是總結javascript基礎內容的,因為我覺得這些東西很重要。而且很多時候你覺得你理解了,其實並沒有你自認為的那麼理解。十月份沒怎麼寫文章,因為國慶出去玩的比較久,心變野了,現在是時候重新回到學習的軌跡了,今天要總結的是javascript中的this.
介紹this之前,先來兩句話,這兩句話比較重要,可以說貫穿全文。
1、this的最終指向的是那個調用它的對象
2、如果一個函數中包含多個對象,儘管這個函數是被最外層的對象所調用,this指向的也只是它上一級的對象
下面通過一些代碼示例來講解this
1、window中的this
demo1
function test1(){
this.x = 1;
console.log(this.x);
}
test1(); // 1
function test2(){
var y = 2;
console.log(this.y); //undefined
console.log(this); //Window
}
test2();
上面的兩個例子中,都是屬於屬於全局性調用,因此this就代表全局對象。也就是為什麼test2打印出來的this.y會是undefined,因為this指向了 window.
2、在對象中使用this
demo2
var x=0;
var obj={
x:1,
fn:function(){
console.log(this.x);
}
}
obj.fn(); // 1
這裡的this指向對象obj,因為調用的fn是通過obj.fn()執行的。
不過這裡有個注意點,就是this的指向在函數創建的時候是決定不了的,在調用的時候才能決定,誰調用的就指向誰,這個是比較重要的一點。為了驗證這句話,稍微改造一下上面的demo2
demo3
var x=0;
var obj={
x:1,
fn:function(){
console.log(this.x);
}
}
obj.fn(); // 1 跟上面的代碼一樣
// 修改了這裡
var obj2=obj.fn;
obj2(); //0
demo3中和demo2的不同之處在於,沒有直接調用obj裡面的fn函數,而是將其賦值給obj2,最終通過obj2來調用fn函數。
而obj2屬於全局變量,因為fn裡面的this指向了 window。這個也驗證了上面那句話: this的指向在函數創建的時候是決定不了的,在調用的時候才能決定,誰調用的就指向誰
demo4
var obj = {
x:1,
y:{
fn:function(){
console.log(this.x); //undefined
}
}
}
obj.y.fn();
如果一個對象中又包含有其他對象,this僅僅會指向它的上一級對象。 就像demo4中,fn裡面調用this.x,這個this只會指向fn的上一級對象y。y中沒有x這個變量,所以返回的是undefined。
稍微改造一下demo4,再次來驗證一下:this的指向在函數創建的時候是決定不了的,在調用的時候才能決定,誰調用的就指向誰
demo5
var obj = {
x:1,
y:{
x:2,
fn:function(){
console.log(this.x); //undefined
}
}
}
var obj2=obj.y.fn;
obj2(); // 因為此時fn中的this指向了window
3、在構造函數中使用this
demo6
function Fn(){
this.x=1;
}
var myFn=new Fn();
console.log(myFn.x); //1
如果函數傾向於和 new 關鍵詞一塊使用,則我們稱這個函數是構造函數, 在函數內部,this 指向新創建的對象。也就是說,這個this不是指向函數Fn,而是指向它的實例 myFn。
4、call和apply,改變this指向(這裡順便把call和apply給介紹了)
在 javascript 中,call 和 apply 都是為了改變某個函數運行時的上下文(context)而存在的,也就是說,是為了改變函數體內部 this 的指向。
call和apply的區別就在於傳遞方式的不同,call在接收指定參數的形式是 someMethod.call(obj, arg1, arg2);
而apply在接收指定參數時的形式是 someMethod.apply(obj, [arg1, arg2]).或者someMethod.apply(obj, arg1),但是這個arg1必須是一個類數組對象
demo7
var personA = {
name: 'kobe',
sayName: function (hobby){
console.log(this.name + ' likes ' + hobby);
}
};
personA.sayName('basketball'); // 'kobe likes basketball'
var personB = {
name: 'James'
}
personA.sayName.call(personB, 'basketball'); // 'James likes basketball'
personA.sayName.apply(personB, ['basketball']); // 'James likes basketball'
personA.sayName('basketball'); 這段代碼中,調用sayName()這個方法的對象是personA,因此sayName()內部的this指向就是personA對象。 personA.sayName.call(personB, 'basketball'); 本來sayName方法的this指向是personA對象,但是調用call/apply後,this對象指向了personB對象。
也可以這麼理解,personA.sayName.call(personB, 'basketball')其實就是 personB.sayName(『basketball');
demo8
function PersonA(name,hobby) {
this.name = name,
this.hobby = hobby,
this.say = function() {
console.log(name +" likes " + this.hobby + '.');
}
}
function PersonB(name,hobby) {
PersonA.call(this,name,hobby);
}
var Fn=new PersonB('James','basketball');
Fn.say(); // James likes basketball.
雖然我們沒有在PersonB 對象裡添加任何屬性和方法,但是我們使用call() 繼承了原本屬於PersonA 的屬性和方法。就可以做到 PersonA 函數所有能做到的事情。
這裡額外再穿插一下appy的使用一些場景
apply應用場景1:數組合併
var list1 = [0,1,2];
var list2 = [3,4,5];
[].push.apply(list1,list2);
//或者 Array.prototype.push.apply(list1, list2);
console.log(list1);// [0,1,2,3,4,5]
apply應用場景2:獲取數組中的最大值或者最小值
var arr = [0,1,2,15,6];
var getMax=Math.max.apply(this,arr);
console.log(getMax); //15
5、使用this的注意點
這裡主要介紹 setTimeout或者setInterval中使用this的注意點
demo9
var name='james';
var person={
name:'koBe',
sayName:function(){
setTimeout(function(){
console.log(this.name);
},0);
}
}
person.sayName(); // james
因為setTimeout() 這個異步函數調用的時候,內部的回調函數this 的指向是window.剛好window中有一個 name為 james的標量。所以輸出james.
那如何將setTimeout中的this指向 person呢。兩種方式:
方法一:將this保存在一個變量中
demo10
var name='james';
var person={
name:'koBe',
sayName:function(){
var that=this; //將this存儲在that中。
setTimeout(function(){
console.log(that.name);
},0);
}
}
person.sayName(); // koBe
將this保存在that中,這樣,setTimeout調用this.name就變成了that.name了。
方法二:使用bind
demo11
var name='james';
var person={
name:'koBe',
sayName:function(){
setTimeout(function(){
console.log(this.name);
}.bind(this),0);
}
}
person.sayName(); // koBe
bind 方法,起的作用和call ,apply 一樣,都是改變函數/方法執行時,this 的指向,確保這個函數/方法 運行時this 指向保持一致。
demo11中,通過bind方法將this對象綁定為person。那麼回調函數在執行的時候,this指向還是person。
有誤之處,歡迎指出 如果您覺得文章有用,可以打賞個咖啡錢
|