ホームページ  >  記事  >  ウェブフロントエンド  >  これに関連する入門、JS での適用、呼び出し、バインド

これに関連する入門、JS での適用、呼び出し、バインド

巴扎黑
巴扎黑オリジナル
2017-09-20 09:28:541237ブラウズ

JS の This、apply、call、bind は典型的な面接の質問です。this と call、apply、bind の方向の違いを理解することが最善です。 Script House の編集者に従って、この知識を学び、応募し、電話をかけ、バインドしましょう

これも典型的な面接の質問です~/(ㄒoㄒ)/~~ これは、ES5 にある多くの落とし穴の 1 つでもあります。 ES6 これにより発生するエラーを大幅に回避できる可能性がありますが、一部の古いコードを保守するには、this のポイントと call、apply、bind の違いを理解することが最善です。

this

のポイント 実際、ES5 では、this のポイントは常に 1 つの原則に従います。これは、常に最後に呼び出したオブジェクトを指します。さあ、私の後に 3 回読んでください。そのオブジェクト、this は常にそれを呼び出した最後のオブジェクトを指し、this は常にそれを呼び出した最後のオブジェクトを指します。この文を覚えておいてください。半分はすでに知っています。

最も単純な例を見てみましょう:

例 1:


 var name = "windowsName";
 function a() {
  var name = "Cherry";
  console.log(this.name);   // windowsName
  console.log("inner:" + this); // inner: Window
 }
 a();
 console.log("outer:" + this)   // outer: Window

ログが windowsName である理由は誰もが知っていると思います。なぜなら、今の文によると、「これは常に最後に呼び出したログを指しているからです」 it Object" で、a が a(); と呼ばれる最後の場所を見てみましょう。前に呼び出されなかったオブジェクトは、window.a() と同等のグローバル オブジェクト ウィンドウです。厳密モードを使用していないことに注意してください。ここで、厳密モードが使用されている場合、グローバル オブジェクトが未定義である場合、「Uncaught TypeError: Cannot read property 'name' of unknown」というエラーが報告されます。

この例をもう一度見てください:

例 2:


var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 a.fn();

この例では、関数 fn がオブジェクト a によって呼び出されるため、出力される値は a の name の値です。もう少し分かりやすくなりましたか~

少し変更を加えてみましょう:

例 3:


var name = "windowsName";
 var a = {
  name: "Cherry",
  fn : function () {
   console.log(this.name);  // Cherry
  }
 }
 window.a.fn();

ここに Cherry が表示されている理由も、先ほどの文のせいです。「これは常に最後に呼び出したオブジェクトを指します」 it” ” の場合、最終的にそれを呼び出したオブジェクトは依然としてオブジェクト a です。

もう一度この例を見てみましょう:

例 4:


 var name = "windowsName";
 var a = {
  // name: "Cherry",
  fn : function () {
   console.log(this.name);  // undefined
  }
 }
 window.a.fn();

なぜここに unfineed が出力されるのでしょうか?これは、先ほど説明したように、 fn がオブジェクト a によって呼び出されるためです。これは、 fn の内部 this がオブジェクト a であり、 name がオブジェクト a で定義されていないため、ログ内の this.name の値が undefine であるためです。

この例は、さらに次のことを示しています。 fn を最後に呼び出したオブジェクトは a であるため、 this は常にそれを最後に呼び出したオブジェクトを指します。そのため、a に name 属性がない場合でも、次の this.name の検索は続行されません。前のオブジェクトですが、未定義を直接出力します。

もっと分かりにくい例を見てみましょう:

例 5:


 var name = "windowsName";
 var a = {
  name : null,
  // name: "Cherry",
  fn : function () {
   console.log(this.name);  // windowsName
  }
 }
 var f = a.fn;
 f();

ここで疑問があるかもしれませんが、なぜ Cherry ではないのでしょうか? これは、オブジェクトの fn メソッドが変数 f に割り当てられているためです。 、呼び出しはありません、そして私の後にこの文を読んでください: 「これは常にそれを最後に呼び出したオブジェクトを指します。」 f が今呼び出されなかったので、fn() は最終的にまだウィンドウによって呼び出されています。したがって、これはウィンドウを指します。

上記の 5 つの例から、es5 では、this のポイントは常に最後に呼び出したオブジェクトを指すことがわかります。

別の例を見てみましょう:

例6:


 var name = "windowsName";
 function fn() {
  var name = 'Cherry';
  innerFunction();
  function innerFunction() {
   console.log(this.name);  // windowsName
  }
 }
 fn()

今読んだら、なぜこれが起こっているのか理解できるはずです(o゚▽゚)o。

thisの点を変更する方法

thisの点を変更する以下の方法をまとめました:

ES6のarrow関数を使う

関数内で_this = thisを使う

apply, call、bind

new はオブジェクトをインスタンス化します

例 7:


var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   },100);
  }
 };
 a.func2()  // this.func1 is not a function

アロー関数が使用されていない場合、setTimeout を呼び出す最後のオブジェクトが window であるため、エラーが報告されますが、setTimeout が存在しないためです。 func1関数はありません。

このポインタを変更するこのセクションでは、デモとしてこの例を変換します。

アロー関数

ご存知のとおり、ES6 のアロー関数は、ES5 でこれを使用する場合の落とし穴を回避できます。アロー関数の this は、関数が実行されるときではなく、関数が定義されるときに常に this を指します。アロー関数は次の文を覚えておく必要があります。「アロー関数には this バインディングがありません。その値はスコープ チェーンを検索して決定する必要があります。アロー関数がアロー関数以外の関数に含まれている場合、このバインディングは次のようになります。」最も近い非矢印関数は this、それ以外の場合は未定義です。」

例 8:


 var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   setTimeout( () => {
    this.func1()
   },100);
  }
 };
 a.func2()  // Cherry

関数内で _this = this を使用します

ES6 を使用しない場合は、このメソッドが最も簡単でエラーのない方法です。最初にこの関数を呼び出します。オブジェクトは次のとおりです。変数 _this に保存され、その後、この _this が関数で使用されるため、_this は変更されません。

例 9:


 var name = "windowsName";
 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)  
  },
  func2: function () {
   var _this = this;
   setTimeout( function() {
    _this.func1()
   },100);
  }
 };
 a.func2()  // Cherry

这个例子中,在 func2 中,首先设置 var _this = this;,这里的 this 是调用 func2 的对象 a,为了防止在 func2 中的 setTimeout 被 window 调用而导致的在 setTimeout 中的 this 为 window。我们将 this(指向变量 a) 赋值给一个变量 _this,这样,在 func2 中我们使用 _this 就是指向对象 a 了。

使用 apply、call、bind

使用 apply、call、bind 函数也是可以改变 this 的指向的,原理稍后再讲,我们先来看一下是怎么实现的:

使用 apply

例 10:


 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.apply(a),100);
  }
 };
 a.func2()   // Cherry

使用 call

例 11:


 var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.call(a),100);
  }
 };
 a.func2()   // Cherry

使用 bind

例 12:


var a = {
  name : "Cherry",
  func1: function () {
   console.log(this.name)
  },
  func2: function () {
   setTimeout( function () {
    this.func1()
   }.bind(a)(),100);
  }
 };
 a.func2()   // Cherry

apply、call、bind 区别

刚刚我们已经介绍了 apply、call、bind 都是可以改变 this 的指向的,但是这三个函数稍有不同。

在 MDN 中定义 apply 如下;

apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数

语法:


fun.apply(thisArg, [argsArray])

thisArg:在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。

argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。浏览器兼容性请参阅本文底部内容。

apply 和 call 的区别

其实 apply 和 call 基本类似,他们的区别只是传入的参数不同。

call 的语法为:


fun.call(thisArg[, arg1[, arg2[, ...]]])

所以 apply 和 call 的区别是 call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。

例 13:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.apply(a,[1,2])  // 3

例 14:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.call(a,1,2)  // 3

bind 和 apply、call 区别

我们先来将刚刚的例子使用 bind 试一下


 var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.bind(a,1,2)

我们会发现并没有输出,这是为什么呢,我们来看一下 MDN 上的文档说明:

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

所以我们可以看出,bind 是创建一个新的函数,我们必须要手动去调用:


var a ={
  name : "Cherry",
  fn : function (a,b) {
   console.log( a + b)
  }
 }
 var b = a.fn;
 b.bind(a,1,2)()   // 3

以上がこれに関連する入門、JS での適用、呼び出し、バインドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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