Javascriptの中のthisの取得値
30520 ワード
もっと読む
thisはjavascriptの中の非常に基礎的な知識点であり、多くの初心者が迷う知識点でもあります.
Ecmascriptでは、以下のように説明されています.
The e e e is a this value assited with everactive execution context.The this value depends on the caler and the type of code being exted and is determined when control enters the ext context.The is is
thisの値はexecutable codeのタイプと直接関連しています.execute codeには3つのGlobal code、Function code、Eval codeがあります.thisの値取りに関するものは前の二つです.
thisのglobal codeの中のは値をとります
この場合問題は比較的簡単で、
this in global code
varを使わずに直接グローバル変数を宣言することができます.
という言い方は間違っていますが、実はウィンドウズに属性を追加しました.
variable and property
function codeにおける thisの値は、対応する関数と結合されているものではなく、すなわち関数の作成時に決定されるものではない. thisの値はコンテキストに入ると決定され、実行中には可変されない.ie.変数の割当値のようにthisに値をつけてはいけません. this
thisの取得値は関数の定義により決定され、関数が大域関数として定義されている場合、対応するthisはglobalである.関数がオブジェクトの方法であれば、thisの値は対応するオブジェクトです.
このような言い方は間違っています.一例を見てみます.
Is the definition of function determing this
実際、
どうして
この質問に答えるには、まずECMAの内部タイプを見てください.
Reference type
The internal Reference type is not a langage data type.It is defined by this specification for expository purposes.However,a value of type Reference is used only as anterinmediate of expressity vation
The Reference type is used to explane the behaviour of such operators as delete、typeof、and the assignment operators.
other use of the Reference type is to expline the determination of the this value for a function call.
A Reference is a reference to a property of an object.A Reference consists of two components,the base object and the property name.
The follwing abstract operations arused in this specification to access the components of references: GetBase(V).Returns the base object component of the reference V. GetPropertyName(V).Returns the property name component of the reference V.
Referenceの構造識別子解析(dentifers resolution)は、識別子に変数名、関数名、関数パラメータ名、および上記のvar宣言を用いずに直接値を付与する変数を含む. 属性アクセス(Property access)は、
Reference
GetValueダミーコード
以上、 関数における である.は、関数呼び出し括弧 に設定する.の他のすべての場合(例えば、 に変換されます. eg 1で がeg 2で はeg 3でfoo.barをtestに割り当てました.testを識別子として、testを呼び出した時にtestReferenceが発生しましたので、global に戻りました.
同じ関数を理解して、異なる方法で呼び出します.なぜ戻り値が違いますか?
二つの問題を見て、実行結果はどうなるかを考えます.
思考
上記のように、関数呼び出し
non-Reference call
複雑な点の例をいくつか見てみます.
thisはjavascriptの中の非常に基礎的な知識点であり、多くの初心者が迷う知識点でもあります.
Ecmascriptでは、以下のように説明されています.
The e e e is a this value assited with everactive execution context.The this value depends on the caler and the type of code being exted and is determined when control enters the ext context.The is is
thisの値はexecutable codeのタイプと直接関連しています.execute codeには3つのGlobal code、Function code、Eval codeがあります.thisの値取りに関するものは前の二つです.
thisのglobal codeの中のは値をとります
この場合問題は比較的簡単で、
this
の値はglobalオブジェクト自体です.this in global code
1
2
3
4
5
6
7
8
9
10
11
12
// explicit property definition of the global object
this.a = 10; // global.a = 10
alert(a); // 10
// implicit property definition of the global object
b = 20;
alert(this.b); // 20
// also implicit via variable declaration
// in global context: this = global = VO
var c = 30;
alert(this.c); // 30
demoの中のbはvarを通じて声明していません.実はvariableではなく、windowのpropertyです.変数と属性の著しい違いは変数が「DotDelete」を持っていますが、後者はありません.だからよく言いますvarを使わずに直接グローバル変数を宣言することができます.
という言い方は間違っていますが、実はウィンドウズに属性を追加しました.
variable and property
1
2
3
4
var a =5;
b = 4; // equal to windows.b = 4
alert(delete a); // false
alert(delete b); // true
thisのfunction codeでの取得値function codeにおける
this
の値はglobal codeのように簡単ではない:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var foo = {x: 10};
var bar = {
x: 20,
test: function () {
alert(this === bar); // true
alert(this.x); // 20
this = foo; // error, can't change this value
alert(this.x); // if there wasn't an error, then would be 10, not 20
}
};
// on entering the context this value is
// determined as "bar" object;
bar.test(); // true, 20
foo.test = bar.test;
// however here this value will now refer
// to "foo" – even though we're calling the same function
foo.test(); // false, 10
どのような要因がthisに影響を与えるのですか?いくつかの文章と本の中には、次のような言い方があります.thisの取得値は関数の定義により決定され、関数が大域関数として定義されている場合、対応するthisはglobalである.関数がオブジェクトの方法であれば、thisの値は対応するオブジェクトです.
このような言い方は間違っています.一例を見てみます.
Is the definition of function determing this
1
2
3
4
5
6
7
8
9
10
function foo() {
bar: function() {
console.log(this);
}
}
foo.bar(); // foo
var baz = foo.bar;
console.log(baz === foo.bar); // true
baz(); // global
bazはfoo.barの値と同じですが、同じ関数を指します.しかし、呼び出しの結果は違っていますので、thisの取得値は関数の定義によって決定されません.実際、
this
の値は、関数の呼び出しによって決定される、例えば、関数の親コンテキストなどの使用者によって提供される.どうして
this
の値は関数の呼び出しによって決まるのですか?この質問に答えるには、まずECMAの内部タイプを見てください.
Reference
typeReference type
Refference
は内部タイプで、Reference
タイプの値を返すことができる関数は何もありません.built-in関数でも、ユーザ定義の関数でもあります.Reference
に関する仕様の説明は以下の通りである.The internal Reference type is not a langage data type.It is defined by this specification for expository purposes.However,a value of type Reference is used only as anterinmediate of expressity vation
The Reference type is used to explane the behaviour of such operators as delete、typeof、and the assignment operators.
other use of the Reference type is to expline the determination of the this value for a function call.
A Reference is a reference to a property of an object.A Reference consists of two components,the base object and the property name.
The follwing abstract operations arused in this specification to access the components of references:
Reference
の構成は、以下のように説明することができる.Referenceの構造
1
2
3
4
var ReferenceType = {
base: <base object>,
propertyName: <property name>
};
仕様によれば、以下の2つの場合のみ、Reference
タイプの値が返される.[]
または.
を介して、foo.bar
のような2つの方法でアクセスされている.Reference
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//
var foo = 10;
function bar() {}
// Reference
var fooReference = {
base: global,
propertyName: 'foo'
};
var barReference = {
base: global,
propertyName: 'bar'
};
//
foo.bar();
foo['bar']();
// Reference type
var fooBarReference = {
base: foo,
propertyName: 'bar'
};
foo['bar']
は中間値であり、real valueを取得するにはReference
方法が必要である(参照).GetValueダミーコード
1
2
3
4
5
6
7
8
9
10
11
12
13
function GetValue(value) {
if (Type(value) != Reference) {
return value;
}
var base = GetBase(value);
if (base === null) {
throw new ReferenceError;
}
return base.[[Get]](GetPropertyName(value));
}
GetValue
関数は、プロトタイプチェーン上の継承属性を考慮しながらオブジェクト属性の値を返します.以上、
[[Get]]
の取得値について:this
の取得値は、使用者によって提供され、関数の現在の呼び出し方式によって決定されるthis
の左に()
のタイプの値がある場合、Reference
の値をその値のBase属性の値this
の左の値は()
タイプではない)、Reference
はthis
に設定されます.null
は何の意味もないので、それらは陰的にglobal object 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// eg1
function foo() {
return this;
}
foo(); // global
// Reference
var fooReference = {
base: global,
propertyName: 'foo'
};
// eg2
var foo = {
bar: function () {
return this;
}
};
foo.bar(); // foo
// Reference
var fooBarReference = {
base: foo,
propertyName: 'bar'
};
// eg3
// foo.bar
var test = foo.bar;
test(); // global
// Reference
var testReference = {
base: global,
propertyName: 'test'
};
上のデモにnull
を呼び出した場合、上記の原則に従って、fooは変数であり、識別子解析でfoo()
typeの値fooReferenceを返します.thisはfooReferenceオブジェクトのbase属性の値に設定されます.Reference
を呼び出したとき、barはfooの属性の一つとして、属性を読み取ってglobal
タイプの値fooBarReferenceを返します.thisはbase属性の値に設定されます.foo.bar()
同じ関数を理解して、異なる方法で呼び出します.なぜ戻り値が違いますか?
二つの問題を見て、実行結果はどうなるかを考えます.
思考
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// :
function foo () {
console.log(this);
}
foo(); // ?
foo.prototype.constructor(); // ?
// :
function foo() {
console.log(this.bar);
}
var x = {bar: 10};
var y = {bar: 20};
x.test = foo;
y.test = foo;
x.test(); // ?
y.test(); // ?
Function call and non-Reference type上記のように、関数呼び出し
Reference
の左側がReferenceタイプ値ではない場合、thisはnullに設定され、次いで暗黙的にglobalに変換される.non-Reference call
1
2
3
(function () {
alert(this); // null => global
})();
上記の例ではfoo
の左側は関数オブジェクトであり、識別子でも属性でもないので、Reference値には戻りません.thisはnullに設定され、次いでglobalに変換されます.複雑な点の例をいくつか見てみます.
1
2
3
4
5
6
7
8
9
10
11
12
var foo = {
bar: function () {
alert(this);
}
};
foo.bar(); // Reference, OK => foo
(foo.bar)(); // Reference, OK => foo
(foo.bar = foo.bar)(); // global?
(false || foo.bar)(); // global?
(foo.bar, foo.bar)(); // global?