序文
最近キーワードのJavaScriptの記事を読んでthis
、教育の記事を共有するすべての人のために整理少し、この記事に基づいて、そのため、多くを得ます。希望は、JavaScriptの子供用の靴、よく理解学習に貢献することができるthis
JavaScriptでこの最も重要なキーワードを。
意味
1.定義
これは、「現在の」場所のオブジェクトプロパティまたはメソッドです。
this.property
复制代码
上記のコードは、このプロパティは、プロパティが現在配置されているオブジェクトを表します。
以下は、実用的な例です。
var person = {
name: '张三',
describe: function () {
return '姓名:'+ this.name;
}
};
person.describe()
// "姓名:张三"
复制代码
2.このばらつき
オブジェクトのプロパティは、現在のオブジェクトの特性が可変である別のオブジェクトに割り当てることができるので、すなわち、この点は可変です。
var A = {
name: '张三',
describe: function () {
return '姓名:'+ this.name;
}
};
var B = {
name: '李四'
};
B.describe = A.describe;
B.describe()
// "姓名:李四"
复制代码
少し改造この例では、このダイナミックはより明確に指して見ることができます。
function f() {
return '姓名:'+ this.name;
}
var name='王五';
var A = {
name: '张三',
describe: f
};
var B = {
name: '李四',
describe: f
};
A.describe() // "姓名:张三"
B.describe() // "姓名:李四"
f() // "姓名:王五"
复制代码
3. Webプログラミングアプリケーション
Webプログラミングの例を見てください。
<input type="text" name="age" size=3 onChange="validate(this, 18, 99);">
<script>
function validate(obj, lowval, hival){
if ((obj.value < lowval) || (obj.value > hival))
console.log('Invalid Value!');
}
</script>
复制代码
要約すると、JavaScript言語の中で、すべてのものがオブジェクトである関数はオブジェクトで実行されているので、動作環境は、オブジェクトであり、これは、関数が(環境)を実行しているオブジェクトです。
物質
メモリアドレスの1オブジェクト
JavaScriptのメモリデータ構造と関係を持っているデザインの、この言語、そこにある理由。
var obj = { foo: 5 };
复制代码
上記目的は、変数OBJに割り当てられたコードです。可変オブジェクトobjに割り当てられ、次にメモリアドレス:JavaScriptエンジンは、最初のコードは、メモリに、オブジェクト{5 FOO}を生成するであろう。換言すれば、変数objがアドレス(参照)です。obj.foo、エンジン始動をリードバックOBJメモリアドレスを取得した後、元のオブジェクトからアドレスを読み出すためには、属性fooのを返します。
辞書構造に格納された元のオブジェクトは、各プロパティ名は、プロパティ記述オブジェクトに対応します。例えば、上記の例FOO特性は、実際には次の形式で格納されます。
{
foo: {
[[value]]: 5
[[writable]]: true
[[enumerable]]: true
[[configurable]]: true
}
}
复制代码
値fooの中に格納された値は、オブジェクトの内部属性説明属性があります。
2.メモリアドレスの機能
このような構造は、問題のプロパティの値が関数であるかもしれないことを、非常に明確です。
var obj = { foo: function () {} };
复制代码
この場合、個別のメモリに記憶されたエンジンの意志機能は、次いで、アドレスは、関数fooに割り当てられたプロパティ値を属性。
{
foo: {
[[value]]: 函数的地址
...
}
}
复制代码
動作環境の3機能
関数は単一の値であるので、異なる環境(コンテキスト)で行うことができます。
var f = function () {};
var obj = { f: f };
// 单独执行
f()
// obj 环境执行
obj.f()
复制代码
関数の本体内で許可されたJavaScriptは、他の変数の現在の環境を参照してください。
var f = function () {
console.log(x);
};
复制代码
上記のコードでは、関数本体は、変数Xを使用します。この変数は、動作環境によって提供されます。
4.この外観
今の質問は、機能が異なる動作環境で実行することができますので、関数本体内の現在の動作環境(コンテキスト)を取得するためのメカニズムを持っていることが必要である、となります。これは登場しそう、現在のオペレーティング環境の機能を参照して、体内に機能するように設計されています。
var f = function () {
console.log(this.x);
}
复制代码
上記のコードでは、関数本体は、x this.x現在の動作環境を意味します。
var f = function () {
console.log(this.x);
}
var x = 1;
var obj = {
f: f,
x: 2,
};
// 单独执行
f() // 1
// obj 环境执行
obj.f() // 2
复制代码
機会を利用して
1.地球環境
これを使用して、地球環境、それはトップレベルのオブジェクトのウィンドウを指します。
this === window // true
function f() {
console.log(this === window);
}
f() // true
复制代码
説明上記のコード、関数内か否かは、限り、地球環境で実行されているように、これは、トップレベルのオブジェクトのウィンドウを指します。
2.コンストラクタ
コンストラクタこれは、インスタンス・オブジェクトを指します。
var Obj = function (p) {
this.p = p;
};
复制代码
上記のコードは、コンストラクタOBJに定義します。これは、オブジェクトインスタンスを参照するので、コンストラクタは、オブジェクト・インスタンスの属性pの定義に相当し、this.p内で定義され。
var o = new Obj('Hello World!');
o.p // "Hello World!"
复制代码
3.オブジェクト
オブジェクトがポイントを常駐含まれているオブジェクトのメソッドは、この方法であれば、これは実行時。別のオブジェクトに割り当てられている。この方法では、これはポイントを変更します。
しかし、このルールは把握することは容易ではありません。次のコードを考えてみましょう。
var obj ={
foo: function () {
console.log(this);
}
};
obj.foo() // obj
复制代码
obj.foo方法を実行されたときに上記のコードでは、これは内部OBJを指します。
しかし、これの使い方は、次の種類が、この点を変更します。
// 情况一
(obj.foo = obj.foo)() // window
// 情况二
(false || obj.foo)() // window
// 情况三
(1, obj.foo)() // window
复制代码
上記の3つのケースは、次のコードと等価です。
// 情况一
(obj.foo = function () {
console.log(this);
})()
// 等同于
(function () {
console.log(this);
})()
// 情况二
(false || function () {
console.log(this);
})()
// 情况三
(1, function () {
console.log(this);
})()
复制代码
このメソッドは、オブジェクトの第1の層が配置されていない場合、これは現在注目点のひとつであり、より上層を継承しないであろう。
var a = {
p: 'Hello',
b: {
m: function() {
console.log(this.p);
}
}
};
a.b.m() // undefined
复制代码
コードの実際の実行は、以下であるので、上記のコードは、第2層ABMメソッドオブジェクトでは、この方法は、点A、点AB&内部ではなく。
var b = {
m: function() {
console.log(this.p);
}
};
var a = {
p: 'Hello',
b: b
};
(a.b).m() // 等同于 b.m()
复制代码
あなたは所望の効果を達成したい場合は、次のようにだけ書くこと。
var a = {
b: {
m: function() {
console.log(this.p);
},
p: 'Hello'
}
};
复制代码
あなたは、変数に割り当てられたオブジェクト内のメソッドを入れ子になった場合、これはまだグローバルオブジェクトを指します。
var a = {
b: {
m: function() {
console.log(this.p);
},
p: 'Hello'
}
};
var hello = a.b.m;
hello() // undefined
复制代码
上記のコード、mは内部多層オブジェクトのメソッドです。あなたは結果を呼び出すときに簡単にするために、それはハロー変数に代入され、これはトップレベルのオブジェクトを指します。この問題を回避するには、それだけでここで、mこんにちは、この呼び出しオブジェクトに割り当てることができ、この時点では変更されません。
var hello = a.b;
hello.m() // Hello
复制代码
使用上の注意
この多層を避けます
この点が不明であるので、この関数に複数の層を含むことはありません。
var o = {
f1: function () {
console.log(this);
var f2 = function () {
console.log(this);
}();
}
}
o.f1()
// Object
// Window
复制代码
コードの実際の実行は、以下であるため、上記のコードは、この二層、演算の結果、最初のポインティング物体O層、グローバルオブジェクトの第2の層とを含んでいます。
var temp = function () {
console.log(this);
};
var o = {
f1: function () {
console.log(this);
var f2 = temp();
}
}
复制代码
一つの解決策は、この層の第二外層に可変ポインティングを使用することです。
var o = {
f1: function() {
console.log(this);
var that = this;
var f2 = function() {
console.log(that);
}();
}
}
o.f1()
// Object
// Object
复制代码
2.この配列を回避する処理方法
メソッドのマップとforeachの配列は、それがパラメータとしての機能を提供することを可能にします。この内部関数は、これを使うべきではありません。
var o = {
v: 'hello',
p: [ 'a1', 'a2' ],
f: function f() {
this.p.forEach(function (item) {
console.log(this.v + ' ' + item);
});
}
}
o.f()
// undefined a1
// undefined a2
复制代码
上記のコードでは、このforeachの方法におけるコールバック関数は、実際には、オブジェクト・ウィンドウへのポインタであるため、OVの値を取得することができません。この多層セクションを維持する理由は、これが外側に向けられた内側層、およびトップレベルのオブジェクト点はないが、同じです。
この問題を解決する一つの方法は、これを用いて前述の固定中間変数です。
var o = {
v: 'hello',
p: [ 'a1', 'a2' ],
f: function f() {
var that = this;
this.p.forEach(function (item) {
console.log(that.v+' '+item);
});
}
}
o.f()
// hello a1
// hello a2
复制代码
別の方法は、オペレーティング環境に固定された第2パラメータとしてこの方法をforeachのことです。
var o = {
v: 'hello',
p: [ 'a1', 'a2' ],
f: function f() {
this.p.forEach(function (item) {
console.log(this.v + ' ' + item);
}, this);
}
}
o.f()
// hello a1
// hello a2
复制代码
3.このコールバック関数を避けます
コールバック関数は、この点を変更する傾向があり、それが最善の回避されます。
var o = new Object();
o.f = function () {
console.log(this === o);
}
// jQuery 的写法
$('#button').on('click', o.f);
复制代码
この方法の結合
1.コール
関数呼び出しインスタンスの方法は、これは、次いで、指定範囲、指定された機能(すなわち、ここで実行される機能の範囲)の内部に関数呼び出しを向けることができます。
var obj = {};
var f = function () {
return this;
};
f() === window // true
f.call(obj) === obj // true
复制代码
パラメータメソッド呼び出し、それがオブジェクトでなければなりません。引数が、ヌルヌルと定義されていない場合は、グローバルオブジェクトは、デフォルトで渡されます。
var n = 123;
var obj = { n: 456 };
function a() {
console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456
复制代码
引数は呼び出しメソッド元の値である場合、プリミティブ値は自動的に包装することに対応するオブジェクトは、着信方法に転送されます。
var f = function () {
return this;
};
f.call(5)
// Number {[[PrimitiveValue]]: 5}
复制代码
この方法はまた、呼の複数のパラメータを受け入れることができます。
func.call(thisValue, arg1, arg2, ...)
复制代码
そのオブジェクトの呼び出し最初の引数は、このとき、関数呼び出しのパラメータを必要とするパラメータの背中を指すことがあります。
function add(a, b) {
return a + b;
}
add.call(this, 1, 2) // 3
复制代码
アプリケーションがネイティブメソッドのメソッドを呼び出すオブジェクトを呼び出します。
var obj = {};
obj.hasOwnProperty('toString') // false
// 覆盖掉继承的 hasOwnProperty 方法
obj.hasOwnProperty = function () {
return true;
};
obj.hasOwnProperty('toString') // true
Object.prototype.hasOwnProperty.call(obj, 'toString') // false
复制代码
2.適用
作用の方法と呼び出しと同様の方法を適用するが、この点も変化し、その関数を呼び出しています。唯一の違いは、次の形式を使用して、実行パラメータの関数として配列を受け取ることです。
func.apply(thisValue, [arg1, arg2, ...])
复制代码
最初の引数は、この方法を適用するnullに設定または未定義の場合は、グローバルオブジェクトを指定するのと同じ、オブジェクトが指摘されるべきことです。第2のパラメータは、今度は、パラメータとして、アレイのすべてのメンバーは、元の関数を通過し、アレイです。元の関数のパラメータは、一つの呼処理を追加したが、この方法を適用する必要があり、それはアレイの形態で添加されなければなりません。
function f(x, y){
console.log(x + y);
}
f.call(null, 1, 1) // 2
f.apply(null, [1, 1]) // 2
复制代码
(1)配列の最大要素を見つけます
JavaScriptは、配列の最大の要素を見つけるための機能を提供していません。方法および適用Math.max組み込まれた方法は、それが配列の最大要素に戻すことができます。
var a = [10, 2, 4, 15, 9];
Math.max.apply(null, a) // 15
复制代码
(2)配列要素は未定義空になります
空の配列コンストラクタ素子アレイが未定義となる使用方法を適用します。
Array.apply(null, ['a', ,'b'])
// [ 'a', undefined, 'b' ]
复制代码
(3)アレイのようなオブジェクトの変換を
さらに、実際の配列にオブジェクトスライス方法、(例えば、引数オブジェクトとして)オブジェクトの類似配列の配列を使用することによって。
Array.prototype.slice.apply({0: 1, length: 1}) // [1]
Array.prototype.slice.apply({0: 1}) // []
Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
Array.prototype.slice.apply({length: 1}) // [undefined]
复制代码
(4)結合コールバックオブジェクト
次のように前の例のボタンクリックイベントは、書き換えることができます。
var o = new Object();
o.f = function () {
console.log(this === o);
}
var f = function (){
o.f.apply(o);
// 或者 o.f.call(o);
};
// jQuery 的写法
$('#button').on('click', f);
复制代码
3.バインド
バインド方法は、対象にインビボでこの機能を結合するために使用し、新しい機能を返しています。
var d = new Date();
d.getTime() // 1481869925657
var print = d.getTime;
print() // Uncaught TypeError: this is not a Date object.
复制代码
この問題を解決する方法をバインドします。
var print = d.getTime.bind(d);
print() // 1481869925657
复制代码
この方法は、この被験体に結合することにパラメータを結合することであり、以下では明確の一例です。
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var func = counter.inc.bind(counter);
func();
counter.count // 1
复制代码
これにバインドされ、他のオブジェクトが可能です。
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var obj = {
count: 100
};
var func = counter.inc.bind(obj);
func();
obj.count // 101
复制代码
バインドはまた、より多くのパラメータを受け入れることができ、これらのパラメータは、元の関数のパラメータをバインドします。
var add = function (x, y) {
return x * this.m + y * this.n;
}
var obj = {
m: 2,
n: 2
};
var newAdd = add.bind(obj, 5);
newAdd(5) // 20
复制代码
バインドメソッドの最初の引数がnullまたは未定義の、このグローバルオブジェクトにバインド等しい場合、関数この点は、トップレベルのオブジェクト(ブラウザウィンドウ)です。
function add(x, y) {
return x + y;
}
var plus5 = add.bind(null, 5);
plus5(10) // 15
复制代码
使用して、注意を払うためにいくつかのbindメソッドがあります。
(1)たびに新しい関数が戻ります
あなたがバインドメソッドを実行するたびに、それが問題を引き起こす可能性があり、新たな機能を、返します。たとえば、次のようにイベントを監視し、それが書かれてすることはできません。
element.addEventListener('click', o.m.bind(o));
复制代码
上記のコードは、イベントのバインド方法は、生成された無名関数をバインドします。次のコードは無効であるので、これは、アンバインドするためにつながることはありません。
element.removeEventListener('click', o.m.bind(o));
复制代码
次のように正しい方法は書かれています:
var listener = o.m.bind(o);
element.addEventListener('click', listener);
// ...
element.removeEventListener('click', listener);
复制代码
(2)コールバックの使用と併せて
JavaScriptのコールバック関数は、最も一般的なモデルの一つであるが、一般的な間違いは、ダイレクトコールバック関数として、この方法を含めることです。ソリューションは、バインドメソッドを使用することで、バインディングがカウンターcounter.incます。
var counter = {
count: 0,
inc: function () {
'use strict';
this.count++;
}
};
function callIt(callback) {
callback();
}
callIt(counter.inc.bind(counter));
counter.count // 1
复制代码
別の状況は、より微妙であるいくつかの方法は、関数のパラメータとして配列を受け入れることです。これらの内部関数この時点で、あなたはまた、間違っている可能性があります。
var obj = {
name: '张三',
times: [1, 2, 3],
print: function () {
this.times.forEach(function (n) {
console.log(this.name);
});
}
};
obj.print()
// 没有任何输出
复制代码
ほとんど変化がそれ、あなたがより明確に見ることができます。
obj.print = function () {
this.times.forEach(function (n) {
console.log(this === window);
});
};
obj.print()
// true
// true
// true
复制代码
このbindメソッドによって割り当てられているこの問題を解決するには。
obj.print = function () {
this.times.forEach(function (n) {
console.log(this.name);
}.bind(this));
};
obj.print()
// 张三
// 张三
// 张三
复制代码
(3)呼び出しに関連して使用する方法を
bindメソッドを使用すると、たとえば、メソッドの配列をスライスするネイティブJavaScriptメソッドのいくつかのフォームを使用するように書き換えることができます。
[1, 2, 3].slice(0, 1) // [1]
// 等同于
Array.prototype.slice.call([1, 2, 3], 0, 1) // [1]
复制代码
呼び出し方法は、本質的にコールFunction.prototype.call方法であるので、上記式は、バインド方法で書き換えることができます。
var slice = Function.prototype.call.bind(Array.prototype.slice);
slice([1, 2, 3], 0, 1) // [1]
复制代码
同様の表記法は、他の配列方法に使用することができます。
var push = Function.prototype.call.bind(Array.prototype.push);
var pop = Function.prototype.call.bind(Array.prototype.pop);
var a = [1 ,2 ,3];
push(a, 4)
a // [1, 2, 3, 4]
pop(a)
a // [1, 2, 3]
复制代码
さらに場合は、Function.prototype.bindオブジェクトにバインドするFunction.prototype.call方法は、それはまた、書き換え可能なバインドの形で呼び出すことを意味します。
function f() {
console.log(this.v);
}
var o = { v: 123 };
var bind = Function.prototype.call.bind(Function.prototype.bind);
bind(f, o)() // 123
复制代码
概要
- キーワードこれは、現在の動作環境の関数であり、
- ために機能するオペレーティング環境の変化に、これはまた、変動されています
- 関数の関数のメモリアドレスは、オブジェクトのメソッドとは独立しているのみ参照されるメモリ・アドレス
- この使用シナリオ:地球環境、コンストラクタ、オブジェクトメソッド
- 理由経営環境の変化のこの方法の目的は、この点を変更します
- そして、このネストされたコールバック関数は、ウィンドウオブジェクトは、多くの場合、ポイント
- 固定された中間値、2オペレーティング環境を結合:二つの方法のこの固定点。
- 呼び出して、適用、バインドは、この機能では、固定小数点を使用することができます
説明リンク
ます。https://juejin.im/post/5d06180d6fb9a07eab687f6eで再現