ダイナミックスコープって?
◆ ダイナミックスコープは 実行した場所でスコープが決まる
◆ レキシカルスコープは定義した場所でスコープが決まる
◆ レキシカルスコープは定義した場所でスコープが決まる
JavaScriptはレキシカルスコープですよね
なんかダイナミックスコープというのを目にしてなんだろうそれっと調べてみました
レキシカルスコープは 日本語だと静的スコープと言われるようです
関数を定義した場所でスコープが決まります
関数cは関数bの中で定義されてるのでxの値をみることができます
b() で関数cが返って来て それを実行することで xの値10が返って来ます
ダイナミックスコープは 動的スコープと言われて 関数を実行した場所でスコープが決まるようです
上の例だと b() の返り値を受け取ってるところは 関数aの中です
ここでは xは定義されていません
なので もしJavaScriptがダイナミックスコープだと b()() とやって 関数cを実行するとxが未定義エラーということになります
こう見ると不便そうですけど 同じ関数が実行する場所によって参照できる変数が変わる仕組みって使いこなせればとても便利そうに思えます
なのに 扱いづらいからと人気がなくて 一部のLisp方言でしか使われてないんだとか
いい例とは言えないかもですが こういうことができるようになるんですよね
レキシカルスコープなJavaScriptだと expand関数内でevalしても g は参照できないのでevalを呼び出し元でするという気持ちの悪いことになります
「eval 使ってる時点で」 とか 「strが展開できない」 とかいうのはこの際おいてといてください
関数ごとにレキシカルスコープかダイナミックスコープか選べるとすごく便利そうなんですが 実装コストが高いのか 需要が少ないのか そういう言語があるって聞かないですね
ところでダイナミックスコープ調べてる時に見つけた「んん??」と思ったこと
言語ごとにスコープがどうなってるのか書いていて
「JavaScriptはレキシカルスコープなのでこうなります」
「●●だとこうなります」(何だったか覚えてなくて 確か読めるけど書けない言語だったのでJavaScriptで代わりにかいてます)
え??
その書き方じゃ レキシカルスコープの言語でも100がでますよ?!
他の言語はちゃんとかけてるのになぜここだけこうなった……
素で書き間違ってたんだと思いますけど こういう情報を調べるときは ちゃんと読んでみたり実行してみたりしないとダメですね
このブログだって100%バッチリです とはいえないので注意してくださいね
なんかダイナミックスコープというのを目にしてなんだろうそれっと調べてみました
レキシカルスコープは 日本語だと静的スコープと言われるようです
関数を定義した場所でスコープが決まります
(function a(){
function b(){
var x = 10
return function c(){
return x
}
}
b()() // 10
})()
よくあるこういうのfunction b(){
var x = 10
return function c(){
return x
}
}
b()() // 10
})()
関数cは関数bの中で定義されてるのでxの値をみることができます
b() で関数cが返って来て それを実行することで xの値10が返って来ます
ダイナミックスコープは 動的スコープと言われて 関数を実行した場所でスコープが決まるようです
上の例だと b() の返り値を受け取ってるところは 関数aの中です
ここでは xは定義されていません
なので もしJavaScriptがダイナミックスコープだと b()() とやって 関数cを実行するとxが未定義エラーということになります
こう見ると不便そうですけど 同じ関数が実行する場所によって参照できる変数が変わる仕組みって使いこなせればとても便利そうに思えます
なのに 扱いづらいからと人気がなくて 一部のLisp方言でしか使われてないんだとか
いい例とは言えないかもですが こういうことができるようになるんですよね
function expand(str){
var str = ('"'+str+'"').replace(/\{([a-zA-Z0-9\-\_\$]+)\}/g, function(_, match){
return '"+' + match + '+"'
})
return eval(str);
}
function fn(g){
var a = expand("argument is {g}")
}
変数展開をしたいって時に 変数名の入った文字列さえ渡して関数を実行すれば スコープ上呼び出し元の変数を参照できるので文字列結合に置換してevalすれば変数展開された文字列が返せるわけですvar str = ('"'+str+'"').replace(/\{([a-zA-Z0-9\-\_\$]+)\}/g, function(_, match){
return '"+' + match + '+"'
})
return eval(str);
}
function fn(g){
var a = expand("argument is {g}")
}
レキシカルスコープなJavaScriptだと expand関数内でevalしても g は参照できないのでevalを呼び出し元でするという気持ちの悪いことになります
「eval 使ってる時点で」 とか 「strが展開できない」 とかいうのはこの際おいてといてください
関数ごとにレキシカルスコープかダイナミックスコープか選べるとすごく便利そうなんですが 実装コストが高いのか 需要が少ないのか そういう言語があるって聞かないですね
ところでダイナミックスコープ調べてる時に見つけた「んん??」と思ったこと
言語ごとにスコープがどうなってるのか書いていて
「JavaScriptはレキシカルスコープなのでこうなります」
var z = 100
function x(z){
return function y(){
return z
}
}
x(10)() // 10
うん そうだよねfunction x(z){
return function y(){
return z
}
}
x(10)() // 10
「●●だとこうなります」(何だったか覚えてなくて 確か読めるけど書けない言語だったのでJavaScriptで代わりにかいてます)
var z = 100
function x(n){
return y
}
function y(){
return z
}
x(10)() // 100
「この言語はレキシカルスコープじゃないですね」function x(n){
return y
}
function y(){
return z
}
x(10)() // 100
え??
その書き方じゃ レキシカルスコープの言語でも100がでますよ?!
他の言語はちゃんとかけてるのになぜここだけこうなった……
素で書き間違ってたんだと思いますけど こういう情報を調べるときは ちゃんと読んでみたり実行してみたりしないとダメですね
このブログだって100%バッチリです とはいえないので注意してくださいね