ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript 関数における this の 4 つのバインディング形式

JavaScript 関数における this の 4 つのバインディング形式

小云云
小云云オリジナル
2018-02-22 09:30:341692ブラウズ
これに関しては、人々をめまいさせるような抽象的な概念がたくさん出てきますが、ここでは核心部分についてのみ話します - 関数内の this は常にそれを呼び出すオブジェクトを指しており、以下のストーリーはすべて展開します。このあたり。
【ストーリー】ある日、ディスは「ガヴァスケリ」(JavaScript)という異世界にトリップしてしまいました。やるべきことは - 宿泊先を見つける - 関数を呼び出すオブジェクト

このデフォルトバインディング

【ストーリー—— ルート1】 If Dis (this )暗くなる前に受け入れ先が見つからず、アフリカ難民生活を送ろうとしているところに、心優しい魔法使いの村長――窓際の救世主が現れた――まずはうちにお泊りなさい!

【本文】
関数に明確な呼び出しオブジェクトがない場合、つまり、単に独立した関数として呼び出される場合、この関数にはデフォルトのバインディングが使用されます。 window オブジェクト
function fire () {
     console.log(this === window)
}
fire(); // 输出true

上記の例はほとんどの人にとって簡単だと思いますが、例を変更すると混乱する場合があります:
JavaScript 関数における this の 4 つのバインディング形式
function fire () {
  // 我是被定义在函数内部的函数哦!     function innerFire() {
  console.log(this === window)
      }
     innerFire(); // 独立函数调用}
fire(); // 输出true
JavaScript 関数における this の 4 つのバインディング形式

関数 innerFire は外部関数 fire で宣言されて呼び出されますが、その this ポイントは誰を指すのでしょうか? まだウィンドウです
多くの人は、innerFire に対する fire 関数のスコープの影響を心配しているかもしれませんが、必要なのは理論上の武器を手に入れることだけです。明示的な呼び出しオブジェクトがない場合、この関数にはデフォルトのバインディングが使用されます。 : グローバルウィンドウオブジェクトにバインドして正解を取得します
以下の例の拡張版でもtrueが出力されます
JavaScript 関数における this の 4 つのバインディング形式
var obj = {
   fire: function () {
       function innerFire() {
          console.log(this === window)
        }
        innerFire();   // 独立函数调用     }
}
obj.fire(); //输出 true
JavaScript 関数における this の 4 つのバインディング形式

【注意】 この例では、 obj.fire() の呼び出しは、実際には this の暗黙的なバインディングを使用します。これについては、次に説明します
[概要] すべての関数は、どこであっても独立しています。が配置され、グローバル環境で直接呼び出すのと同じように動作します

この暗黙のバインディング

【ストーリー - ルート 2】 ディス (これ) が異世界「ガバスケリ」に旅行したとき (JavaScript )、彼はたまたまお金を持っていたので、泊まるホテルを見つけました

関数がオブジェクトに「含まれている」とき、関数の this が暗黙的に this にバインドされていると言います。現時点では、以下のプロパティなど、バインドされたオブジェクト内の他のプロパティに直接アクセスできます
JavaScript 関数における this の 4 つのバインディング形式
var obj = {
     a: 1,
      fire: function () {
           console.log(this.a)
        }
}
obj.fire(); // 输出1
JavaScript 関数における this の 4 つのバインディング形式

一般的なコード操作についてさらに深く考えてみましょう。まず、次の 2 つのコードは同じ効果を実現します。
JavaScript 関数における this の 4 つのバインディング形式
fire 関数には何の違いもありません。これは、obj オブジェクトの内部と外部で定義されているため、上記の 2 つの暗黙的バインディング形式では、fire はこれを渡します。これにより、obj の a プロパティにアクセスできます。これは、次のようになります。 、または、コードの作成中ではなく、コードの実行中にバインドされますJavaScript 関数における this の 4 つのバインディング形式2. 関数のオブジェクトからの独立性、this の配信損失の問題 
(下面的描述可能带有个人的情感倾向而显得不太严谨,但这是因为我希望阅读者尽可能地理解我想表达的意思)
JavaScript 関数における this の 4 つのバインディング形式

隐式绑定下,作为对象属性的函数,对于对象来说是独立的

 
基于this动态绑定的特点,写在对象内部,作为对象属性的函数,对于这个对象来说是独立的。(函数并不被这个外部对象所“完全拥有”)
 
我想表达的意思是:在上文中,函数虽然被定义在对象的内部中,但它和“在对象外部声明函数,然后在对象内部通过属性名称的方式取得函数的引用”,这两种方式在性质上是等价的(而不仅仅是效果上)
 
定义在对象内部的函数只是“恰好可以被这个对象调用”而已,而不是“生来就是为这个对象所调用的”
 
借用下面的隐式绑定中的this传递丢失问题来说明:
JavaScript 関数における this の 4 つのバインディング形式
var obj = {
      a: 1,    // a是定义在对象obj中的属性   1      fire: function () {
   console.log(this.a)
        }
      }
 var a = 2;  // a是定义在全局环境中的变量    2var fireInGrobal = obj.fire;  
fireInGrobal(); //  输出 2
JavaScript 関数における this の 4 つのバインディング形式

 

 
上面这段简单代码的有趣之处在于: 这个于obj中的fire函数的引用( fireInGrobal)在调用的时候,行为表现(输出)完全看不出来它就是在obj内部定义的,其原因在于:我们隐式绑定的this丢失了!! 从而 fireInGrobal调用的时候取得的this不是obj,而是window
 
上面的例子稍微变个形式就会变成一个可能困扰我们的bug:
 
JavaScript 関数における this の 4 つのバインディング形式
var a = 2;var obj = {
    a: 1,    // a是定义在对象obj中的属性    fire: function () {
          console.log(this.a)
     }
}  
function otherFire (fn) {
     fn();
}  
otherFire(obj.fire); // 输出2
JavaScript 関数における this の 4 つのバインディング形式

 

 
在上面,我们的关键角色是otherFire函数,它接受一个函数引用作为参数,然后在内部直接调用,但它做的假设是参数fn仍然能够通过this去取得obj内部的a属性,但实际上, this对obj的绑定早已经丢失了,所以输出的是全局的a的值(2),而不是obj内部的a的值(1)
 JavaScript 関数における this の 4 つのバインディング形式

在一串对象属性链中,this绑定的是最内层的对象

在隐式绑定中,如果函数调用位置是在一串对象属性链中,this绑定的是最内层的对象。如下所示:
JavaScript 関数における this の 4 つのバインディング形式
var obj = {
      a: 1,
      obj2: {
           a: 2,
           obj3: {
                a:3,
                getA: function () {
                    console.log(this.a)   
                 }
           }
       }
}
 
obj.obj2.obj3.getA();  // 输出3
JavaScript 関数における this の 4 つのバインディング形式

 

this的显式绑定:(call和bind方法)

【故事——线路3】 迪斯(this)穿越来异世界“伽瓦斯克利”(javascript),经过努力的打拼,积累了一定的财富,于是他买下了自己的房子
 

 

上面我们提到了this的隐式绑定所存在的this绑定丢失的问题,也就是对于 “ fireInGrobal = obj.fire”
fireInGrobal调用和obj.fire调用的结果是不同的,因为这个函数赋值的过程无法把fire所绑定的this也传递过去。这个时候,call函数就派上用场了

 

call的基本使用方式: fn.call(object)
fn是你调用的函数,object参数是你希望函数的this所绑定的对象。
fn.call(object)的作用:
1.即刻调用这个函数(fn)
2.调用这个函数的时候函数的this指向object对象
 
例子:
JavaScript 関数における this の 4 つのバインディング形式
var obj = {
      a: 1,    // a是定义在对象obj中的属性      fire: function () {
         console.log(this.a)
      }
}
 var a = 2;  // a是定义在全局环境中的变量  var fireInGrobal = obj.fire;
fireInGrobal();   // 输出2fireInGrobal.call(obj); // 输出1
JavaScript 関数における this の 4 つのバインディング形式

 

 
原本丢失了与obj绑定的this参数的fireInGrobal再次重新把this绑回到了obj
 
但是,我们其实不太喜欢这种每次调用都要依赖call的方式,我们更希望:能够一次性 返回一个this被永久绑定到obj的fireInGrobal函数,这样我们就不必每次调用fireInGrobal都要在尾巴上加上call那么麻烦了。
 
怎么办呢? 聪明的你一定能想到,在fireInGrobal.call(obj)外面包装一个函数不就可以了嘛!
JavaScript 関数における this の 4 つのバインディング形式
var obj = {
      a: 1,    // a是定义在对象obj中的属性      fire: function () {
        console.log(this.a)
      }
}
 var a = 2;  // a是定义在全局环境中的变量  var fn = obj.fire;var fireInGrobal = function () {
    fn.call(obj)   //硬绑定}
       
fireInGrobal(); // 输出1
JavaScript 関数における this の 4 つのバインディング形式

 

如果使用bind的话会更加简单
var fireInGrobal = function () {
    fn.call(obj)   //硬绑定}

 

可以简化为:
var fireInGrobal = fn.bind(obj);

 

call和bind的区别是:在绑定this到对象参数的同时:
 
1.call将立即执行该函数
2.bind不执行函数,只返回一个可供执行的函数
 
【其他】:至于apply,因为除了使用方法,它和call并没有太大差别,这里不加赘述
 
在这里,我把显式绑定和隐式绑定下,函数和“包含”函数的对象间的关系比作买房和租房的区别。
 

 

因为this的缘故
 
在隐式绑定下:函数和只是暂时住在“包含对象“的旅馆里面,可能过几天就又到另一家旅馆住了
在显式绑定下:函数将取得在“包含对象“里的永久居住权,一直都会”住在这里“
 

new绑定

【故事】 迪斯(this)组建了自己的家庭,并生下多个孩子(通过构造函数new了许多个对象)
 
 

 

执行new操作的时候,将创建一个新的对象,并且将构造函数的this指向所创建的新对象
 
JavaScript 関数における this の 4 つのバインディング形式
function foo (a) {     this.a = a;
}
 var a1  = new foo (1);var a2  = new foo (2);var a3  = new foo (3);var a4  = new foo (4);
 
console.log(a1.a); // 输出1console.log(a2.a); // 输出2console.log(a3.a); // 输出3console.log(a4.a); // 输出4

相关推荐:

JavaScript中的this规则及this对象用法实例

函数调用的不同方式及this的指向详解

js中this对象用法实例详解

以上がJavaScript 関数における this の 4 つのバインディング形式の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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