(a ==1 && a== 2 && a==3)
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ stackoverflow のクイズ
◆ 色々方法あって楽しめた
◆ 色々方法あって楽しめた
今週話題になってたらしい クイズ?
JavaScript で (a ==1 && a== 2 && a==3) を true にする方法
暇つぶしに はてなブックマークのホットエントリー を眺めていたら見つけたページで stackoverflow のページがありました
https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true
普通に考えたら できなそうですが JavaScript だと toString とか valueOf とかで関数実行できるし 簡単にいけるんじゃない?と思って回答を見てみると当たりでした
ただ valueOf と toString どっちだったか自信なくて
両方かけば動くだろうけど~ 本命は~ たぶん valueOf ? と言う感じでギリギリ感あります
答えは 片方だけならどっちでも動きます
両方つけた場合は valueOf が優先されます
両方あって valueOf がオブジェクトだとさらに toString も呼ばれます
↑の _ のところが変数にできる空白文字
ハングルらしいです
問題が (a ==1 && a== 2 && a==3) とわざとなのか偶然なのか 1 つめの a のあとだけスペースがあるからこそですね
一応スペースがなくても JavaScript の変数名には ZWNJ が使えるので見えない空白文字があると仮定して 3 つの変数を用意することもできます
ZWNJ というのは ZeroWidthNonJoiner という幅のない見えない文字です
コードにすると
\u200c が ZWNJ です
わかりやすく \u200c と書いていますが code を出力すると
となって ZWNJ があるかどうかは見分けがつきません
ただ グローバルと仮定すれば別回答にある window のプロパティ a に getter を付けるだけでもできます
こっちだと strict モードで with が禁止されていても大丈夫ですね
変数を 3 つ用意する方法や getter の方法だと 同じ型にできるので == でなく === でも大丈夫です
一見 valueOf も toString も書き換えてないのでどうなってるのだろうと不思議に思える方法です
JavaScript は色々書き方があっておもしろい言語ですよね
案の定コメントにはダメな言語とか書いてる人がいますが 出来る人ほどこういう裏技っぽいものに興味を持って利用して何か作ってみようとしてると思います
言語をダメと言ってるようで実際のところは自分には使いこなせないです 扱いきれませんと言ってるようなものですしね
toString/valueOf は普通に使う分にはあまり触れることないところですが変なもの作ってみようってときにはいじってみるといいと思います
http://2ality.com/2011/12/fake-operator-overloading.html
こんなこともできたりね
ただ 実際に役立つ使い方 というと
== じゃなくて === でも使えて (== は特別理由ないときはできるだけ使わない方がいい)
strict mode でも使える (将来的に module は強制 strict だから)
defineProperty?
なんか面白くない普通なものになりました
逆に使うと一番後悔するのは見えない変数文字でしょうね
まだ空白があるハングルのだといいですが ZWNJ なんか使い始めると もうどこにあるのかわからないですから
しかもコピペしたときにエディタによっては消されて なぜか動かなくなることもあったりで……
昔は CodeIQ (だっけ?) でやってたこんな感じの JavaScript クイズが好きでよくやってましたが久しぶりにやってみたくなりました
JavaScript で (a ==1 && a== 2 && a==3) を true にする方法
暇つぶしに はてなブックマークのホットエントリー を眺めていたら見つけたページで stackoverflow のページがありました
https://stackoverflow.com/questions/48270127/can-a-1-a-2-a-3-ever-evaluate-to-true
valueOf/toString
(a ==1 && a== 2 && a==3) を評価して true にすればいいようです普通に考えたら できなそうですが JavaScript だと toString とか valueOf とかで関数実行できるし 簡単にいけるんじゃない?と思って回答を見てみると当たりでした
ただ valueOf と toString どっちだったか自信なくて
両方かけば動くだろうけど~ 本命は~ たぶん valueOf ? と言う感じでギリギリ感あります
答えは 片方だけならどっちでも動きます
var _a = 1
var a = {
valueOf(){return _a++}
}
console.log(a == 1 && a == 2 && a == 3)
// true
var a = {
valueOf(){return _a++}
}
console.log(a == 1 && a == 2 && a == 3)
// true
var _a = 1
var a = {
toString(){return _a++}
}
console.log(a == 1 && a == 2 && a == 3)
// true
var a = {
toString(){return _a++}
}
console.log(a == 1 && a == 2 && a == 3)
// true
両方つけた場合は valueOf が優先されます
var obj = {
valueOf(){
console.log("valueOf")
return 1
},
toString(){
console.log("toString")
return "1"
}
}
console.log(obj == "1")
// valueOf
// true
valueOf(){
console.log("valueOf")
return 1
},
toString(){
console.log("toString")
return "1"
}
}
console.log(obj == "1")
// valueOf
// true
両方あって valueOf がオブジェクトだとさらに toString も呼ばれます
var obj = {
valueOf(){
console.log("valueOf")
return {}
},
toString(){
console.log("toString")
return "1"
}
}
console.log(obj == "1")
// valueOf
// toString
// true
valueOf(){
console.log("valueOf")
return {}
},
toString(){
console.log("toString")
return "1"
}
}
console.log(obj == "1")
// valueOf
// toString
// true
変数を 3 つ用意する
他にも a の前後のスペースに統一性がないので 変数名にできる空白をつけて 3 つの異なる変数を作っていたり 面白い回答もあって楽しめましたvar a_ = 1
var a = 2
var _a = 3
var a = 2
var _a = 3
↑の _ のところが変数にできる空白文字
ハングルらしいです
問題が (a ==1 && a== 2 && a==3) とわざとなのか偶然なのか 1 つめの a のあとだけスペースがあるからこそですね
一応スペースがなくても JavaScript の変数名には ZWNJ が使えるので見えない空白文字があると仮定して 3 つの変数を用意することもできます
ZWNJ というのは ZeroWidthNonJoiner という幅のない見えない文字です
コードにすると
var code = `
var a = 1
var a\u200c = 2
var a\u200c\u200c = 3
console.log(a == 1 && a\u200c == 2 && a\u200c\u200c == 3)
`
eval(code)
// true
var a = 1
var a\u200c = 2
var a\u200c\u200c = 3
console.log(a == 1 && a\u200c == 2 && a\u200c\u200c == 3)
`
eval(code)
// true
\u200c が ZWNJ です
わかりやすく \u200c と書いていますが code を出力すると
var a = 1
var a = 2
var a = 3
console.log(a == 1 && a == 2 && a == 3)
var a = 2
var a = 3
console.log(a == 1 && a == 2 && a == 3)
となって ZWNJ があるかどうかは見分けがつきません
getter
また あまり使う機会がないので全く思いつかなかったのですが a プロパティに getter 付けたオブジェクトを with する方法もありましたvar _a = 1
with ({get a(){return _a++}}){
console.log(a == 1 && a == 2 && a == 3)
}
// true
with ({get a(){return _a++}}){
console.log(a == 1 && a == 2 && a == 3)
}
// true
ただ グローバルと仮定すれば別回答にある window のプロパティ a に getter を付けるだけでもできます
こっちだと strict モードで with が禁止されていても大丈夫ですね
var _a = 1
Object.defineProperty(window, "a", {
get(){
return _a++
}
})
console.log(a == 1 && a == 2 && a == 3)
// true
Object.defineProperty(window, "a", {
get(){
return _a++
}
})
console.log(a == 1 && a == 2 && a == 3)
// true
変数を 3 つ用意する方法や getter の方法だと 同じ型にできるので == でなく === でも大丈夫です
valueOf 2
valueOf を使う方法は他にもあって 配列の valueOf では join メソッドが呼び出されることを利用して join プロパティを shift に置き換えて自身の値を更新しますvar a = [1, 2, 3]
a.join = a.shift
console.log(a == 1 && a == 2 && a == 3)
// true
a.join = a.shift
console.log(a == 1 && a == 2 && a == 3)
// true
一見 valueOf も toString も書き換えてないのでどうなってるのだろうと不思議に思える方法です
JavaScript は色々書き方があっておもしろい言語ですよね
案の定コメントにはダメな言語とか書いてる人がいますが 出来る人ほどこういう裏技っぽいものに興味を持って利用して何か作ってみようとしてると思います
言語をダメと言ってるようで実際のところは自分には使いこなせないです 扱いきれませんと言ってるようなものですしね
toString/valueOf は普通に使う分にはあまり触れることないところですが変なもの作ってみようってときにはいじってみるといいと思います
http://2ality.com/2011/12/fake-operator-overloading.html
こんなこともできたりね
ただ 実際に役立つ使い方 というと
== じゃなくて === でも使えて (== は特別理由ないときはできるだけ使わない方がいい)
strict mode でも使える (将来的に module は強制 strict だから)
defineProperty?
なんか面白くない普通なものになりました
逆に使うと一番後悔するのは見えない変数文字でしょうね
まだ空白があるハングルのだといいですが ZWNJ なんか使い始めると もうどこにあるのかわからないですから
しかもコピペしたときにエディタによっては消されて なぜか動かなくなることもあったりで……
昔は CodeIQ (だっけ?) でやってたこんな感じの JavaScript クイズが好きでよくやってましたが久しぶりにやってみたくなりました