ホームページ  >  記事  >  ウェブフロントエンド  >  js での This のエレガントな使用法

js での This のエレガントな使用法

php中世界最好的语言
php中世界最好的语言オリジナル
2018-06-04 10:05:101407ブラウズ

今回は js での This のエレガントな使い方をお届けします。 js で This をエレガントに使うための 注意事項 は何ですか? 以下は実際的なケースです。

関数が呼び出されると、アクティビティレコード (実行コンテキスト) が作成されます。


このレコードには、関数が呼び出された場所 (コールスタック)、関数の呼び出しメソッド、渡されたパラメーターなどの情報が含まれます。

これは記録される属性の 1 つであり、関数の実行中に使用されます。

これは関数自体を指すものでも、関数のスコープを指すものでもありません。

これは実際には関数が呼び出されたときに発生するバインディングであり、それが何を指すかは関数が呼び出される場所によって完全に異なります。

厳密モードでは、関数が呼び出されるとき、これは未定義を指します。

1. これを使用する理由

これは、オブジェクトへの参照を暗黙的に「渡す」ためのより洗練された方法を提供するため、API をより簡潔で再利用しやすいように設計できます。

例:

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. これに関する 2 つの誤解

(1) これは関数自体を指します

(2) これは関数のスコープを指します。

スコープは JavaScript コードを通じてアクセスできません。スコープは JavaScript エンジン内に存在します。これを語彙スコープの検索と組み合わせるときは、これは不可能であることを必ず思い出してください。

これは、書き込み時ではなく、実行時にバインドされます。そのコンテキストは、関数が呼び出されるときのさまざまな条件によって異なります。 this のバインディングは関数宣言の場所とは関係がなく、関数の呼び出し場所 (つまり、関数の呼び出し方法) にのみ依存します。

3. バインディング ルール

1) デフォルト バインディング

最も一般的に使用される関数呼び出しタイプ: 独立した関数呼び出し。このルールは、他のルールを適用できない場合のデフォルトのルールであると考えてください。

例:

function foo() {  console.log(this.a);
}var a = 2;
foo(); // 2

2) 暗黙のルール

暗黙のバインディングのルールは、呼び出し元の場所にコンテキスト オブジェクトがあるかどうか、またはオブジェクトが所有しているかオブジェクトに含まれているかどうかです。

りー

。 foo() が呼び出されると、this は obj にバインドされるため、this.a と obj.a は同じになります。

しかし、暗黙の損失が発生する場合もあります。

りー

。 bar は obj.foo への参照ですが、実際には foo 関数自体を指します。

この時点の bar() は、実際には何も変更せずに、デフォルトのバインディングが適用された関数呼び出しです。
3) バインディングを表示

呼び出して適用

します。 JavaScript では、call と apply はこの親のようなもので、この親はどこに住んでいても従わなければなりません。パラメータがない場合、現在のオブジェクトは window
例:

function foo() {  console.log(this.a);
}var obj = {    a: 2,    foo: foo
};
obj.foo(); // 2

です。その中で、これは関数 getName にあります。これがどこにあっても、関数の実行中にその場所を見つける必要があります。このとき、関数 getName の実行時の位置は、

(1) getName(xpg);//Global
明らかに、関数 getName が配置されているオブジェクトは window なので、このホームは次の場所にある必要があります。ウィンドウ、つまり
window オブジェクト を指している場合、getName によって返される this.name は実際には window.name であるため、アラートは「グローバル」として出力されます。 (2) getName.call(xpg);//部分的
.このうち、callはthisのホームがxpgオブジェクトであることを指定しているため、thisはxpgのみに強制的に定着するので、このときthis.nameがxpgオブジェクトを指しており、実際にはthis.nameがxpg.nameなのでアラートが出ます。 「ローカル」として!

バインド()

。バインド メソッドは es5 以降で提供されるため、ie9 以降でのみサポートされます。例:

function foo() {  console.log(this.a);
}var obj = {    a: 2,    foo: foo
};var bar = obj.foo; // 函数  var a = "oops, global"; //bar(); // "oops, global"

console.log(o.f(), o.g()); // 37、test //o.f() はプロパティを通じて呼び出されます。オブジェクトの、これはオブジェクトを指します o;//特別なのは、オブジェクトの属性として新しくバインドされたメソッドを呼び出したとしても、 //o.g() は依然として以前のバインディングに従うため、答えは次のとおりです。 test は g


ではありません 4) 新しいバインディング

new のこのバインディングは変更できません。

新しい呼び出し関数は次の操作を自動的に実行します:

(1) 新しいオブジェクトを作成 (または構築)

(2) この新しいオブジェクトは [[Prototype]] を実行することで接続されます。 object は関数呼び出しの this にバインドされます。
(4) 関数が他のオブジェクトを返さない場合、新しい式の関数呼び出しは自動的にこの新しいオブジェクトを返します。
例:

var name="全局";var xpg={    name:"局部"};function getName(){
    alert(this.name);
}
getName(xpg);//全局getName.call(xpg);//局部getName.call();//全局

上記の例では、まず Person 関数が定義されており、これは通常どおりに呼び出すことも、
コンストラクター

の形式で呼び出すこともできます。

。通常に呼び出すと通常の関数として実行され、文字列が出力されます。 。新しい演算子を介して渡されると、新しいオブジェクトが構築されます。 。通常の呼び出しを行う場合、前述したように、デフォルトのバインド ルールが適用され、これがグローバル オブジェクトにバインドされます。このとき、name と age の 2 つの属性がグローバル オブジェクトに追加されます。
。 new 演算子を介して呼び出された場合、関数はオブジェクトを返します。出力結果から、このオブジェクトが返されたオブジェクトにバインドされていることがわかります。

したがって、いわゆる new バインディングとは、new 演算子を介して関数が呼び出されるときに、新しいオブジェクトが生成され、コンストラクター内の this がこのオブジェクトにバインドされることを意味します。

4. 優先順位

new binding > callapply など。 Display binding > Implicit binding > Default binding。

了解了函数调用中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中文网其它相关文章!

推荐阅读:

怎样利用JS做出引用传递与值传递

使用JS实做出加密解密操作

以上がjs での This のエレガントな使用法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。