JavaScript 上級
これはルールを指します
場合
function foo() {
console.log(this)
}
// 1 调用方式1
foo();
// 2 调用方式2 放入对象中调用
var obj = {
name: "why",
foo: foo
}
obj.foo()
// 调用方式三 通过 call/apply 调用
foo.call("abc")
定義を指す
これは、js によって関数に与えられるバインディング値です。
- 関数が呼び出されると、JavaScript はデフォルトで値をこれにバインドします。
- this のバインディングは、定義の場所 (記述場所) とは何の関係もありません。
- this のバインディングは、呼び出しメソッドと呼び出し場所に関連します。
- これは実行時にバインドされます
非厳密モードではウィンドウとなり、厳密モードがオンの場合は udnefined になります。
このための拘束ルールは次のとおりです。
-
バインディング 1: デフォルトのバインディング PS: どのオブジェクトにもバインドされておらず、関数がオブジェクト内で定義されているが独立して呼び出され、オブジェクトもウィンドウである場合
-
バインディング 2: 暗黙的なバインディング PS: オブジェクトを指す呼び出し元オブジェクトに JS によってバインドされます。
-
バインディング 3: 新しいバインディング
- 新しい実行プロセス
- 1 空のオブジェクトを作成する
- 2 空のオブジェクトを指すようにこれを変更します。
- 3 関数本体コードを実行する
- このオブジェクトは、空ではないオブジェクトを返す表示がない場合にデフォルトで返されます。
-
バインディング 4 ショー バインディング
-
オブジェクト内にこの関数への参照を含めたくないが、同時にこのオブジェクトに対して強制呼び出しを行いたい場合
-
function foo() { console.log(this) } var obj = { name: "why", foo: foo } foo.call(123) console 输出内容 { name: 'why', foo: ƒ}
-
call/apply はこの効果を達成するのに役立ちます
-
追加機能の追加
Call/Apply 呼び出しメソッドに大きな違いはありませんが、微妙な違いがあります。
apply
:
function foo(name, age, height) {
console.log("foo 函数this 指向", this);
console.log("参数:", name, age, height);
}
// 普通调用 直接入参
foo("why", 18, 1.22)
// apply
// 第一个参数 绑定 this
// 第二个参数 传入额外的实参 以数组的形式
// foo.apply("apply",["why", 18, 1.22])
foo.apply("123", ["why", 18, 1.22])
call
:
function foo(name, age, height) {
console.log("foo 函数this 指向", this);
console.log("参数:", name, age, height);
}
// call
// 第一个参数 绑定 this
// 后续参数以 参数列表形式
foo.call("call", "远目鸟", 18, 12)
この 2 つの点は、呼び出し側メソッドの最初のパラメータがこれを指しているという点で同じですが、唯一の違いは、渡される後続のパラメータの形式のみです。
- apply は配列です
,
call は次のように分割されたリストです
bind
: バインディング関数を作成します。foo を呼び出すときは、常に obj を指すようにしてください。
function foo() {
console.log("foo 函数this 指向", this);
}
var obj = {
name: "why"
}
// 需求 调用foo时 总是绑定 obj
var bar = foo.bind(obj)
bar()
bind() を呼び出すと、bind() の最初のパラメータとして新しい関数のこれが指定され、残りのパラメータは呼び出し時に使用する新しい関数のパラメータとして使用されます。実際の開発ではあまり使用されないので参考程度にどうぞ。
組み込み関数
一般的に、ブラウザの組み込み機能やサードパーティのフレームワークのポインタについては、ソース コードやドキュメントを 1 つずつ表示することが非現実的かどうかは経験に基づいて判断するしかありません。
この優先順位は
- デフォルトのバインディング優先度は最も低いです
- 明示的バインディングは暗黙的バインディングよりも上位です
- new は暗黙的なバインディングよりも上位です PS: new は call/apply では使用できません
- 新しいバインディングはバインドよりも優先されます
- 明示的バインドと同じですが、呼び出し/適用よりも優先度が高くなります。
拡張:ルール外
**ケース 1:** 表示バインディングに null または未定義を渡すと、表示バインディングは無視され、デフォルトのルールが使用されます。
function foo() {
console.log("foo 函数this 指向", this);
}
var obj = {
name: "why"
}
foo.call(obj)
foo.call(null)
foo.call(undefined)
var bar = foo.bind(obj)
bar()
ただし、厳密モードをオンにすると、基本プロパティを使用して null または未定義を直接表示できます。
**ケース 2:** 関数への間接参照を作成する この場合、デフォルトのバインド ルールが使用されます。
- この場合 (obj2.foo = obj1.foo) は、ウィンドウを指すデフォルトのルールを使用します。
var obj1 = {
name: "obj1",
foo: function () {
console.log("foo 函数this 指向", this);
}
}
var obj2 = {
name: "obj2"
};
obj1.foo();
(obj2.foo = obj1.foo)();
**ケース 3:**アロー関数
- アロー関数は this 属性と argument 属性をバインドしません。
- アロー関数はコンストラクターとして使用できません
// {} 是执行体
var arrFn = () => {
}
// 指向的是对象 需要加小括号才可以做到
var arrFn = () => ({
name: "why" })
アロー関数
-
基本的な書き方
-
(): 関数パラメータ
-
{}: 関数の実行本体
-
var foo3 = (name, age) => { console.log("箭头函数的函数体") console.log(name, age) }
-
-
書き込みの最適化
-
パラメータが1つの場合、()は省略可能
names.forEach(item => { console.log(item) })
-
コードが 1 行のみの場合は、{} を省略できます
names.forEach(item => console.log(item))
-
コードが 1 行の場合、式の戻り値はアロー関数のデフォルトの戻り値になるため、return は省略できます。
var newNums = nums.filter(item => item % 2 === 0) var newNums = nums.filter(item => item % 2 === 0)
-
アロー関数がデフォルトでオブジェクトを返す場合、{} を省略すると、オブジェクトを () => ({name: “why”}) で囲む必要があります。
var arrFn = () => ["abc", "cba"] var arrFn = () => {} // 注意: 这里是{}执行体 var arrFn = () => ({ name: "why" }) console.log(arrFn())
-
アロー関数は、this の 4 つの標準ルールを使用しません (つまり、this をバインドしません) が、外側のスコープに基づいてこれを決定します。
ネットワーク リクエストをシミュレートする例を見てみましょう。
- ここでは setTimeout を使用してネットワーク リクエストをシミュレートしていますが、リクエスト後にデータを data に保存するにはどうすればよいですか?
- obj オブジェクトを取得してデータを設定する必要があります。
- ただし、直接取得する this は window なので、外側の層で定義する必要があります: var _this = this
- setTimeout のコールバック関数で _this を使用すると、obj オブジェクトを表します
- しかし、特性に応じてアロー関数を使用すると、this を上向きに検索するため、_this = this という操作が不要になります。
var obj = {
data: [],
getData: function () {
request("/11", (res) => {
this.data = [].concat(res)
})
}
}
function request(url, callbackFn) {
var res = ["abc", "cba", "nba"]
callbackFn(res)
}
obj.getData()
要約する
- このポインティングの問題と優先順位はJSへの登竜門であり、仕組みを理解してから使用しないと変なエラーが発生する可能性があります。
- ES6 構文のアロー関数を使用して、ES6 構文に事前に慣れておくと、開発効率が向上します。