ES 6の矢印関数を深く理解する
6308 ワード
JavaScriptは、ES 6の矢印関数を深く理解する.
矢印関数式の構文は関数式より短く、自身のthis、argments、superまたはnew.targetをバインドしない.さらに、矢印関数は、非方法関数で使用した方がよく、構造関数としては使用できません.
構文
基礎文法
矢印関数の導入には二つの面の役割があります.一つはより短い関数で書き、もう一つはthisに対する語法解析です.
より短い関数
より短い関数は関数式プログラミングで人気があります.比較:
矢印関数が現れる前に、それぞれの新しい定義された関数にはそれぞれのthis値があります.例えば、構造関数のthisは新しいオブジェクトを指します.厳密なモードでの関数のthisはundefinedです.関数がオブジェクトとしての方法で呼び出された場合、そのオブジェクトにthisが呼び出されます.オブジェクト指向のプログラミングでは、多くの悩みがあります.
矢印関数は、そのコンテキストのthis値をキャプチャします.自分のthis値として、下記のコードは予定通り実行されます.
thisが語法的な面であることを考慮して、厳密なモードではthisに関する規則は無視されます.
コールまたはアップルを使って呼び出します.
thisは語法レベルでバインディングを完了したので、関数を
矢印関数は、その内部にパラメータ(argments):argments.length、argments[0]、argments[1]などを露出しません.矢印関数のargmentsを指すのではなく、矢印関数のある作用領域の一つを指しています.
上記のように、矢印関数式は非方法関数に最適です.方法として試してみたときに何が起こったかを見てみましょう.
矢印関数はコンストラクタとしては使えません.
矢印関数にはプロトタイプの属性がありません.
yieldキーは通常、矢印関数では使用できません.使用可能な関数内に入れ子がない限り、矢印関数はジェネレータとして使用できません.
関数本体
矢印関数は、簡単な書き込みと一般的な作成をサポートします.
簡略化するには、1つの表式と1つの戻り値だけが必要です.通常の作成には、明確な戻り値が必要です.
矢印関数はパラメータと矢印の間で改行できません.
矢印関数の矢印は操作子ではないですが、矢印関数には特殊な解析規則があります.普通の関数に比べて操作者の優先度によって影響されます.
GitHub:https://github.com/microzz 個人サイト:https://microzz.com/
矢印関数式の構文は関数式より短く、自身のthis、argments、superまたはnew.targetをバインドしない.さらに、矢印関数は、非方法関数で使用した方がよく、構造関数としては使用できません.
構文
基礎文法
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// : => { return expression; }
// , :
(singleParam) => { statements }
singleParam => { statements }
// :
() => { statements } _ => { statements }
高度な文法// , , :
params => ({foo: bar})
// Rest parameters default parameters:
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements }
//
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
説明矢印関数の導入には二つの面の役割があります.一つはより短い関数で書き、もう一つはthisに対する語法解析です.
より短い関数
より短い関数は関数式プログラミングで人気があります.比較:
var a = [
"Hydrogen",
"Helium",
"Lithium",
"Beryllium"
];
var a2 = a.map(function(s){ return s.length });
var a3 = a.map( s => s.length );
バインディングしない矢印関数が現れる前に、それぞれの新しい定義された関数にはそれぞれのthis値があります.例えば、構造関数のthisは新しいオブジェクトを指します.厳密なモードでの関数のthisはundefinedです.関数がオブジェクトとしての方法で呼び出された場合、そのオブジェクトにthisが呼び出されます.オブジェクト指向のプログラミングでは、多くの悩みがあります.
function Person() {
// Person() `this`
this.age = 0;
setInterval(function growUp() {
// ,growUp() `this` ,
Person() `this`
this.age++;
}, 1000);
}
var p = new Person();
// ECMAScript 3/5 , this ,
// 。
function Person() {
var self = this; // `that` `self`.
// .
self.age = 0;
setInterval(function growUp() {
// `self`
self.age++;
}, 1000);
}
これ以外にも、Bind関数を使用して、所望のthis値をgrowUp()
関数に伝達することができる.矢印関数は、そのコンテキストのthis値をキャプチャします.自分のthis値として、下記のコードは予定通り実行されます.
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // this person
}, 1000);
}
var p = new Person();
厳しいモードとの関係thisが語法的な面であることを考慮して、厳密なモードではthisに関する規則は無視されます.
var f = () => {'use strict'; return this};
f() === window; //
厳格なモードのその他の規則は依然として不変です.コールまたはアップルを使って呼び出します.
thisは語法レベルでバインディングを完了したので、関数を
call()
またはapply()
方法で呼び出すと、パラメータが入ってきただけで、thisには影響がありません.var adder = {
base : 1,
add : function(a) {
var f = v => v + this.base;
return f(a);
},
addThruCall: function(a) {
var f = v => v + this.base;
var b = {
base : 2
};
return f.call(b, a);
}
};
console.log(adder.add(1)); // 2
console.log(adder.addThruCall(1)); // 2( 3)
バインディングされていないパラメータ(argments)矢印関数は、その内部にパラメータ(argments):argments.length、argments[0]、argments[1]などを露出しません.矢印関数のargmentsを指すのではなく、矢印関数のある作用領域の一つを指しています.
var arguments = 42;
var arr = () => arguments;
arr(); // 42
function foo() {
var f = (i) => arguments[0]+i; // foo
return f(2);
}
foo(1); // 3
// arguments ,
// ,rest :
function foo() {
var f = (...args) => args[0];
return f(2);
}
foo(1); // 2
方法のように矢印関数を使います.上記のように、矢印関数式は非方法関数に最適です.方法として試してみたときに何が起こったかを見てみましょう.
'use strict';
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
}
}
obj.b(); // undefined, Window
obj.c(); // 10, Object {...}
// this 。
// Object.defineProperty(): :
'use strict';
var obj = {
a: 10
};
Object.defineProperty(obj, "b", {
get: () => {
console.log(this.a, typeof this.a, this);
return this.a+10;
// represents global object 'Window',
// therefore 'this.a' returns 'undefined'
}
});
new操作子を使う矢印関数はコンストラクタとしては使えません.
new
と一緒に使うとエラーが発生します.var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
原型の属性を使う矢印関数にはプロトタイプの属性がありません.
var Foo = () => {};
console.log(Foo.prototype); // undefined
キーワードを使うyieldキーは通常、矢印関数では使用できません.使用可能な関数内に入れ子がない限り、矢印関数はジェネレータとして使用できません.
関数本体
矢印関数は、簡単な書き込みと一般的な作成をサポートします.
簡略化するには、1つの表式と1つの戻り値だけが必要です.通常の作成には、明確な戻り値が必要です.
var func = x => x * x;
// return
var func = (x, y) => { return x + y; };
//
テキスト表式を返します.params => {object:literal}
という簡単な文法で文字式を返すのは無理だと覚えてください.var func = () => { foo: 1 };
// undefined!
var func = () => { foo: function() {} };
// SyntaxError: function statement requires a name( )
// ( {} )
//( , foo , )。
だから、丸括弧で文字表現を包んでください.var func = () => ({ foo: 1 });
行をかえる矢印関数はパラメータと矢印の間で改行できません.
var func = ()
=> 1; // SyntaxError: expected expression, got '=>'
解析の順序矢印関数の矢印は操作子ではないですが、矢印関数には特殊な解析規則があります.普通の関数に比べて操作者の優先度によって影響されます.
let callback;
callback = callback || function() {}; // ok
callback = callback || () => {};
// SyntaxError:
callback = callback || (() => {}); // ok
例// , undefined
let empty = () => {};
(() => "foobar")() // "foobar"
var simple = a => a > 15 ? 15 : a;
simple(16); // 15
simple(10); // 10
let max = (a, b) => a > b ? a : b;
// ( filter ), ( map ), ...
var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b); // 66
var even = arr.filter(v => v % 2 == 0);
// [6, 0, 18]
var double = arr.map(v => v * 2);
// [10, 12, 26, 0, 2, 36, 46]
// promise
promise.then(a => {
// ...
}).then(b => {
// ...
});
//
setTimeout( () => {
console.log('I happen sooner');
setTimeout( () => {
// deeper code
console.log('I happen later');
}, 1);
}, 1);
AboutGitHub:https://github.com/microzz 個人サイト:https://microzz.com/