ホームページ > 記事 > ウェブフロントエンド > js_javascript スキルの this キーワードを理解する
このキーワードは c と java の両方で提供されています。最初に学習し始めると難しいですが、一度理解すると、このキーワードを理解するという記事で js で詳しく説明します。 。
これに関しては、多くのフロントエンド面接で必須の質問ですが、時々インターネットでこれらの質問を見て、自分で試してみました。実際の開発でも、この問題に遭遇します (ただし、一部のクラス ライブラリがこの問題に対処するのに役立ちます)。たとえば、ノックアウトなどのフレームワークを使用する場合、なぜこれを直接使用しないのか理解できないことがあります。ですが、パラメータが渡されるのでこれを使用します。
次に、私の理解と今後の参考のためのメモとしてお話します。間違っているところがあれば、指摘、批判してください。
1. C# とは異なり、これは現在のオブジェクトを指す必要があります。
js の this 点は不確実ですが、動的に変更できることを意味します。 call/apply は、これが指すポイントを変更するために使用される関数です。この設計により、コードがより柔軟で再利用可能になります。
2. これは通常、関数の所有者を指します。
これはとても重要です!これはとても重要です!これはとても重要です!
これは面接でよくある質問でもあり、コードは次のとおりです:
<script type="text/javascript"> var number = 1; var obj = { number: 2, showNumber: function(){ this.number = 3; (function(){ console.log(this.number); })(); console.log(this.number); } }; obj.showNumber(); </script>
showNumber メソッドの所有者は obj なので、this.number=3; これは obj の属性番号を指します。
同様に、2 番目の console.log にも属性番号が出力されます。
2 番目の点で、一般的にこれが関数の所有者を指すとしているのはなぜですか。特別な事情があるからです。関数の自己実行は特殊なケースであり、関数の自己実行では、これはウィンドウを指します。したがって、最初の console.log にはウィンドウの属性番号が出力されます。
そこで、少し追加する必要があります:
3. 関数の自己実行では、これはウィンドウ オブジェクトを指します。
補足ですが、これに関して、もう 1 つややこしいのが、DOM イベントには通常、次の 3 つの状況があるということです。
以下のように:
1. label 属性を使用してイベントを登録します。このとき、これは window オブジェクトを指します。
<input id="test" type="button" value="按钮" onClick="test()"/> function test(){alert(this)}
2. 1 の場合、これを入力に指定するには、これをパラメーターとして渡すことができます。
3. addEventListener などを使用して登録します。このとき、これも入力を指します。
document.getElementById("test").addEventListener("click",test);
オブジェクト指向プログラミング言語では、this キーワードがよく知られています。たとえば、C、C#、Java にはすべてこのキーワードがありますが、学習の初めは難しくても、一度理解すると非常に便利で有意義です。 JavaScript にもこのキーワードはありますが、古典的な OO 言語よりも使用するのがはるかに「混乱」します。
JavaScript でこれを使用するさまざまな方法の何が混乱しているのかを見てみましょう。
1. このキーワードを HTML 要素のイベント属性でインラインで使用します:
// 可以在里面使用this ">division element // 可以在里面使用this ">division element
ここで使用する最も一般的なメソッドは、javascirpt: EventHandler(this) の形式です。ただし、必要に応じて、実際にはここに任意の正当な JavaScript ステートメントを記述することができます (ただし、これは内部クラスになります)。ここでの原則は、スクリプト エンジンが div インスタンス オブジェクトの匿名メンバー メソッドを生成し、onclick がこのメソッドを指すということです。
2. DOM メソッドを使用して、イベント処理関数でこのキーワードを使用します:
division element var div = document.getElementById('elmtDiv'); div.attachEvent('onclick', EventHandler); function EventHandler() { // 在此使用this } // --> division element var div = document.getElementById('elmtDiv'); div.attachEvent('onclick', EventHandler); function EventHandler() { // 在此使用this } // -->
このとき、EventHandler() メソッドの this キーワードは、オブジェクトが IE ウィンドウ オブジェクトであることを示します。これは、EventHandler が単なる通常の関数であるため、attachEvent の後のスクリプト エンジンの呼び出しは div オブジェクト自体とは何の関係もありません。同時に、EventHandler の caller 属性 (null に等しい) を確認できます。このメソッドで div オブジェクト参照を取得したい場合は、this.event.srcElement を使用する必要があります。
3. DHTML を使用して、イベント処理関数でこのキーワードを使用します:
division element lt;mce:script language="javascript"> var div = document.getElementById('elmtDiv'); div.onclick = function() { // 在此使用this }; / --> division element var div = document.getElementById('elmtDiv'); div.onclick = function() { // 在此使用this }; // -->
ここで this キーワードで示される内容は、div 要素のオブジェクトのインスタンスです。スクリプト内で DHTML を使用して、div.onclick に直接 EventHandler メソッドを割り当てることは、div オブジェクトのインスタンスにメンバー メソッドを追加することと同じです。このメソッドと最初のメソッドの違いは、最初のメソッドは HTML メソッドを使用するのに対し、後者のスクリプト解析エンジンは匿名メソッドを生成しなくなることです。
4. クラス定義で次のキーワードを使用します:
function JSClass() { var myName = 'jsclass'; this.m_Name = 'JSClass'; } JSClass.prototype.ToString = function() { alert(myName + ', ' + this.m_Name); }; var jc = new JSClass(); jc.ToString(); function JSClass() { var myName = 'jsclass'; this.m_Name = 'JSClass'; } JSClass.prototype.ToString = function() { alert(myName + ', ' + this.m_Name); }; var jc = new JSClass(); jc.ToString();
这是JavaScript模拟类定义中对this的使用,这个和其它的OO语言中的情况非常的相识。但是这里要求成员属性和方法必须使用this关键字来引用,运行上面的程序会被告知myName未定义。
5、为脚本引擎内部对象添加原形方法中的this关键字:
function.prototype.GetName = function() { var fnName = this.toString(); fnName = fnName.substr(0, fnName.indexOf('(')); fnName = fnName.replace(/^function/, ''); return fnName.replace(/(^\s+)|(\s+$)/g, ''); } function foo(){} alert(foo.GetName()); function.prototype.GetName = function() { var fnName = this.toString(); fnName = fnName.substr(0, fnName.indexOf('(')); fnName = fnName.replace(/^function/, ''); return fnName.replace(/(^\s+)|(\s+$)/g, ''); } function foo(){} alert(foo.GetName());
这里的this指代的是被添加原形的类的实例,和4中类定义有些相似,没有什么太特别的地方。
6、结合2&4,说一个比较迷惑的this关键字使用:
view plaincopy to clipboardprint? function JSClass() { this.m_Text = 'division element'; this.m_Element = document.createElement('DIV'); this.m_Element.innerHTML = this.m_Text; this.m_Element.attachEvent('onclick', this.ToString); } JSClass.prototype.Render = function() { document.body.appendChild(this.m_Element); } JSClass.prototype.ToString = function() { alert(this.m_Text); }; var jc = new JSClass(); jc.Render(); jc.ToString(); function JSClass() { this.m_Text = 'division element'; this.m_Element = document.createElement('DIV'); this.m_Element.innerHTML = this.m_Text; this.m_Element.attachEvent('onclick', this.ToString); } JSClass.prototype.Render = function() { document.body.appendChild(this.m_Element); } JSClass.prototype.ToString = function() { alert(this.m_Text); }; var jc = new JSClass(); jc.Render(); jc.ToString();
我就说说结果,页面运行后会显示:"division element",确定后点击文字"division element",将会显示:"undefined"。
7、CSS的expression表达式中使用this关键字:
height: expression(this.parentElement.height);"> division element height: expression(this.parentElement.height);"> division element
这里的this看作和1中的一样就可以了,它也是指代div元素对象实例本身。
8、函数中的内部函数中使用this关键字:
view plaincopy to clipboardprint? function OuterFoo() { this.Name = 'Outer Name'; function InnerFoo() { var Name = 'Inner Name'; alert(Name + ', ' + this.Name); } return InnerFoo; } OuterFoo()(); function OuterFoo() { this.Name = 'Outer Name'; function InnerFoo() { var Name = 'Inner Name'; alert(Name + ', ' + this.Name); } return InnerFoo; } OuterFoo()();
运行结果显示是:"Inner Name, Outer Name"。按我们在2中的讲解,这里的结果如果是"Inner Name, undefined"似乎更合理些吧?但是正确的结果确实是前者,这是由于JavaScript变量作用域的问题决定的,详细了解推荐参看"原来JScript中的关键字'var'还是有文章的"一文及回复。
归纳起来,JavaScript中的this用法有以下3种(详细用法参原文):
1.在HTML元素事件属性 或 CSS的expression表达式 中inline方式使用this关键字——对应原文的1、7
2.在事件处理函数中使用this关键字——对应原文的2、3
其中可分为两种方式
(1)DOM方式——此种方式的结果是this指向窗口(window)对象
(2)DHTML方式——此种方式的结果是this指向div元素对象实例
3.在类定义中使用this关键字并在其 内部函数 或 成员函数(主要是prototype产生)中使用——对应原文的4、5、8
需要说明的是,在函数也是个对象,因此需要区分 变量定义 和 成员变量定义,如下:
view plaincopy to clipboardprint? var variableName; //变量定义 //作用域:函数定义范围内 //使用方法:直接使用variableName this.varName; //成员变量定义 //作用域:函数对象定义范围内及其成员函数中 //使用方法:this.varName var variableName; //变量定义 //作用域:函数定义范围内 //使用方法:直接使用variableName this.varName; //成员变量定义 //作用域:函数对象定义范围内及其成员函数中 //使用方法:this.varName
以上归纳出的三类this的使用方法中,第一种比较容易理解,这里对原文中第6点提到的程序进行了测试和改进如下,以说明上述后两种使用方法:
view plaincopy to clipboardprint? function JSClass() { var varText = "func variable!"; //函数中的普通变量 this.m_Text = 'func member!'; //函数类的成员变量 this.m_Element = document.createElement('DIV'); //成员变量,创建一个div对象 this.m_Element.innerHTML = varText; //使用函数的普通变量 this.m_Element.attachEvent('onclick', this.ToString); //给这个对象的事件连上处理函数 this.newElement = document.createElement('DIV'); this.newElement.innerHTML = "new element"; this.newElement.m_Text = "new element text!"; //给创建的对象建个成员 this.newElement.onclick = function() { alert(this.m_Text); //指向div对象的成员 }; } JSClass.prototype.Render = function() { document.body.appendChild(this.m_Element); //把div对象挂在窗口上 document.body.appendChild(this.newElement); } JSClass.prototype.ToString = function() { alert(this.m_Text); //指向窗口(window)对象 }; function initialize(){ var jc = new JSClass(); jc.Render(); jc.ToString(); //里面的this指向JSClass类的实例,里面有m_Text成员 } // --> initialize(); // --> function JSClass() { var varText = "func variable!"; //函数中的普通变量 this.m_Text = 'func member!'; //函数类的成员变量 this.m_Element = document.createElement('DIV'); //成员变量,创建一个div对象 this.m_Element.innerHTML = varText; //使用函数的普通变量 this.m_Element.attachEvent('onclick', this.ToString); //给这个对象的事件连上处理函数 this.newElement = document.createElement('DIV'); this.newElement.innerHTML = "new element"; this.newElement.m_Text = "new element text!"; //给创建的对象建个成员 this.newElement.onclick = function() { alert(this.m_Text); //指向div对象的成员 }; } JSClass.prototype.Render = function() { document.body.appendChild(this.m_Element); //把div对象挂在窗口上 document.body.appendChild(this.newElement); } JSClass.prototype.ToString = function() { alert(this.m_Text); //指向窗口(window)对象 }; function initialize(){ var jc = new JSClass(); jc.Render(); jc.ToString(); //里面的this指向JSClass类的实例,里面有m_Text成员 } // --> initialize(); // -->
上面的代码执行结果是:
页面加载时,弹出对话框,输出func member!
页面上显示
func variable! new element
单击func variable时,弹出对话框,显示undefined
——因为这时toString函数里的this指针指向window
单击new element时,弹出对话框显示new element text!
——因为这时toString函数里的this指针指向div元素,而该元素已经定义了m_Text成员(this.newElement.m_Text = "new element text!")