相信大家在學習JavaScript的時候思劳,this關鍵字總是會讓大家感到很困惑,下面就來給大家詳細的介紹有關this的一些知識點忍捡。
this
在JavaScript中this總是指向一個對象,而具體指向的那個對象是在運行代碼時基于函數(shù)的執(zhí)行環(huán)境動態(tài)綁定的,而不是函數(shù)在聲明時的環(huán)境怀骤。
this的指向問題
在JavaScript中出去特殊的with和eval之外,具體到實際運用中一般包括以下四種情況:
1焕妙、作為對象的方法調用蒋伦;
2、作為普通函數(shù)調用焚鹊;
3痕届、作為構造函數(shù)調用;
4末患、Function.prototype.call和Function.prototype.apply的調用爷抓。
1. 作為對象的方法調用
當一個函數(shù)當作一個對象的方法調用時,this指向該對象
var obj = {
name : 'iFuhang',
getName : function(){
console.log(this); // obj
console.log(this.name); // iFuhang
}
}
obj.getName();
2. 作為普通函數(shù)調用
當一個函數(shù)不被當作對象的方法調用時阻塑,而是當作普通的函數(shù)被調用時蓝撇,此時的this指向全局對象,在瀏覽器中也就是指的window對象陈莽。
window.name = 'smile';
var getName = function(){
var name = 'iFuhang';
return this.name;
}
console.log(getName()); // smile
還有一種情況
window.name = 'smile';
var myObject= {
name : 'iFuhang',
getName : function(){
return this.name;
}
}
var getName = myObject.getName;
console.log(getName());
這種情況下渤昌,雖然getName是myObject.getName()賦值給它的,但是此時的getName仍然是當作普通函數(shù)來調用的走搁,所以此時this還是指向window的独柑。在這種情況下,有的時候會帶給我們一些不必要的麻煩私植,比如下面的示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script>
document.getElementById('app').onclick = function(){
console.log(this.id); // app
var getId = function(){
console.log(this.id); // undefined
}
getId();
}
</script>
</body>
</html>
大家可以看到忌栅,最后getId()函數(shù)中打印出來的是undefined,這個結果我想大家并不意外了曲稼,是的索绪,getId()仍然是作為一個普通函數(shù)的調用。其是我們最后想要的結果是打印出div的id瑞驱,那么要怎樣解決呢娘摔?
其實很簡單,我們可以在執(zhí)行getId()函數(shù)之前唤反,先將div的引用保存起來,然后調用它就可以了。還是來看代碼吧!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script>
document.getElementById('app').onclick = function(){
var self = this; // 提前將this保存起來楞卡,這里的this是指向div的
console.log(this.id); // app
var getId = function(){
console.log(this.id); // app
}
getId();
}
</script>
</body>
</html>
好了,問題解決了,是不是很簡單池摧。其實這里可以還可以通過call方法來改變this的指向创葡,關于call方法的應用我們在后面將會講述。
需要注意的是在ECMAScript5中的嚴格模式下骚露,普通函數(shù)的this指向并不是window了。
function getThis(){
"use strict";
console.log(this); // undefined
}
getThis();
3. 作為構造函數(shù)的調用
構造函數(shù)看起來其實和普通函數(shù)沒啥區(qū)別女嘲,只是在調用方式上不一樣,當使用new運算符調用函數(shù)時菇晃,此時此函數(shù)就稱為構造函數(shù),并且總是返回一個對象缤剧,通常情況下,構造函數(shù)中的this指向返回的這個對象兄纺。
var MyName = function(){
this.name = 'iFuhang';
}
var obj= new MyName();
console.log(obj.name); // iFuhang
使用構造函數(shù)的時候钦奋,需要注意一個問題厌衔,如果構造函數(shù)顯式的返回了一個對象睬隶,此時的this指向的是返回的這個對象了苏潜。如果返回的不是一個對象,就不會存在下面這種情況了变勇。
var MyName = function(){
this.name = 'iFuhang';
return {
name : 'smile';
}
}
var obj= new MyName();
console.log(obj.name); // smile
4. Function.prototype.call和Function.prototype.apply的調用
通過Function.prototype.call和Function.prototype.apply這兩種方法可以動態(tài)的修改this的指向恤左。
var obj1 = {
name : 'iFuhang',
getName : function(){
return this.name;
}
}
var obj2 = {
name : 'smile'
}
console.log(obj1.getName()); // iFuhang
console.log(obj1.getName.call(obj2)); // smile
點擊了解更多關于call和apply的知識點。
以上就是關于this的四種指向問題了搀绣,下面講解一下this丟失的問題飞袋。
this丟失
在開發(fā)中經常會遇到this丟失的問題,就比如下面這個示例:
var obj = {
name : 'iFuhang',
getName : function(){
return this.name;
}
}
console.log(obj.getName()); // iFuhang
var getName = obj.getName();
console.log(getName()); //undefined
出現(xiàn)這種情況的原因其實之前講到過的链患,在調用getName時授嘀,其實時普通函數(shù)的調用方式,所以此時的this指向window锣险,但是window中并沒有name這是屬性蹄皱,所以會返回undefined,如果在嚴格模式下芯肤,則會報錯巷折。再來看看下面這個例子:
一般我們用JavaScript獲取DOM節(jié)點時都會用到document.getElementById等之類的方法,但是為了使用簡單我們一般會封裝一個函數(shù)來簡化操崖咨。
var getId = function(id){
return document.getElementById(id);
}
getId(id);
還有人思考為什么不能使用下面的方法呢锻拘?不是顯得更加簡單些嗎?
var getId = document.getElementById;
getId(id);
此段代碼運行時會拋出一個錯誤击蹲。(Uncaught TypeError: Illegal invocation)
這是因為在許多瀏覽器的引擎中實現(xiàn)document.getElementById時都會用到this署拟,而且this都被期望指向的是document,在getElementById被document調用的時候歌豺,this確實時指向document的推穷,但是當用getId來引用document.getElementById調用時,此時的getId是作為普通函數(shù)調用的类咧,this會指向window馒铃,而不再是document蟹腾。此時我們可以通過apply來改變this指向document。
document.getElementById = (function(func) {
return function(){
return func.apply(document, arguments);
}
})(document.getElementById );
var getId = document.getElementById;
getId(id);
這段代碼中最后執(zhí)行的其實 func.apply(document, arguments)這個函數(shù)区宇,我們將document.getElementById作為參數(shù)傳遞娃殖,也就是func,最后在調用func時议谷,利用apply將this指向了document炉爆,所以最后可以輸出正確結果了。