Heim > Artikel > Web-Frontend > Elegante Verwendung von This in js
Dieses Mal werde ich Ihnen die elegante Verwendung von This in js vorstellen. Was sind die Vorsichtsmaßnahmen für die elegante Verwendung von This in js?
Wenn eine Funktion aufgerufen wird, wird ein Aktivitätsdatensatz (Ausführungskontext) erstellt.
Dieser Datensatz enthält Informationen wie den Ort, an dem die Funktion aufgerufen wurde (Aufrufliste), die Aufrufmethode der Funktion, die übergebenen Parameter usw.
Dies ist eines der aufgezeichneten Attribute und wird während der Funktionsausführung verwendet.
Dies weist weder auf die Funktion selbst noch auf den Umfang der Funktion hin.
Dies ist eigentlich eine Bindung, die auftritt, wenn die Funktion aufgerufen wird, und worauf sie verweist, hängt vollständig davon ab, wo die Funktion aufgerufen wird.
Wenn im strikten Modus eine allgemeine Funktion aufgerufen wird, zeigt dies auf undefiniert.
1. Warum dies verwenden?
Dies bietet eine elegantere Möglichkeit, einen Verweis auf ein Objekt implizit zu „übergeben“, sodass die API prägnanter und einfacher zu reproduzieren ist .
zB:
var me = { name: "fenfei" }; //不使用this,调用 function speak(name){ console.log("Hello, I'm "+ name); } speak(me.name); //Hello, I'm fenfei //使用this,调用 function speak(){ console.log("Hello, I'm "+ this.name); } speak.call(me); //Hello, I'm fenfei
2. Zwei Missverständnisse dazu
(1) Dies weist auf die Funktion selbst hin
(2) Dies Zeigt auf den Umfang der Funktion.
Auf den Bereich kann nicht über JavaScript-Code zugegriffen werden, er existiert innerhalb der JavaScript-Engine. Wenn Sie dies mit Suchvorgängen mit lexikalischem Gültigkeitsbereich kombinieren, denken Sie daran, dass dies unmöglich ist!
Dies ist zur Laufzeit gebunden, nicht zum Zeitpunkt des Schreibens. Sein Kontext hängt von verschiedenen Bedingungen ab, wenn die Funktion aufgerufen wird. Die Bindung davon hat nichts mit dem Speicherort der Funktionsdeklaration zu tun, sondern hängt nur vom aufrufenden Speicherort der Funktion ab (dh davon, wie die Funktion aufgerufen wird)!
3. Bindungsregeln
1) Standardbindung
Der am häufigsten verwendete Funktionsaufruftyp: unabhängiger Funktionsaufruf. Stellen Sie sich diese Regel als Standardregel vor, wenn keine anderen Regeln angewendet werden können.
zB:
function foo() { console.log(this.a); }var a = 2; foo(); // 2
2) Implizite Regeln
Die Regel der impliziten Bindung besteht darin, ob sich am aufrufenden Ort ein Kontextobjekt befindet oder ob es Eigentum eines Objekts ist oder von diesem eingebunden wird.
function foo() { console.log(this.a); }var obj = { a: 2, foo: foo }; obj.foo(); // 2
. Wenn foo() aufgerufen wird, ist this an obj gebunden, sodass this.a und obj.a gleich sind.
Aber manchmal kommt es zu impliziten Verlusten.
function foo() { console.log(this.a); }var obj = { a: 2, foo: foo };var bar = obj.foo; // 函数 var a = "oops, global"; //bar(); // "oops, global"
. Obwohl bar ein Verweis auf obj.foo ist, bezieht er sich tatsächlich auf die foo-Funktion selbst.
bar() ist also derzeit tatsächlich ein Funktionsaufruf ohne jegliche Änderung, mit angewendeter Standardbindung.
3) Verbindlich anzeigen
anrufen und bewerben
. In JavaScript sind call und apply wie die Eltern von this. Sie müssen dort leben, wo dies lebt, und sie müssen gehorchen! Wenn keine Parameter vorhanden sind, ist das aktuelle Objekt Fenster
z. B.:
var name="全局";var xpg={ name:"局部"};function getName(){ alert(this.name); } getName(xpg);//全局getName.call(xpg);//局部getName.call();//全局
. Unter anderem befindet sich dies in der Funktion getName. Unabhängig davon, wo sich dies befindet, müssen Sie den Speicherort finden, wenn die Funktion ausgeführt wird. Zu diesem Zeitpunkt ist die Position der Funktion getName, wenn sie ausgeführt wird, für
(1) getName(xpg);//global
Offensichtlich ist das Objekt, in dem sich die Funktion getName befindet, das Fenster, also die Heimat von Dies muss sich im Fenster befinden, d. h. auf Fensterobjekt zeigen, dann ist dieser von getName zurückgegebene Name tatsächlich Fenstername, sodass die Warnung als „global“ ausgegeben wird!
(2) getName.call(xpg);//Teilweise
. Unter diesen gibt der Aufruf an, dass die Heimat davon das xpg-Objekt ist, da dieses nur in xpg festgelegt werden muss. Dann zeigt dies zu diesem Zeitpunkt auf das xpg-Objekt, und this.name ist tatsächlich xpg.name, sodass die Warnung ausgegeben wird als „lokal“ !
bind()
. Die Bindungsmethode wird ab ES5 bereitgestellt, daher unterstützt ie9+ nur
zB:
function f(){ return this.a; } var g = f.bind({a : "test"}); //想把某个对象作为this的时候,就把它传进去,得到一个新对象gconsole.log(g()); // test //重复调用的时候,this已经指向bind参数。 //这对于我们绑定一次需要重复调用依然实现绑定的话,会比apply和call更加高效(看下面这个例子)var o = {a : 37, f : f, g : g};
console.log(o.f(), o.g()); // 37, test //o.f() besteht die Objekt Attributaufruf, dies zeigt auf Objekt o; //Das Besondere ist, dass //o.g() auch dann der vorherigen Bindung folgt, wenn wir die neu gebundene Methode als Attribut des Objekts aufrufen, sodass die Antwort test lautet nicht g
4) neue Bindung
neu, diese Bindung kann nicht verändert werden!
Die neue Aufruffunktion führt automatisch die folgenden Vorgänge aus:
(1) Erstellen (oder Konstruieren) eines brandneuen Objekts
(2) Dieses neue Objekt wird ausgeführt [[Prototyp]] Verbindung ;
(3) Dieses neue Objekt wird an diesen des Funktionsaufrufs gebunden. (4) Wenn die Funktion keine anderen Objekte zurückgibt, gibt der Funktionsaufruf im neuen Ausdruck automatisch dieses neue Objekt zurück .
zB:
function Person(name,age) { this.name = name this.age = age console.log("我也只不过是个普通函数") } Person("zxt",22) // "我也只不过是个普通函数"console.log(name) // "zxt"console.log(age) // 22var zxt = new Person("zxt",22) // "我也只不过是个普通函数"console.log(zxt.name) // "zxt"console.log(zxt.age) // 22Im obigen Beispiel wird zunächst eine Person-Funktion definiert, die entweder normal oder in Form eines
Konstruktors aufgerufen werden kann. . Bei normalem Aufruf wird sie als normale Funktion ausgeführt und eine Zeichenfolge ausgegeben.
. Wenn es einem neuen Operator übergeben wird, wird ein neues Objekt erstellt.
. Bei einem normalen Aufruf werden, wie bereits erwähnt, die Standardbindungsregeln angewendet und an das globale Objekt gebunden. Zu diesem Zeitpunkt werden zwei Attribute, Name und Alter, zum globalen Objekt hinzugefügt.
. Wenn die Funktion über den neuen Operator aufgerufen wird, gibt sie ein Objekt zurück. Aus dem Ausgabeergebnis ist ersichtlich, dass dieses Objekt an das zurückgegebene Objekt gebunden ist.
了解了函数调用中this绑定的四条规则,需要做的就是找到函数的调用位置并判断对应哪条规则。
(1)函数是否是new绑定?如果是,this绑定的是新创建的对象。
var bar = new Foo();
(2)函数是否通过call、apply显示绑定或硬绑定?如果是,this绑定的是指定的对象。
var bar = foo.call(obj);
(3)函数是否在某个上下文对象中隐式调用?如果是,this绑定的是那个上下文对象。
var bar = obj.foo();
(4)上述全不是,则使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局window对象。
var bar = foo();
new绑定和call、apply无法一起使用,因此不能使用new foo.call(obj).
五、this绑定例外
1)被忽略的绑定
如果你把null或者undefined作为this的绑定对象传入call、apply或者bind。
这些值在调用时会被忽略,实际应用的是默认绑定规则。
eg:
function foo() { console.log(this.a); }var a = 2; foo.call(null); // 2
2)间接引用
eg:
function foo() { console.log(this.a); }var a = 2; var o = { a: 3, foo: foo }; var p = { a: 4 }; o.foo(); // 3(p.foo = o.foo)(); // 2
赋值表达式p.foo = o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或者o.foo()。
3)当前对象不明确时的this
当没有明确的执行时的当前对象时,this指向全局对象window。
例如对于全局变量引用的函数上我们有:
var name = "Tom";var Bob = { name: "Bob", show: function(){ alert(this.name); } }var show = Bob.show; show(); //Tom
。你可能也能理解成show是window对象下的方法,所以执行时的当前对象时window。但局部变量引用的函数上,却无法这么解释:
var name = "window";var Bob = { name: "Bob", showName: function(){ alert(this.name); } };var Tom = { name: "Tom", showName: function(){ var fun = Bob.showName; fun(); } }; Tom.showName(); //window
4)在浏览器中setTimeout、setInterval和匿名函数执行时的当前对象是全局对象window:
var name = "Bob"; var nameObj ={ name : "Tom", showName : function(){ alert(this.name); }, waitShowName : function(){ setTimeout(this.showName, 1000); } }; nameObj.waitShowName();
5)软绑定
eg:
var count=2;var obj={ count:0, cool:function coolFn(){ console.log(this.count);//0 var self=this; if(self.count<1){ setTimeout(function timer(){ self.count++; console.log("awesome?"); console.log(self.count);//1 console.log(this.count);//2 },100); } } }; obj.cool();
6)dom事件中的this
(1)直接在dom元素中使用
1eb9ebab541c78a07af4b7a6c86d652c
分析:对于dom元素的一个onclick(或其他如onblur等)属性,它为所属的html元素所拥有,直接在它触发的函数里写this,this应该指向该html元素。
(2)给dom元素注册js函数
a、不正确的方式
<script type="text/javascript"> function thisTest(){ alert(this.value); // 弹出undefined, this在这里指向??}</script><input id="btnTest" type="button" value="提交" onclick="thisTest()" />
。分析:onclick事件直接调用thisTest函数,程序就会弹出undefined。
因为thisTest函数是在window对象中定义的, 所以thisTest的拥有者(作用域)是window,thisTest的this也是window。而window是没有value属性的,所以就报错了。
b、正确的方式
<input id="btnTest" type="button" value="提交" /><script type="text/javascript"> function thisTest(){ alert(this.value); }document.getElementById("btnTest").onclick=thisTest; //给button的onclick事件注册一个函数</script>
。分析:在前面的示例中,thisTest函数定义在全局作用域(这里就是window对象),所以this指代的是当前的window对象。
而通过document.getElementById(“btnTest”).onclick=thisTest;这样的形式,其实是将btnTest的onclick属性设置为thisTest函数的一个副本,在btnTest的onclick属性的函数作用域内,this归btnTest所有,this也就指向了btnTest。
因为多个不同的HTML元素虽然创建了不同的函数副本,但每个副本的拥有者都是相对应的HTML元素,各自的this也都指向它们的拥有者,不会造成混乱。
eg:
<input id="btnTest1" type="button" value="提交1" onclick="thisTest()" /><input id="btnTest2" type="button" value="提交2" /><script type="text/javascript">function thisTest(){this.value="提交中"; }var btn=document.getElementById("btnTest1"); alert(btn.onclick); //第一个按钮函数var btnOther=document.getElementById("btnTest2"); btnOther.onclick=thisTest; alert(btnOther.onclick); //第二个按钮函数</script>
其弹出的结果是:
//第一个按钮function onclick(){ thisTest() }//第二个按钮function thisTest(){ this.value="提交中"; }
7)this词法(ES6:箭头函数)
箭头函数不使用function关键字定义,而是使用“胖箭头”的操作符=>定义;箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。
eg:
function foo(){ return (a)=>{ //this继承自foo console.log(this.a); }; }var obj1={ a:2}var obj2={ a:3}var bar=foo.call(obj1); bar.call(obj2);//2不是3!
foo()内部创建的箭头函数会捕获调用时foo()的this。由于foo()的this被绑定到obj1,bar(引用箭头函数)的this也被绑定到obj1,而箭头函数的绑定无法修改。(new的也不能!)
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Das obige ist der detaillierte Inhalt vonElegante Verwendung von This in js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!