+ JavaScript の質問用スレッド vol.114 +

このエントリーをはてなブックマークに追加
952Name_Not_Found:2014/05/02(金) 08:30:58.55 ID:???
スレの勢いからすると960過ぎくらいでもいいと思う。
どこかの板のスレみたいに950で立てるのは馬鹿だがw
953Name_Not_Found:2014/05/02(金) 11:32:23.42 ID:???
>>950
> 配列のサイズが変わったかどうかを突き止めるのは、
> かなり大変でしょ?
まぁ多分大変だろうね
ただ
http://jsperf.com/caching-array-length/4
↑ここでベンチ結果が出てるけど、len代入とarray.lengthそのままでは全く速度は同じだね(青と黄を比較)
ちなみに With caching Part 2 の結果が爆速になってるけど処理内容を変えちゃってるから駄目だろ…
954Name_Not_Found:2014/05/02(金) 11:36:13.49 ID:???
>>953
なんか少し古いバージョンだった…
http://jsperf.com/caching-array-length/25
これが最新だった(結果は一緒だけど)
955Name_Not_Found:2014/05/02(金) 14:26:24.83 ID:???
>>934話の流れを見て欲しい。あくまで2段階コンストラクトを行うとき、及び内部的なプロパティの話をしている。
この場合の未初期化というのは継承可能、共有可能な第一コンストラクタ、つまり@@createやそれに当たる関数に処理されて、
そのオブジェクトがそのクラスのインスタンスたる最低限の処理、つまり内部プロパティに当たるものだったり、
プロキシの設定を済ませてはいるが、メソッドでの処理に必要な情報の多くを決定=初期化されていない状態を指している。

コンストラクタを「作る」フェイズと「初期化する」フェイズにキッチリ分け、両方を意識することでコンストラクタ≒クラスを継承、再利用しやすくなる。
ES6でもそれ=@@createがあるからネイティブクラスの継承が容易にできるようになっている。
例えば class MyArray extends Array {};;; obj = new MyArray(...arg) は obj = MyArray.call(MyArray[@@create]() ,...arg) と大体等しく、
まず作る段階でMyArray.__proto__[@@create]、つまりArray[@@create]がthisをMyArrayとして呼ばれて適切な処理を受けることが出来る。
そして続けてのconstructorもデフォルト処理のsuper(...arg)が適切に効く。

コンストラクタを二段階にするのは他にも理由がある。それは安全性のため。
コンストラクタはthisを初期化するものだが、それだとClass.call(tekitou)みたいな使い方ができてしまう。
これを許すとProxy性を持たないArrayだったり、「規格外の正当なインスタンス」が存在し得るので各所でのチェックが余分に必要となったりといいことがない。
だから、ClassのconstructorのthisはそのClassの未初期化のインスタンスのみを受け付けるようにする。
956Name_Not_Found:2014/05/02(金) 14:37:42.34 ID:???
しかしESにはクラスは存在せず、インスタンスとその作成元を保証してくれるような静的な繋がりもないので、インスタンスかどうかの判断が問題になる。
ここでES6内部仕様に習うと、そのクラスの代表的な内部プロパティの有無で判断する。
そして内部プロパティを持っていても、初期化済みのインスタンスを再初期化する事のないように、内部プロパティがundefinedかどうかで初期化済みを確かめる。
逆にメソッドでは、未初期化のインスタンスがかけられないように、初期化済みを確かめる。

つまり安全性のため、内部プロパティを設定、確保する段階がコンストラクタより前に必要になる。
そうすることで最小限のコードでクラスの安全性と発展性を両立させることができる。
プロトタイプベースで内部的にダックタイピングを利用するしかなくても、厳正なクラスを提供することが出来る。

そして厳正なクラスにおいて、プロパティとデータをごっちゃにすることはない。
原則プロパティとはアクセサであって、ネイティブのクラスでもメソッドでオブジェクトの外部プロパティを直接利用するというものはほぼ無い。
必ずアクセサ経由で内部プロパティの変更、参照を伴うものになっていて、メソッドは内部プロパティを利用するようになっている。
そして原則内部プロパティがundefinedのときは即エラーにする。nullは0と同じような列記とした初期化済みの値で、未初期化のような意味は持たない。
957Name_Not_Found:2014/05/02(金) 16:53:55.10 ID:???
何回も使うものはあらかじめ変数にキャッシュしておくっていうのが
プログラミングにおける合理性なわけじゃん
万が一謎の最適化のせいでその方が遅くなるとしたら、
それは最適化の方が間違っているんだから
プログラマーが気にする必要はない
間違ったものはいずれ修正されていくから。
最適化を気にして非合理なコードを書くのは本末転倒すぎる。
よってC級プログラマー。
958Name_Not_Found:2014/05/02(金) 16:56:56.06 ID:???
最適化厨は最適化にかかるコストを頭に入れてないよね
くそダサいコードを最適化するのもコストがかかるんですけど?
959Name_Not_Found:2014/05/02(金) 17:17:33.63 ID:???
筋の悪い最適化に合わせて筋の悪いコードを書いて
それが時間の経過と共に非最適化していくと目も当てられない
プログラマーはひたすら筋のいいコードを書くことを心がけてさえいればいい
960Name_Not_Found:2014/05/02(金) 21:21:53.98 ID:Xjj8/aiF
普通はobj.propを一々明示的にキャッシュしたりしないのが筋がいいが、配列のlengthだけは特別
配列のlengthは知っての通りプロパティでもなく、アクセサでもなく、プロキシのようなオブジェクトのハックによって実現されてる
特殊中の特殊で一般的なキャッシュ最適化の話はできない
どれだけ処理系が配列の実装に特別な工夫を凝らしてるのかという話になる
そこを把握して期待するのは余りに重いので、プロキシが気持ち悪ければキャッシュしてもいい
961Name_Not_Found:2014/05/02(金) 21:40:57.05 ID:???
それは筋がいいのではなく単なる怠慢
ローカル変数が一番速いという真理は変わらない
962Name_Not_Found:2014/05/02(金) 22:00:09.01 ID:???
「そうした方が速くなるのが当たり前」なことをするのが筋のいいプログラミング
わざわざローカル変数に入れなくても最適化してくれる環境もあるかもしれないが、
そんな働くか働かないか分からない最適化に期待するのは筋がいいとは言えない
963Name_Not_Found:2014/05/02(金) 22:14:47.22 ID:???
> 「そうした方が速くなるのが当たり前」なことをするのが筋のいいプログラミング

違うよ。

最優先に考えるのが開発コストを下げること。
速度に関して言えば効果が高い所のみ手を入れるのが筋のいいプログラミング

だからライブラリを使うんだろう?
ライブラリを使うと関数呼び出しが増えるからたいてい遅くなる。
それでも使うのは開発コストを下げるため。
964Name_Not_Found:2014/05/02(金) 22:25:02.63 ID:???
>>962
多くの開発者が考える「そうした方が速くなるのが当たり前」は当てにならないと言う当たり前の常識を知らない時点で(ry
965Name_Not_Found:2014/05/02(金) 22:43:55.20 ID:???
thickboxの最新版なんですが、
子を閉じたときに親がリロードするのを止めるにはどこをどうしたらよろしいでしょうか?
ご教示お願いいたします
966Name_Not_Found:2014/05/03(土) 00:17:54.40 ID:???
>>963
開発コストを最優先した筋のいいプログラミングなんてないから
それは安いプログラミング
それ以上でも以下でもない
967Name_Not_Found:2014/05/03(土) 00:19:25.90 ID:???
>>964
迷信に頼るのではなく、自明の事実に基づくべきだと言っているんだよ
カスが
968Name_Not_Found:2014/05/03(土) 00:25:20.31 ID:???
>>955,956
俺は934だが単なる開発ポリシーの話しをしてるのに、あんたは随分規格に詳しいようだが
ES6のclassの継承の話しをされても、実装されてないもんは全く実感出来んしよう分からん…

ES6のclassの継承になんらかの問題がありそうな主張は分かったんで、実装されたら
また気にしてみるよ
969Name_Not_Found:2014/05/03(土) 00:31:01.97 ID:???
>>960
> 普通はobj.propを一々明示的にキャッシュしたりしないのが筋がいいが、配列のlengthだけは特別
Float32Array とかはlengthは変更不可(pushとかも不可)だから、その前提は常に正しいとは言えない
970Name_Not_Found:2014/05/03(土) 00:38:32.52 ID:???
>>966
開発コストって単に人件費をムリクリ抑える事をいうのでなければ、
開発効率を追求する事は最優先だと思うよ

開発効率を追求して開発コストを抑える事が出来れば筋のいいプログラミングと言える
971Name_Not_Found:2014/05/03(土) 00:49:20.95 ID:???
>>967
おまえが経験浅いのは分かったから、もう黙ってろよw
972Name_Not_Found:2014/05/03(土) 01:12:26.60 ID:???
論ずるなら、その主張の根拠となるコード例の一つでも出せばいいのに
973Name_Not_Found:2014/05/03(土) 04:09:29.76 ID:???
ローカル変数に代入するというごく普通のテクニックまで否定し出してびびるわw
まぁ俺には関係ないからいいけど
974Name_Not_Found:2014/05/03(土) 07:17:44.96 ID:???
いつの間にか使わなくなったプロパティーを見つけたいと思います
プロパティー名を文字列として検索してどこにもなければ使われていないと判別できると思います
そういうことをやるプログラムなどはありませんか?
975Name_Not_Found:2014/05/03(土) 08:24:50.65 ID:???
976Name_Not_Found:2014/05/03(土) 11:30:41.82 ID:???
>>968
ES6に限った話じゃないよ。ES6で大々的に摂り入れて成功してる話を交えただけ。
ES5で全部を真似するのは難しいけど、考え方、ポリシーは摂り入れられる。
話が膨らんだがnullの件については>>956の最後の段落が言いたいこと。
977Name_Not_Found:2014/05/03(土) 12:09:26.45 ID:???
口だけで筋のいいとか言われてもわからんから、サンプル見せてくれよ

できれば、悪い例とどうしたら筋が良くなるって解説つきで
978Name_Not_Found:2014/05/03(土) 12:42:24.11 ID:???
>>973
ローカル変数に代入するのは
開発しやすくするためで
速度のためじゃないんだよw
979Name_Not_Found:2014/05/03(土) 13:08:24.61 ID:???
>>973
論点ズレてるなあ。
そんなレスしてるから経験浅いとか言われちゃうんだよ。
980Name_Not_Found:2014/05/03(土) 13:19:47.64 ID:???
いや俺は変な2chねらーの意見よりも
ハイパフォーマンスJavaScriptの著者のニコラスを信用するからw
経験ワロスww
981Name_Not_Found:2014/05/03(土) 13:41:47.27 ID:???
本に書いてあることは全て正しいと思ってるタイプか
専門書で間違ったこと一切書いてない本なんてそうそうないぞ
982Name_Not_Found:2014/05/03(土) 13:57:28.44 ID:???
俺も本の正規表現が間違ってて数日悩んだ事があったから
軸となる本と、ネットで情報収集、ココで質問するといい

学校の教科書だって初版だと訂正箇所みたいなの沢山出てくるんだから
983Name_Not_Found:2014/05/03(土) 14:09:29.08 ID:???
著者を信用してるって言うのと、本に書いてあることを信用してるっていうのはまったく別次元話だろw
984Name_Not_Found:2014/05/03(土) 14:12:33.66 ID:???
教科書で自分のスキルを強化しょう
985Name_Not_Found:2014/05/03(土) 14:27:46.23 ID:???
いったん変数に代入するのは、古いPC・ブラウザ向けの対策。
新しいものは、変数が少し増えても、影響は受けないだろ

それに、Webサイトはプログラムなどと違って、
1回しか見ないことも多いので、
時間をかけて最適化して元が取れるのか、という観点もある

それより、Mathの関数を何百回も呼ぶので、
変数に代入して使っているんだが、これは正しいのか?
>>950
// 乱数を発生させる。少数点以下を切り捨てる
var fRnd = Math.random, fFlo = Math.floor;
fFlo(fRnd() * 100);

それと、配列のアクセスには、forEach系を使う、
って誰かが書いていたけど、forの方が速いのじゃ?
986Name_Not_Found:2014/05/03(土) 14:43:36.63 ID:???
>>985
>>950ではないが…。
- Math.random をローカル変数にキャッシュするのは手法として間違ってない。
- 一般に関数呼び出しは遅いので forEach より for が速い。
987985:2014/05/03(土) 15:05:47.76 ID:???
Math.random, Math.floorは静的関数かな?
なぜこれらを変数に代入すると、速くなるの?
988Name_Not_Found:2014/05/03(土) 15:09:21.01 ID:fUUxJBT9
array.lengthをキャッシュするのと
int8array.lengthをキャッシュするのと
Math.randomをキャッシュするのは全部事情が異なる
上からプロキシ、ゲッター、スロットへのアクセスだから

あと、JSとネイティブを跨ぐ最適化は困難という問題がある
だからV8なんかはどんどん自己ホスト化を進めていて特にMath系の関数ですごく効果が出てる
例えばMath.randomも全部JS化されているから完全にインライン化される
https://code.google.com/p/v8/source/browse/branches/bleeding_edge/src/math.js#148

三角関数系もそう
だがその副作用で制度が落ちたと問題になった
今も最後尾数字が1変わるくらいの違いがある
浮動小数は===で比較してはいけない(教訓)
989986:2014/05/03(土) 15:33:27.34 ID:???
>>987
Math.random はグローバル関数であり、ローカル関数よりも遅い(スコープチェーン)
更にプロパティアクセス演算子も1回しか使用しなくて済む
990985:2014/05/03(土) 16:02:33.62 ID:???
例えば、MathのアドレスがA番地として、
randomのアドレスがBとして、

var p = Math.random;
とすると、pにはB番地が入る?

でも、変数に代入せず、Math.randomのまま使うと、
毎回、A→Bの間接参照が行われるの?
なぜインタプリタは、Bを変数に代入して使わないのか?
991986:2014/05/03(土) 16:25:04.03 ID:???
>>990
>>989でも説明したが、スコープチェーン
プロパティアクセスが遅い理由はプロトタイプチェーン
992Name_Not_Found:2014/05/03(土) 16:25:35.71 ID:???
当然してる
ただMathに変更がないことを確認するオーバーヘッドがある
それとただのキャッシュだけではなくて、random内の処理が埋め込まれて、それからさらに最適化がされる
その辺でより最適化を望むならES7のRelationshipsに期待するといい
http://wiki.ecmascript.org/doku.php?id=strawman:relationships
これは確認がいらない、というか、処理系の代わりに、責任をset/get関数側が負う設計
もしそれを守らなかったり、設計ミスをすると、最適化/非最適化で結果が変わるというJSには珍しいアンセーフな代物
その代わり最高のパフォーマンスが出る
993Name_Not_Found:2014/05/03(土) 17:09:40.92 ID:???
やっとキャッシュは有効というまともな話になったか
キャッシュ否定厨はキャッシュに親でも殺されたのかよw
994985:2014/05/03(土) 17:15:16.97 ID:???
>>988
>プロキシ、ゲッター、スロットへのアクセスだから
結局、"a.b"と、ドットが付いていたら、
何でも変数に代入した方がいいのかな?

Math.randomまで代入するのは、やりすぎのような気もします
変数が多くなって、プログラムがわかりにくくなる

プロキシ、ゲッター、スロットの中で、
どれを変数に代入すべきでしょうか?

長時間、お付き合いありがとう
古いPC・ブラウザのことを考えると、
どうしてもインタプリタが最適化しやすい、
プログラミングを考えてしまいます
995Name_Not_Found:2014/05/03(土) 17:34:08.74 ID:???
chromeのconsole.timeの最小単位は1msなのでしょうか?
小数点以下が0以外になったのを見たことがありません
996Name_Not_Found:2014/05/03(土) 18:00:49.69 ID:???
textareaにある文字をそのまま$(textarea).val()で取得してdata-unk=""の中に入れちゃおうと思うんですが
これってエスケープとか必要ですか?
997Name_Not_Found:2014/05/03(土) 18:00:50.01 ID:???
dom要素へのidの設定はsetAttributeを使うのとidプロパティへの代入と
どっちがいいんですか?
998Name_Not_Found:2014/05/03(土) 18:07:55.32 ID:???
変数に代入って言葉そろそろやめませんか
999Name_Not_Found:2014/05/03(土) 18:27:22.68 ID:???
じゃあいい言葉考えろよ
1000Name_Not_Found:2014/05/03(土) 18:42:37.42 ID:fUUxJBT9
皆最適化最適化言うけど、なかなかCPUのことまで考えないと
最近のCPUはコードのパターンに添って様々な先読みをしている
そして外れた時のペナルティがかなりデカイ(当たったことを考えたら)
問題はそれが必ずしも直感と一致しないこと

例えばnは0から3までの整数の乱数で、nが0,1のときA,2のときB,3のときCを実行するとする

普通に考えると、条件評価の期待値の少ない少ないこういうコードになる
if (n < 2) return A()
if (n == 2) return B()
return C()

しかし分岐予測のことを考えたらこういうコードになる
if (n == 3) return C()
if (n == 2) return B()
return A()

簡単に説明すると、予測が外れる確率が、Aの分岐はわからないから50%、B、Cの分岐は分岐しないと予測して25%
予測が外れる期待値が一番低いのが2番目のようなコードになる
もちろん実際はもっと複雑だが、筋の良いコードが高速だとは限らない
10011001
このスレッドは1000を超えました。
もう書けないので、新しいスレッドを立ててくださいです。。。