JavaScriptでは予約語やkeywordを識別子(変数名)に使える状況が多々あります(過言)。どういう事でしょうか?
予約語
識別子として使用不可なものは break,case,catch,class,const,continue,debugger,default,delete,do,else,export,extends,false,finally,for,function,if,import,in,instanceof,new,null,return,super,switch,this,throw,true,try,typeof,var,void,while,with。
それに加え厳格("use strict")な場所で使用不可になるものは let、static、yield。
letはletやconstで宣言する時とclass定義内でも予約語。
staticはclass定義内でも予約語。
yieldはGenerator関数本体でも予約語。
//let
function _(){var let=0}
function _(){let let=0}//error
function _(){const let=0}//error
function _(){"use strict";var let=0}//error
class _{constructor(){var let=0}}//error
//yield
function _(){var yield=0}
function*_(){var yield=0}//error
function _(){"use strict";var yield=0}//error
//static
var static=0;
function _(){"use strict";var static=0}//error
class _{constructor(){var static=0}}//error
awaitは非同期関数内やmodule内で予約語。
function _(){var await=0}
async function _(){var await=0}//error
<script type=module>
var await=0//error
</script>
特別な識別子
arguments、as、async、eval、fom、get、of、setはkeywordでなくても、ある文脈で特別な意味を持つ
実践編
of祭り
let of=[of=>of=>of];
for(of of of)of(of)(of);
for([]of[]);
for([]of[,]);//error
async祭り
let async=async function async(async=async=>async){return++async}
object
//化石Browserでは動作しかねる
let a={let:0,var:0,const:0,function:0,return:0,
do:0,for:0,while:0,break:0,continue:0,
with:0,if:0,else:0,try:0,catch:0,finally:0,
switch:0,case:0,default:0,
class:0,extends:0,debugger:0,super:0,
new:0,delete:0,in:0,instanceof:0,void:a=>a,
throw:0,export:0,import:0,true:0,false:0,this:0,null:0
};
a.void(0);
a.let++;a.if++;a.this++;
何が優先されるかな?
with祭り
with({if:a=>console.log(a)})if(1);
with({do:a=>console.log(a),while:a=>console.log(a)}){do(0);while(0)}
with({typeof:a=>typeof(a)})console.log(typeof(0)=="string");
with({void:a=>b=a,b:1})void(0),console.log(b);
(function*(a){with({yield:a=>console.log(a)})yield(a)})(0);
(async function(a){with({await:a=>console.log(a)})await(a)})(0);