JavaScriptはthisのいくつかの面接問題と紹介について
7989 ワード
原文のリンク
他の言語と比較して、関数の
圧倒的多数の場合、関数の呼び出し方式は
まず面接問題をいくつか作ります.
第一コース:
一、グローバルコンテキスト
大域的な動作コンテキスト(任意の関数の外部)では、
関数内部では、
1、直接呼び出し
非厳密モードでは、
2、対象方法における
以下の例では、
前の例では、
同様に、
以下の例では、方法
4、
なお、コンストラクタが返したデフォルト値が
ECMAScript 5は
(終わり)
他の言語と比較して、関数の
this
キーワードはJavaScriptでの挙動が少し違っています.また,厳密モードと非厳密モードの間にもいくつかの違いがある.圧倒的多数の場合、関数の呼び出し方式は
this
の値を決定する.this
は実行中に値が割り当てられず、関数が呼び出される度にthis
の値も異なるかもしれない.ES 5は、関数がどのように呼び出されるかを考慮することなく、関数のbind
値を設定するthis
方法を導入する.まず面接問題をいくつか作ります.
第一コース:
var name = "caibaojian.com";
var person = {
name: "kang",
pro: {
name: "Michael",
getName: function() {
return this.name;
}
}
};
console.log(person.pro.getName()); // Michael
var pepole = person.pro.getName;
console.log(pepole()); // caibaojian.com
第二コース:var name = "caibaojian.com";
var person = {
name: "kang",
pro: {
name: "Michael",
getName: function() {
console.log(this);
return this.name;
}
}
};
console.log(person.pro.getName()); // Object { name: "...", getName: () }, Michael
var pepole = person.pro.getName;
console.log(pepole()); // Window, caibaojian.com
第三コース:'use strict';
var name = "caibaojian.com";
var person = {
name: "kang",
pro: {
name: "Michael",
getName: function() {
console.log(this);
return this.name;
}
}
};
console.log(person.pro.getName()); // Object { name: "...", getName: () }, Michael
var pepole = person.pro.getName;
console.log(pepole()); // undefined
第四コース:var name = "caibaojian.com",
person = {
name : "kang",
getName : function(){
return function(){
return this.name;
};
}
};
console.log(person.getName()()); // caibaojian.com
次に、this
の使い方について説明します.一、グローバルコンテキスト
大域的な動作コンテキスト(任意の関数の外部)では、
this
は、厳密なモードであるかどうかにかかわらず、大域的なオブジェクトを指す.ブラウザでは、グローバルオブジェクトはwindow
オブジェクトである.console.log(this.document === document); // true
console.log(this === window); // true
this.a = 37;
console.log(window.a); // 37
二、関数の文脈関数内部では、
this
の値は、関数がどのように呼び出されるかによって決まる.1、直接呼び出し
非厳密モードでは、
this
の値は、関数実行時には設定されません.このときのthis
の値は、デフォルトでグローバルオブジェクトに設定されます.function foo(){
return this;
}
foo() === window; // true
厳格なモードでは、this
は、彼が実行環境に入ったときの値を保持するので、以下のthis
は、undefined
にデフォルトで設定されるだろう.function foo(){
"use strict"; //
return this;
}
foo() === undefined; // true
厳密なモードでは、this
が実行されていないコンテキスト環境定義の場合、undefined
はデフォルトである.2、対象方法における
this
関数がオブジェクト内の方法で呼び出されると、それらのthis
は、関数を呼び出すオブジェクトである.以下の例では、
obj.f()
が呼び出されると、関数内のthis
はobj
オブジェクトにバインドされる.var obj = {
prop: 37,
foo: function() {
return this.prop;
}
};
console.log(obj.foo()); // 37
なお、呼び出し関数がどこにあるか、またはどのように定義されているかは、this
の動作に全く影響しない.前の例では、
obj
を定義する際に、そのメンバfoo
に匿名関数を定義した.しかし、まず関数を定義してからobj.foo
に付属することもできる.このようにしてthis
の評価も上記と一致している.var obj = { prop: 37 };
function independent() {
return this.prop;
}
obj.foo = independent;
console.log(obj.foo()); // 37
これは、this
の値が、foo
のメンバとして関数obj
によってのみ呼び出されることに関係していることを示している.同様に、
this
のバインディングは、最も近いメンバ参照によってのみ影響される.以下の例では、方法
g
をオブジェクトobj.b
の関数として呼び出す.今回の実行中、関数のthis
はobj.b
に向けられます.実は、これは相手自身のメンバーとはあまり関係がなく、一番近い引用が一番重要です.var obj = { prop: 37 };
function independent() {
return this.prop;
}
obj.b = {
g: independent,
prop: 42
};
console.log(obj.b.g()); // 42
3、プロトタイプチェーンのthis
同じ概念はプロトタイプ鎖で定義される方法でも一致した.この方法がオブジェクトのプロトタイプチェーン上に存在する場合、this
は、この方法を呼び出すオブジェクトを指し、この方法がこのオブジェクト上に存在するように表現される.var obj = {
f : function(){
return this.a + this.b;
}
};
var p = Object.create(obj);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
この例では、オブジェクトp
は自身のf
属性ではなく、f
属性はそのプロトタイプから継承されている.しかし、これは最終的にobj
においてf
属性を発見するルックアッププロセスに関係がない.検索プロセスはまずp.f
の参照から開始されるので、関数のthis
はp
を指す.つまり、f
はp
の方法として呼び出されたので、this
はp
を指す.これはJavaScriptの原型継承の中の興味深い特性である.4、
getter
とsetter
のthis
同じ概念も適用される場合の関数は、getter
またはsetter
として呼び出される.getter
またはsetter
の関数として、属性の設定または属性を得るオブジェクトにthis
が紐付けられます.function modulus(){
return Math.sqrt(this.re * this.re + this.im * this.im);
}
var obj = {
re: 1,
im: -1,
get phase(){
return Math.atan2(this.im, this.re);
}
};
Object.defineProperty(obj, 'modulus', {
get: modulus,
enumerable: true,
configurable: true
});
console.log(obj.phase, obj.modulus); // -0.785 1.414
5、コンストラクタのthis
関数が構築関数として使用されるとき(new
キーワードを使用して)、そのthis
は作成される新しいオブジェクトと結合される.なお、コンストラクタが返したデフォルト値が
this
によって参照されたオブジェクトである場合には、他のオブジェクトに戻るように手動で設定することができ、戻り値がオブジェクトでない場合にはthis
に戻る.function Fn(){
this.a = 37;
}
var obj = new Fn();
console.log(obj.a); // 37
function Foo(){
this.a = 37;
return { a: 38 };
}
obj = new Foo();
console.log(obj.a); // 38
6、call
及びapply
関数の関数がthis
キーを使用している場合、Function
オブジェクトのプロトタイプからすべての関数が引き継がれるcall()
方法およびapply()
方法から呼び出した場合、その値は指定されたオブジェクトに結び付けられ得る.function add(c, d){
return console.log(this.a + this.b + c + d);
}
var obj = {
a: 1,
b: 3
};
add.call(obj, 5, 7); // 1 + 3 + 5 + 7 = 16
add.apply(obj, [10, 20]); // 1 + 3 + 10 + 20 = 34
call
およびapply
関数を使用する場合、伝達されたthis
値がオブジェクトでない場合、JavaScriptは内部ToObject
動作を用いてオブジェクトに変換しようと試みる.したがって、伝達された値が元の値である7
またはfoo
のような場合、関連するコンストラクタを使用してオブジェクトに変換されるので、元の値7
はnew Number(7)
を介してオブジェクトに変換され、文字列foo
はnew String('foo')
を使用してオブジェクトに変換される.function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number]
7、bind()
方法ECMAScript 5は
Function.prototype.bind
を導入した.fn.bind(someObject)
を呼び出して、fn
と同じ関数と作用領域を持つ関数を作成しますが、この新しい関数では、this
は、bind
の最初のパラメータに恒久的に結びつけられます.function fn(){
return this.a;
}
var g = fn.bind({ a: "azerty" });
console.log(g()); // "azerty"
var obj = {
a: 37,
foo: fn,
go: g
};
console.log(obj.foo(), obj.go()); // 37, "azerty"
8、DOMイベント処理関数のthis
関数がイベントハンドラ関数として使用されると、そのthis
は、イベントをトリガする要素(一部のブラウザは、モニタを動的に追加する場合、この約束を守らない限り、addEventListener
を使用しない)を指す.//
var elements = document.getElementsByTagName('*');
for(var i = 0; i < elements.length; i++){
// ,
elements[i].addEventListener('click', function (e) {
e.stopPropagation();
console.log(this);
console.log(e.currentTarget);
console.log(e.target);
// 3
this.style.backgroundColor = '#A5D9F3';
});
}
9、インラインイベント処理関数のthis
コードがインライン処理関数によって呼び出されると、そのthis
は、モニターのあるDOM要素を指す.
上のalert
はbutton
を表示します.注意外層コードの中のthis
だけがこのように設定されています.
この場合、内部関数が設定されていないthis
は、global/window
オブジェクト(すなわち、非厳格モードで呼び出された関数が設定されていないときに指すデフォルトオブジェクト)を指す.(終わり)