Chromeでアロー関数とPromiseが使えた
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
Chrome でアロー関数と Promise がつかえるようになっていました
ということで 少し使ってみました
ということで 少し使ってみました
アロー関数は chrome45 から使えます
Promise はいつから詳しくわからないですが Chrome44では使えました
map とかの引数に関数を書くときに便利です
無名関数って 中身が1つの式で return することが多いと思いますが 複数の式を書きたい場合もあります
そういうときは {} を使います
逆にいうと返り値がいらないときは {} で囲めばいいです
短く書けるようになるだけじゃなくて いくつか違いもあるので アロー関数で置き換わるのじゃなくて function での関数定義と両方を使っていくことになると思います
アロー関数だと this が関数の外側と一緒になります
さらに this の値は実行する場所で変わらないです
関数が作られたところの this にずっと固定になります
obj.afn を作った時の this は window です
obj.fn のように this が obj にはなりません
function でつくると fn2 のようにプロパティに入れて 実行する場所を変えれば this も変わります
アロー関数では obj.afn2 のようにグローバルに持ってきても this は obj から変わらないです
なので
this を特別扱いにしないで 普通にレキシカルスコープとして定義されたところから見える this を見ると考えればわかりやすいかもしれません
アロー関数では arguments が作られないので 外側の arguments が見れます
グローバルだと定義されていないのでエラーになります
こっちも arguments を特別扱いせずに定義されたところの外側の arguments がレキシカルスコープなので見れると考えればいいと思います
Firefox では昔からアロー関数が使えましたがアロー関数でも arguments が作られてしまっていて arguments が外側の見れるようになったのは最近だったと思います
map などのメソッドに渡すような中身の短い関数では arguments も this もそのままであってほしいことが多いので 使いやすくされてますね
ほとんどの場合では アロー関数で良さそうですが function で関数定義しないといけないときもあります
一番よくあるのは prototype にメソッドを追加する時かと思います
とりあえず new します
さすがにこれはどう使うのか知らないとどうしようもなかったので軽くググッてみました
最初に実行する関数をコンストラクタに渡すようです
コンストラクタに渡した 引数の関数自体も setTimeout のように非同期実行されると書いてるところもありましたがそんなことはなく new したら即実行されます
↑の結果でも返り値よりさきに 「promise」 がでてますし
Promise では返り値のオブジェクトに対して then や catch のメソッドで完了したら次に何をやるかをチェーンさせます
イメージはこんな感じです…… がこれじゃいつまでまっても 「promise」 しかでません
最初に引数で渡した関数は 2つの引数を与えられて実行されます
1つめは 成功したときに呼べばいい関数
2つめは 失敗したときに呼べば良い関数です
1つめを resolve 2つめを reject と書くことが多いですが 引数の名前なので好きに決めても大丈夫です
逆に catch する方を先に呼んでみます
成功か失敗した関数を呼んだ時に then や catch が無くても大丈夫です
then をつけたときに成功関数が呼ばれると実行されます
try catch がなくても エラーがあると catch が実行されます
エラーが起きる p2.then() の返り値 p3 に対して catch メソッドをつけていないときや p3.then() をつけていると
最初の関数で第二引数の関数(reject の方)を実行していて catch なしでもエラーが出ます
Promise はまだまだ機能があって複雑そうですので とりあえず今回はこの辺にしておきます
Promise はいつから詳しくわからないですが Chrome44では使えました
アロー関数
私的には これが一番 Ecma6 の大きい機能ですvar fn = function (e){return e*e}
をvar fn = e => e*e
と書けますmap とかの引数に関数を書くときに便利です
> [1,2,3,4,5].map(e=>e*e).reduce((a,b)=>a+b)
< 55
< 55
無名関数って 中身が1つの式で return することが多いと思いますが 複数の式を書きたい場合もあります
そういうときは {} を使います
var fn = (a,b) =>{
var t = a + b
return t
}
fn(100,200) // 300
{} があると return が必要ですvar t = a + b
return t
}
fn(100,200) // 300
逆にいうと返り値がいらないときは {} で囲めばいいです
var fn = e => {e.pop()}
fn([1,2,3]) // undefined
fn([1,2,3]) // undefined
短く書けるようになるだけじゃなくて いくつか違いもあるので アロー関数で置き換わるのじゃなくて function での関数定義と両方を使っていくことになると思います
this が変わらない
今まで無名関数の中に入ると this が変わってしまうので bind したり that や self と言った変数に this を退避させておかないとダメでしたvar obj = {
fn: function(val){
var self = this
console.log(this.data)
console.log("bind なし")
val.forEach(function(e){
console.log(this === window)
console.log("this.data", this.data)
console.log("self.data", self.data)
})
console.log("bind あり")
val.forEach(function(e){
console.log(this === window)
console.log("this.data", this.data)
console.log("self.data", self.data)
}.bind(this))
},
data : 100
}
obj.fn([1])
fn: function(val){
var self = this
console.log(this.data)
console.log("bind なし")
val.forEach(function(e){
console.log(this === window)
console.log("this.data", this.data)
console.log("self.data", self.data)
})
console.log("bind あり")
val.forEach(function(e){
console.log(this === window)
console.log("this.data", this.data)
console.log("self.data", self.data)
}.bind(this))
},
data : 100
}
obj.fn([1])
100
bind なし
true
this.data undefined
self.data 100
bind あり
false
this.data 100
self.data 100
function の無名関数は何かのメソッド(オブジェクトのプロパティ)じゃないので 関数内では this が window になりますbind なし
true
this.data undefined
self.data 100
bind あり
false
this.data 100
self.data 100
アロー関数だと this が関数の外側と一緒になります
さらに this の値は実行する場所で変わらないです
関数が作られたところの this にずっと固定になります
var obj = {
afn: () => this,
fn: function (){return this},
afn2: function(){return ()=>this}
}
console.log(obj.afn() === window) // true
console.log(obj.fn() === obj) // true
var fn2 = function(){return this}
console.log(fn2() === window) // true
obj.fn2 = fn2
console.log(obj.fn2() === obj) // true
var fn = obj.afn2()
console.log(fn() === obj) // true
こんな感じですafn: () => this,
fn: function (){return this},
afn2: function(){return ()=>this}
}
console.log(obj.afn() === window) // true
console.log(obj.fn() === obj) // true
var fn2 = function(){return this}
console.log(fn2() === window) // true
obj.fn2 = fn2
console.log(obj.fn2() === obj) // true
var fn = obj.afn2()
console.log(fn() === obj) // true
obj.afn を作った時の this は window です
obj.fn のように this が obj にはなりません
function でつくると fn2 のようにプロパティに入れて 実行する場所を変えれば this も変わります
アロー関数では obj.afn2 のようにグローバルに持ってきても this は obj から変わらないです
なので
var obj = {
fn: function(val){
val.forEach(e => {this.data += e})
},
data: 0
}
obj.fn([2,3,4])
obj.data // 9
こういうことができますfn: function(val){
val.forEach(e => {this.data += e})
},
data: 0
}
obj.fn([2,3,4])
obj.data // 9
this を特別扱いにしないで 普通にレキシカルスコープとして定義されたところから見える this を見ると考えればわかりやすいかもしれません
arguments が作られない
this 以外に arguments の扱いも違いますアロー関数では arguments が作られないので 外側の arguments が見れます
グローバルだと定義されていないのでエラーになります
var fn = ()=> arguments
fn(1,2)
Uncaught ReferenceError: arguments is not defined(…)
var fn2 = ()=>()=>()=>arguments
fn2()()()
Uncaught ReferenceError: arguments is not defined(…)
function fn3(){
(()=>{console.log(arguments)})()
}
fn3(1,2,3)
// [1, 2, 3]
function fn4(){
return ()=>arguments
}
fn4(1,2,3,4)()
// [1, 2, 3, 4]
fn(1,2)
Uncaught ReferenceError: arguments is not defined(…)
var fn2 = ()=>()=>()=>arguments
fn2()()()
Uncaught ReferenceError: arguments is not defined(…)
function fn3(){
(()=>{console.log(arguments)})()
}
fn3(1,2,3)
// [1, 2, 3]
function fn4(){
return ()=>arguments
}
fn4(1,2,3,4)()
// [1, 2, 3, 4]
こっちも arguments を特別扱いせずに定義されたところの外側の arguments がレキシカルスコープなので見れると考えればいいと思います
Firefox では昔からアロー関数が使えましたがアロー関数でも arguments が作られてしまっていて arguments が外側の見れるようになったのは最近だったと思います
map などのメソッドに渡すような中身の短い関数では arguments も this もそのままであってほしいことが多いので 使いやすくされてますね
ほとんどの場合では アロー関数で良さそうですが function で関数定義しないといけないときもあります
一番よくあるのは prototype にメソッドを追加する時かと思います
Array.prototype.last = function(){return this[this.length-1]}
これを アロー関数にしてしまうと 配列の last メソッドを呼んだ時の this が window なので 配列とは全く関係ない ページ内にある最後のフレームの window か undefined が返ってくることになりますPromise
非同期処理が便利になるというやつですとりあえず new します
new Promise()
Uncaught TypeError: Promise resolver undefined is not a function(…)
エラーですUncaught TypeError: Promise resolver undefined is not a function(…)
さすがにこれはどう使うのか知らないとどうしようもなかったので軽くググッてみました
最初に実行する関数をコンストラクタに渡すようです
> new Promise(function(){console.log("promise")})
promise
< Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
返り値は Promise オブジェクトというまた特殊なものですpromise
< Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
コンストラクタに渡した 引数の関数自体も setTimeout のように非同期実行されると書いてるところもありましたがそんなことはなく new したら即実行されます
↑の結果でも返り値よりさきに 「promise」 がでてますし
Promise では返り値のオブジェクトに対して then や catch のメソッドで完了したら次に何をやるかをチェーンさせます
イメージはこんな感じです…… がこれじゃいつまでまっても 「promise」 しかでません
new Promise(function(){console.log("promise")})
.then(function(){console.log("then")})
.catch(function(){console.log("catch")})
.then(function(){console.log("then")})
.catch(function(){console.log("catch")})
最初に引数で渡した関数は 2つの引数を与えられて実行されます
new Promise(function(a,b){console.log(a,b)})
function () { [native code] } funciton () { [native code] }
まったくなにやってるかわからないですね1つめは 成功したときに呼べばいい関数
2つめは 失敗したときに呼べば良い関数です
1つめを resolve 2つめを reject と書くことが多いですが 引数の名前なので好きに決めても大丈夫です
new Promise(function(success, fail){
console.log("promise")
success("success")
fail("fail")
})
.then(function(){console.log("then", ...arguments)})
.catch(function(){console.log("catch", ...arguments)})
console.log("promise")
success("success")
fail("fail")
})
.then(function(){console.log("then", ...arguments)})
.catch(function(){console.log("catch", ...arguments)})
promise
then success
両方実行しても最初の方に対応した関数が実行されてますthen success
逆に catch する方を先に呼んでみます
new Promise(function(success, fail){
console.log("promise")
fail("fail")
success("success")
})
.then(function(){console.log("then", ...arguments)})
.catch(function(){console.log("catch", ...arguments)})
console.log("promise")
fail("fail")
success("success")
})
.then(function(){console.log("then", ...arguments)})
.catch(function(){console.log("catch", ...arguments)})
promise
catch fail
then の方は実行されてませんcatch fail
成功か失敗した関数を呼んだ時に then や catch が無くても大丈夫です
then をつけたときに成功関数が呼ばれると実行されます
var p = new Promise(function(success, fail){
console.log("promise")
success("success")
})
setTimeout(function(){
p.then(function(){
console.log("then")
})
console.log("add then")
}, 1000);
console.log("promise")
success("success")
})
setTimeout(function(){
p.then(function(){
console.log("then")
})
console.log("add then")
}, 1000);
promise
(1秒後)
add then
then
このときは then を実行したときに 関数が呼ばれるのじゃなくて 非同期でいったん実行中の処理が終わってから then で設定した関数が呼ばれます(1秒後)
add then
then
try catch がなくても エラーがあると catch が実行されます
var p = new Promise(function(s, f){
s()
})
var p2 = p.then(function(){
console.log("then1")
})
p.catch(function(){
console.log("catch1")
})
var p3 = p2.then(function(){
console.log("then2")
console.log(null.a)
console.log("then2-2")
})
p2.catch(function(){
console.log("catch2")
})
p3.catch(function(){
console.log("catch3")
})
s()
})
var p2 = p.then(function(){
console.log("then1")
})
p.catch(function(){
console.log("catch1")
})
var p3 = p2.then(function(){
console.log("then2")
console.log(null.a)
console.log("then2-2")
})
p2.catch(function(){
console.log("catch2")
})
p3.catch(function(){
console.log("catch3")
})
then1
then2
catch3
then2
catch3
エラーが起きる p2.then() の返り値 p3 に対して catch メソッドをつけていないときや p3.then() をつけていると
Uncaught (in promise) TypeError: Cannot read property 'a' of null(…)
とエラーが出ます最初の関数で第二引数の関数(reject の方)を実行していて catch なしでもエラーが出ます
var p = new Promise(function(s, f){
f()
})
Uncaught (in promise) undefined
f()
})
Uncaught (in promise) undefined
Promise はまだまだ機能があって複雑そうですので とりあえず今回はこの辺にしておきます