まず最初に言っておきたいのは、this のポイントは関数の定義時には決定できないということです。実際、this が最終的にそれを呼び出すオブジェクトを指すことが決定されるのは、関数が実行されるときだけです。 (この文 いくつかの疑問については後ほど説明します。インターネット上の記事の多くはこのように書かれていますが、そのように理解すれば問題ない場合も多いですが、実際にはそのように理解するのは不正確ですので、これを理解するときに不確実性が生じる場合があります)、次にこの問題について詳しく説明します。
なぜこれを学ぶ必要があるのですか?関数型プログラミングやオブジェクト指向プログラミングを学習したことがある方は、それが何に使われるかを必ず知っています。まだ学習していない方は、当面この記事を読む必要はありません。興味があるなら、これはマスターする必要があるものです。
例 1:
function a(){ var user = "追梦子"; console.log(this.user); //undefined console.log(this); //Window } a();
上で述べたように、これは最終的にはそれを呼び出すオブジェクトを指しますが、ここでの関数 a は実際には Window オブジェクトによって示されます。
function a(){ var user = "追梦子"; console.log(this.user); //undefined console.log(this); //Window } window.a();
実際には、alertもウィンドウの属性であり、ウィンドウごとにクリックされます。
例 2:
var o = { user:"追梦子", fn:function(){ console.log(this.user); //追梦子 } } o.fn();
ここでは、この fn を o.fn() を通じて呼び出しているため、当然、オブジェクト o を指しています。ここでも、this のポイントは にあることが強調されています。関数の作成 いつ呼び出されるかは決定できません。誰が呼び出すかは誰を指すのかを理解する必要があります。
実際、例 1 と例 2 は十分に正確ではありません。次の例は上記の理論を覆す可能性があります。
これを完全に理解したい場合は、次のいくつかの例を読む必要があります
例 3:
var o = { user:"追梦子", fn:function(){ console.log(this.user); //追梦子 } } window.o.fn();
このコードは上記のコードとほぼ同じですが、なぜここでこれが window を指さないのですか?上記の理論では、これは最終的にそれを呼び出すオブジェクトを指します。これは余談ですが、作成した変数は実際にウィンドウに属性を追加するため、ここでは window dot オブジェクトを使用できます。
上のコードでこれが window を指していない理由は説明しないで、コードの一部を見てみましょう。
var o = { a:10, b:{ a:12, fn:function(){ console.log(this.a); //12 } } } o.b.fn();
ここでもオブジェクト o が指摘されていますが、これも実行されません。そうすると、最初に言ったことは間違いだと言うでしょうね?実際にはそうではなく、最初に述べたことが不正確だっただけです。次に、これで指摘されている問題を完全に理解できると思います。
状況 1: 関数内に this があるが、上位レベルのオブジェクトによって呼び出されない場合、this は window を指します。ここで説明する必要があるのは、厳密なバージョンの js では、this は window を指しません。詳細については、オンラインで調べてください。ここでは厳密なバージョンについては説明しません。
ケース2: 関数内に this があり、この関数が上位オブジェクトによって呼び出される場合、this は上位オブジェクトを指します。
ケース 3: 複数のオブジェクトを含む関数内に this がある場合、この関数が最も外側のオブジェクトによって呼び出されたとしても、this はその上のオブジェクトのみを指していることを証明できます。続いていくつかの例を見てみましょう。
var o = { a:10, b:{ // a:12, fn:function(){ console.log(this.a); //undefined } } } o.b.fn();
オブジェクト b に属性 a がない場合でも、このオブジェクトに必要なものがあるかどうかに関係なく、これはその上位レベルのオブジェクトのみを指すため、これもオブジェクト b を指します。
別の特殊なケースがあります。例 4:
var o = { a:10, b:{ a:12, fn:function(){ console.log(this.a); //undefined console.log(this); //window } } } var j = o.b.fn; j();
ここでは、これは window を指していますが、混乱していますか?実際、それはあなたが文章を理解していなかったからであり、これも重要です。
これは常に、最後に呼び出したオブジェクト、つまり実行時に呼び出したオブジェクトを指しますが、関数 fn はオブジェクト b によって参照されていますが、fn を変数 j に代入するときは参照されません。例 3 とは異なり、window を指します。例 3 では fn を直接実行します。
これは実際には同じことですが、状況が異なると異なるものを指します 上記の要約にはいくつかの小さな間違いがあり、間違いとは言えませんが、状況が異なると、状況は異なります。一度にわかりやすく説明することはできませんので、ゆっくり体験していただくしかありません。
これのコンストラクターバージョン:
function Fn(){ this.user = "追梦子"; } var a = new Fn(); console.log(a.user); //追梦子
这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a,为什么我说a是对象,因为用了new关键字就是创建一个对象实例,理解这句话可以想想我们的例子3,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象Fn中会有user,因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。
除了上面的这些以外,我们还可以自行改变this的指向,关于自行改变this的指向请看JavaScript中call,apply,bind方法的总结这篇文章,详细的说明了我们如何手动更改this的指向。
更新一个小问题当this碰到return时
function fn() { this.user = '追梦子'; return {}; } var a = new fn; console.log(a.user); //undefined
再看一个
function fn() { this.user = '追梦子'; return function(){}; } var a = new fn; console.log(a.user); //undefined
再来
function fn() { this.user = '追梦子'; return 1; } var a = new fn; console.log(a.user); //追梦子
function fn() { this.user = '追梦子'; return undefined; } var a = new fn; console.log(a.user); //追梦子
什么意思呢?
如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
function fn() { this.user = '追梦子'; return undefined; } var a = new fn; console.log(a); //fn {user: "追梦子"}
还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。
function fn() { this.user = '追梦子'; return null; } var a = new fn; console.log(a.user); //追梦子
知识点补充:
1.在严格版中的默认的this不再是window,而是undefined。
2.new操作符会改变函数this的指向问题,虽然我们上面讲解过了,但是并没有深入的讨论这个问题,网上也很少说,所以在这里有必要说一下。
function fn(){ this.num = 1; } var a = new fn(); console.log(a.num); //1
为什么this会指向a?首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。
以上就是JavaScript中this指针指向的彻底理解的内容,更多相关内容请关注PHP中文网(www.php.cn)!