/ 最近 .rdf 追記 設定 本棚

log[javascript: 2010-01-31]



20100131() PS3 +ーンベル + torne = 買うしか

最終更: 2010-04-17T12:23+0900

[javascript] JSLint

コマドプロントで利用できる WSHがある

JavaScriptの構文チッカJSLintEmacsから使う - 檜山正幸のキマイラ飼育記にならってサクラエタで編集中の .jsァイルをチックできるようにしよう

といってもダウンロドしてきた jslint.jsをパスの通った場所(っと試してみるだけならエタで開いているファイルと同じトリ)に置いて「ツール>「外部コマド実行」でcscript jslint.jsと入力するだけだった

jslint.js自身を開いた状態で実行した結果はこう

#============================================================
#DateTime : 2010-02-01 06:44:29
#CmdLine  : cscript jslint.js
#============================================================
Microsoft (R) Windows Script Host Version 5.7
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

Lint at line 312 character 9: All 'debugger' statements should be removed.
debugger;if(!/^[A-Za-z][A-Za-z0-9._:\-]*$/.test(v)){warning("Bad id: '{a}'.",nexttoken,v);}else if(option.adsafe){if(adsafe_id){if(v.slice(0,adsafe_id.length)!==adsafe_id){warning("ADsafe violation: An id must have a '{a}' prefix",nexttoken,adsafe_id);}else if(!/^[A-Z]+_[A-Z]+$/.test(v)){warning("ADSAFE violation: bad id.");}}else{adsafe_id=v;if(!/^[A-Z]+_$/.test(v)){warning("ADSAFE violation: bad id.");}}}

終了コード: 1

あまりに割合が少ないのでせっせと Vistaでのサクラエディタのスクリーンショットをアップしております。

  • debuggerの使い道って何だろう
  • jslint.jscopyright2002年だけどコメトを除いた一番最初に "use strict" なんて書いてあるそれFinal final final final draft Standard ECMA-262 5th editionというタトルの PDFァイルで少し前に見たものだ実装が先にあったのか知らないけど対応が早い!
  • jslint.jsの出力は StdErrなんだけどサクラエタはお構いなしに標準出力と合わせて取得している面倒なことを考えずに済んで助かった

20091016() [SakuraEditor]折り返ししている物理行末をーボドで左から右へ矩形選択しようとすると次の物理行にカーソルが移動して意図した通りに選択できません折り返されている行末へカーソルがたどり着いた瞬間次の行の頭に移動していて右端の一列が選択できないたしかに問題折り返し込みの矩形選択とかコピペしたときにどうなるのが正しいのか想像できないんだけど……矩形選択は図形的な操作だから折り返しがあろうが改行があろうが右へ範囲を広げている最中にキャレトが左へ戻ってしまうというのが意外な感じはする

最終更: 2009-10-17T03:43+0900

[javascript] 空文字列にマッチした後の lastIndexの値は IEの挙動が妥当

  var re = /\b/g;
  var match = re.exec( "012" );
  alert( match.index ); //=> 0
  alert( re.lastIndex ); //=> 0(ECMAScript仕様), 1(IE)

仕様では 何度 re.execを実行しても re.lastIndex0から増加しないからre.execをループで実行するときにはマッチ結果が幅0のときに限り特別に lastIndexをインクリメトする処理が必要になる

 lastIndex1ではいけないの?

ッチの範囲は "0"の直前から "0"の直前まででlastIndexは範囲の末尾の次の位置を指すものッチの幅は0

index = 0; lastIndex = 1; であればマッチ範囲は "0"(1)ということになってしまい正しくない

index = 0; lastIndex = 0; であればマッチの幅が 0だということもその位置が "0"の手前だということも表現できていて正しい気がする

 でもlastIndexってパターンオブジトのプロパ……

indexはマッチ結果のプロパだけどlastIndexはパターンオブジトのプロパなのだmatch.index...re.lastIndexの範囲が正しいとか正しくないとかは考慮に値しないのではない

検索結果に影響があるかといえばスクリトエンジンが行ってくれないことをスクリトを書く人間が手作業で行っているだけなのだから影響はないだろう

IEは至極まっとうな実装をしたと思う


20081223() 新☆はてブ < スクロールが重いからピンを抜いたのにカテゴリを選び直すだけで元に戻る鳥頭そこは Cookieを使うべきところです。(潔癖症の人はどうせ拒否設定してるでし)

[SHJS][javascript] SHJS-0.6がリリースされていた(20081215)

アナウスされている変更点は…… (: 日本語部分は俺の勝手な訳のような注釈のようなも)

December 15, 2008 - SHJS 0.6

SHJS 0.6 is available for download.

SHJS 0.6 includes several new features, improvements and bug fixes:

  • SHJS is now distributed under version 3 of the GNU General Public License. (Older releases of SHJS were distributed under version 2 of the GNU GPL.)

    ライセスが GPLv2から GPLv3へ変更

  • Markup inside pre elements is now preserved.

    PREタグの中の HTMLークアップが保存される(以前は Node.dataを再帰的に取り出したもの乱暴にいうと PRE.{innerText|textContent}に相当するものが利用されていたver.0.5ではマークアップとして <br>のみが考慮されていた)

  • Several new languages (from the latest release of GNU Source-highlight) are included: S-Lang, Scala, Java properties files, Desktop files, LSM (Linux Software Map) files, Xorg configuration files, RPM spec files, Haxe, LDAP files, GLSL, Objective Caml, Standard ML, JavaScript with DOM, and C (separate from the C++ language file).

    最新の GNU Source-highlightから新しい言語ファイルを追加JavaScriptには DOMーワドを含んだ lang/sh_javascript_dom.jsが追加された(sh_javascript_dom = sh_javascript + applicationCache|closed|Components|content|controllers|crypto|defaultStatus|dialogArguments|directories|document|frameElement|frames|fullScreen|globalStorage|history|innerHeight|innerWidth|length|location|locationbar|menubar|name|navigator|opener|outerHeight|outerWidth|pageXOffset|pageYOffset|parent|personalbar|pkcs11|returnValue|screen|availTop|availLeft|availHeight|availWidth|colorDepth|height|left|pixelDepth|top|width|screenX|screenY|scrollbars|scrollMaxX|scrollMaxY|scrollX|scrollY|self|sessionStorage|sidebar|status|statusbar|toolbar|top|window + alert|addEventListener|atob|back|blur|btoa|captureEvents|clearInterval|clearTimeout|close|confirm|dump|escape|find|focus|forward|getAttention|getComputedStyle|getSelection|home|moveBy|moveTo|open|openDialog|postMessage|print|prompt|releaseEvents|removeEventListener|resizeBy|resizeTo|scroll|scrollBy|scrollByLines|scrollByPages|scrollTo|setInterval|setTimeout|showModalDialog|sizeToContent|stop|unescape|updateCommands|onabort|onbeforeunload|onblur|onchange|onclick|onclose|oncontextmenu|ondragdrop|onerror|onfocus|onkeydown|onkeypress|onkeyup|onload|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onpaint|onreset|onresize|onscroll|onselect|onsubmit|onunload)

  • Many other languages have minor improvements.

    言語ファイルのアップデ

  • Compressed .min.css stylesheets are now included in the distribution.

    最小化した CSSァイルを同梱(.js.cssYUI Compressorを使用ver.0.5までは .jsのみが JSMinで処理されてい)

Please note that the format of language-specific JavaScript files has changed in SHJS 0.6. JavaScript language files from version 0.6 will not work with sh_main.js from previous releases, and vice versa. Make sure you upgrade both the sh_main.js file and language-specific files.

古い言語ファイル(lang/*.js)と新しいメイスクリ(sh_main.js)は互換性がない(逆も同じ)両方入れ替えるべし

大きな変更は <pre></pre>内の HTMLークアップがシンタックスハイラト後も保存されること(タグがたすき掛けになるときはどうするんだろ)

言語ファイルの変更は小さくて"next""regex""style""exit"というプロパを持ったパターンオブジトが3要素の配列になっている

 異種document対応が必要では? (sh_main.js)

function sh_highlightElement(element, language) {
  sh_addClass(element, 'sh_sourceCode');
  var originalTags = [];
  var inputString = sh_extractTags(element, originalTags);
  var highlightTags = sh_highlightString(inputString, language);
  var tags = sh_mergeTags(originalTags, highlightTags);
  // この documentFragmentはグローバル変数の document由来。
  var documentFragment = sh_insertTags(tags, inputString);
  while (element.hasChildNodes()) {
    element.removeChild(element.firstChild);
  }
  // element.ownerDocument != documentFragment.ownerDocumentのとき失敗しませんか?
  element.appendChild(documentFragment);
}

コメトを参照のことIEのバージョンが 5.5くらいだった時に失敗したような記憶が根拠で確証はないしレアケースだとは思うけど(フレームをまたいで sh_highlightElement(element, language)を呼び出したとき(=スクリトとエレメトが異なドキュメトに属するとき)に起こるかな)

 タグのたすき掛けの結果

 before
<pre class="sh_ruby">
require 'sqlite3'
<strong>require</strong> 'sqlite3'
<strong>req</strong>uire 'sqlite3'
</pre>
<pre class="sh_javascript">
/*
http://example.com
http://example<em>.</em>com
*/
</pre>
 after
<pre class="sh_ruby sh_sourceCode">
<span class="sh_preproc">require</span> <span class="sh_string">'sqlite3'</span>
<strong><span class="sh_preproc">require</span></strong> <span class="sh_string">'sqlite3'</span>
<strong><span class="sh_preproc">req</span></strong><span class="sh_preproc">uire</span> <span class="sh_string">'sqlite3'</span>
</pre>
<pre class="sh_javascript sh_sourceCode">
<span class="sh_comment">/*</span>
<a href="http://example.com" class="sh_url">http://example.com</a>
<a href="http://example.com" class="sh_url">http://example</a><em><a href="http://example.com" class="sh_url">.</a></em><a href="http://example.com" class="sh_url">com</a>
<span class="sh_comment">*/</span>
</pre>

SHJSの挿入するタグは必要に応じてぶつ切りにされるみたい

 追記@2009-02-25: 手製の言語ファイル( rubyjavascript)0.6ーマトに変換した(最小化方法は依然として JSMin)

移行スクリトはこれ( migrate_05_06.js )shjs-0.5までの lang/sh_*.jsァイルドロップすると lang/sh_*.06.jsというファイルができてくるという寸法ちなみに JScript

トもかねてバージョン 0.6を走らせてみたけど軽くなってる道理がない*のでこの日記では shjs-0.4.2に手を入れたものを使い続けている

 追記@2009-04-06: 0.6いいね

言語ファイルのフーマト変更は速度的に有利

パターンマッチの結果を Stateをまたいで保存するようになっているのでこの日記の sh_ruby.jsのようにあっちこっち跳びまわる言語ファイルに有利に働くいちばん時間を消費しているのが RegExp.exec()DOMツリーへの HTML断片の追加なのでパターンマッチ結果のキッシュは大事(っとも 0.4.2のときからキッシュの拡大は個人的にやってい)

* <pre>内のマークアップを保存するためにハイラト前と後の二つの HTML文字列をマージしているでもその機能俺個人はいらないのよね


20081024() [HTML] Logicoolのサトはキーボドでもタブの切り替えができて偉い(スクリトをOFFにするとマウスを使ってさえ表示を切り替えられなくなったが…)

[HTML][javascript] 補助に徹する賢い JavaScriptの使い方

基本はこう

  1. HTMLのみで情報を配置する
  2. CSSで見栄えを整える
  3. スクリトで効果やアクションを付け加える

Logicoolのサトのタブコトロールはキーボドインターフェイスを具えていて偉いと書いたばかりだが、スクリトがオフだとタブの切り替えができないばかりかタブの中身、肝心の情報が表示されないのはイクナイ

スクリトで各タブの表示・非表示を切り替えているのだろうが

  • タブの状態のデフトは非表示
  • スクリトで一つだけを表示に切り替え

ではなく

  • タブの中身はデフトで表示
  • スクリトで一つ以外を非表示に切り替え

より良いやり方ではない(一瞬全ての情報が表示されてすぐに消えるというのは気にすることではないと思ってい)

ロジのサトのこのスクリトは見栄えをいじるだけなのでHTMLとスクリトを切り離して最初に HTMLのみでページを作りスクリトは後からアタッチするものだと考えて欲しかった

スクリトに依存する要素があって切り離せない場合はAmazon.co.jpがやっているように

  • <noscript>の中にスクリトを使わない代替 HTMLを用意する (できなければないで仕方がな)
  • <script>の中でスクリトを必要とする要素をスクリトを使って配置する

方法が賢いと思っている

 っとだけ関連


20080527() [Firefox] 領域を選択してのソース表示はスクリトに書き換えられた最新の HTMLを反映しているのが便利

[Firefox][javascript][SHJS] <pre>が真っ白になり黒色の領域が出現する

例えばこのページ http://vvvvvv.sakura.ne.jp/ds14050/diary/20080112-7.html Endーで末尾に移動して PageUpで戻っていくと空白の PREが目に入ると思うその少し上にはページの内容を覆い隠す黒い領域があるはず。(そうでなければ修正されたのだろうFirefox2で最初に確認しFirefox3.0RC1でも直っていなかった)

大量の PREが存在したり一つだけでも巨大な PREが存在する場合に起こる様子innerHTMLPREの内容を置き換えているのも原因になっているかもしれない

画面の末端にスクロールした状態でページをリロ(F5 or Ctrl+R)すると下方の PREが正常に表示される反面上端付近の PREに同じ問題が生じる遠方の PREの書き換えに問題があるのでは?

っ白の PREの中で右クリックしたりテキトを選択したりといったアクションを起こせば正常に表示されることが多い


あとPREの中から開始した選択は PREの外に出られなかったり(これは TEXTAREAと違い PREでは Ctrl+Aで全文選択ができないために用意された代替手段だという気もす)


20080514() DFAエンジンのマッチの仕組みは謎のまま残された正規表現を利用する側からはコトロールできる部分が皆無で常に同じ結果が返ってくるおもしろみのないものらしいけどその魔法の実現方法は大いに知りたい

[正規表現][javascript][大型] Jeffrey E.F. Friedl【詳説 正規表現 第3版】 オライリージャパン

読んだこの日記で以前書いたようなこと(20080116p01, 20080111p01)は全て書いてあったもちろんそれ以上に知らないこと(NFAのマッチングのしかたNFA型正規表現エンジンに適用できる正規表現のチーニングの具体例UnicodeサポPerl, .NET, Java, PHPの正規表現\Gの使い方などなど)が書かれていた

非常に読みやすい文章で書かれているし必要なところでは必ず前後のページへの参照先が書かれている章の始めには Overviewがありその章から読み始めた読者への配慮も忘れない当たり前のことだけど徹底されている「まずこの本を読め正規表現について話すのはそれからだと言い切れる良い本正規表現を初めて学ぶ人にも効率について考える余地ができてくるほど既に正規表現を使っている人にも役に立つ

すごく実用的なテクニックででも全く想像が及ばなかったものがある168ージ4.5.8.1 肯定の先読みを使ったトミックグループの模倣がそれ

 肯定の先読みを使ったトミックグループの模倣

/(?>pattern)/     // アトミックグループを使ったパターン
/(?=(pattern))\1/  // 先読みでアトミックグループを模倣したパターン

高機能化する他の実装にくらべて昔のままの JavaScriptの正規表現はバトラックを抑制する構文を持っていないJavaScriptでは非常に有用

20080116p01でも書いたが次の終わらない正規表現

/"(?:[^\\"]+|\\.)*"/       // マッチに失敗するとき死ぬほど遅い

トミックグループや絶対最大量指定子が使えるなら次のように書けるが JavaScriptは両方ともサポトしていない

/"(?:[^\\"]+|\\.)*+"/      // JavaScriptでは使えない
/"(?>(?:[^\\"]+|\\.)*)"/g  // JavaScriptでは使えない
/"(?:[^\\"]++|\\.)*"/      // JavaScriptでは使えない。※上2つとは少し意味が違う

次のように先読みでトミックグループを模倣すると組み合わせの爆発を避けることができる

/"(?=((?:[^\\"]+|\\.)*))\1"/
/"\1"/            // 上のパターンから先読み部分を取り除いたもの。

先読みを取り除いたパターンを見ると一目瞭然だが引用符がペアになっていなくて \1 の後ろの " のマッチに失敗したとしても戻る場所がないあるのは "\1 にマッチしたという結果でどちらもオプションではないので取り消すことはできず繰り返しでもないのでマッチした部分を少しずつ手放させることもできないなのでっとずつ後じさりしながら延々とあらゆる組み合わせのマッチを試行することなしにッチが失敗に終わったことが即座に判断できるようになるというわ本物のトミックグループよりは劣るが効率も悪くない同じ働きをする次の二つのパターンとかかる時間を比較してみた

/"[^\\"]*(?:\\.[^\\"]*)*"/
/"(?:[^\\"]|\\.)*"/

 手順

トラックによる組み合わせの爆発が起きない 3つのパターンでかかる時間を比較3回実行した(3回繰り返しても一回一回の中の試行順が固定されていたら傾向は同じになるわな無意味あてみやむい)

var re = [
	/"(?:[^\\"]|\\.)*"/,
	/"(?=((?:[^\\"]+|\\.)*))\1"/,
	/"[^\\"]*(?:\\.[^\\"]*)*"/
];
var s = [
	'"'+ new Array(5000+1).join('\\"'),        //  1/100
	'"'+ new Array(500000+1).join('\\"') +'"',
	'"'+ new Array(500000+1).join("\\'"),
	'"'+ new Array(500000+1).join("\\'") +'"',
	'"'+ new Array(500000+1).join('a'),
	'"'+ new Array(500000+1).join('a') +'"'
];
var results = [];
for(var j = 0; j !== s.length; ++j) {
	var result = [];
	for(var i = 0; i !== re.length; ++i) {
		var t0 = new Date();
		var m = re[i].exec(s[j]);
		result[i] = new Date() - t0;
	}
	results[j] = result;
}
WScript.Echo(results.join("\n"));

 結果

数の単位は msec

パターン1パターン2パターン3
工夫なしトミックグループの模倣ープ展開
/"(?:[^\\"]|\\.)*"//"(?=((?:[^\\"]+|\\.)*))\1"//"[^\\"]*(?:\\.[^\\"]*)*"/
文字列1ッチしない(F)"\"\"......\"\"2910×100, 2928×100, 2914×1002551×100, 2581×100, 2595×1002372×100, 2387×100, 2377×100
ッチする(T)"\"\"......\"\""124, 124, 124138, 137, 134108, 107, 108
文字列2ッチしない(F)"\'\'......\'\'138, 140, 151125, 127, 125122, 118, 118
ッチする(T)"\'\'......\'\'"138, 126, 126140, 128, 133135, 105, 106
文字列3ッチしない(F)"aa..........aa174, 172, 16614, 11, 1396, 90, 92
ッチする(T)"aa..........aa"155, 119, 12632, 15, 1415, 12, 11

 みどころ

  • ッチに失敗するときの成功するときに比べた遅さ
    • パターン2は例外
  • パターン2(トミックグループの模倣)ではしばしばマッチに失敗する方が速い
    • \1のマッチが成功だと判断するにはキャプチャした長い長い文字列を最後までたどって比較する必要があるため\1のマッチに失敗するほうが速くなる?
  • 文字列1Fの特筆すべき遅さ
    • 遅いとはい「終わらないと形容するほど遅くはない(これでも)
    • 文字列長に比例したバトラックが行われているせい?
    • 文字列2Fの結果と比較するに\" という形で " が文字列の途中に含まれていることが最適化を阻んでいる?
  • パターン3(ープ展開)は特定の場合を除いてパターン2(トミックグループの模倣)より若干速い
    • ープ展開『詳説 正規表現に載っていた言葉
    • 特定の場合とは文字列3Fのことで不用意なパターンを用いると処理が終わらなくなる場合のこと
  • パターン2(トミックグループの模倣)(今回の眼目である)組み合わせの爆発が起こるような場合に顕著な速さを見せる
    • 他の文字列ではパターン3(ープ展開)に半歩譲る

ところで文字列1Fがどのパターンでも一様に遅いのは文字列長に比例したバトラックが行われているからなんだろうがパターン2(先読みによるトミックグループの模倣)でもそれを抑制できていないのはなんとかできないものそれでこそ若干のオーバーヘドをのんででもトミックグループの模倣を採用する理由になるのだ


20080221() エクスプローラはバカだエクスプローラはバカだエクスプローラはバカだdesktop.iniは目障りな上に役に立っていない(C:\Windowsが音楽フォルダって何? 実体のないフォルダ(マイコンピータごみ箱デスップーザ)の表示設定も保存し)

[javascript] JavaScript空文字列にまつわる微妙な点 (String.split(), RegExp.lastIndex)

 空文字列を split()

split()の第一パラメータ separatorが空文字列にマッチするかどうかで結果が異なる

"".split(" ").length;      // 1 (空文字列にマッチしないから)
"".split("").length;       // 0 (空文字列にマッチするので)
"".split(/\s+/).length;    // 1 (空文字列にマッチしないから)
"".split(/^$|\s+/).length; // 0 (空文字列にマッチするので)

function getClasses(element) {
  return element.className.split(/^$|\s+/);
}
 追記@2008-05-28: 空白で始まったり空白で終わるときのことを考えていなかった

上の functionでは classNameが空っぽの時には空文字列の要素を作らないが頭や尻尾に空白が付いていると空文字列の要素が残る (IEを除いて)事前トリミングする手間をかけるくらいなら一個二個の空文字列を気にせず(だけど連続する空文字列の要素は気にして) className.split(/\s+/) とする方が好みだな

 空文字列にマッチした後の lastIndex

IE7Firefox2で異なるFirefox2の方が正しいが無限ループに陥りやすい

var re = /\b/g; // 単語境界にマッチする、幅0のメタ文字。
var str = "012 456 89A";
re.lastIndex = 0;
for(var i = 0; i !== 5; ++i) {
  alert("("+ re.exec(str).index +","+ re.lastIndex +")");
  // IE7: (0,1) (3,4) (4,5) (7,8) (8,9) ...
  // Fx2: (0,0) (0,0) (0,0) (0,0) (0,0) ...
}

空文字列にマッチしていれば(IE7でスキップされるマッチがでてく) exec()の前後で lastIndexの値が変わっていなければ(Fx2でのマッチ回数が IE7より増え) indexlastIndexが同じならば lastIndex1インクリメとしておくとどちらでも間違いが起こらない

var re = /\b/g;
var str = "012 456 89A";
re.lastIndex = 0;
for(var i = 0; i !== 5; ++i) {
  var index = re.exec(str).index;
  alert("("+ index +","+ re.lastIndex +")");
  // IE7: (0,1) (3,4) (4,5) (7,8) (8,9) ...
  // Fx2: (0,0) (3,3) (4,4) (7,7) (8,8) ...
  if(index === re.lastIndex) {
    ++re.lastIndex;
  }
}

ープで

  if(index === re.lastIndex) {
    ++re.lastIndex;
  }

なんて分岐を増やすより文字列末尾にマッチする /$/ を例外として*正規表現から空文字列にマッチする可能性を排除する方が良さそう

* /$/.exec("str") の後の lastIndexプロパIE7Fx2とも最後の文字の次を指す。


20080215() [かな変] F6にかえてCtrl+U[カナ変] F7にかえてCtrl+I[部分確定]↓にかえてCtrl+N[辞書検索/辞書ページ送] End[電子辞典切替メニ] Ctrl+End

[javascript]Re: Javascriptstring型とbooleanoneOfメソド他 (agenda)

コメト欄がないのでここでひっそりつっこんでおきます。

 それは valueOf()

StringBoolean(と NumberDate)だけこのように比較方法を === から == にしたりする必要はなくて

String.prototype.equals = Boolean.prototype.equals = function(arg){
    return this == arg;
};

こう

Object.prototype.equals = function(that) {
  return this.valueOf() === that.valueOf();
}

これでオブジトに関しては同一性をチックしプリミブでは値が等しいかどうかをチックする

ところで配列の場合

valueOf メソドの動作はオブジトの種類に応じて異なります

配列の要素はカンマによって連結される文字列に変換されます。Array.toString メソドや Array.join メソドと同じように動作します。

 Microsoft JScript 5.5 リファレンス (chm)

と書かれていて同一性のチックができなさそうに思えるけどJScript5.7Firefox(javascript1.5)ともにチックできていた

 追記

Array.prototype.valueOf()StringBooleanNumberDateのそれと違って特別に用意されてはいなかった

: 15.4 Array オブジ(Array Objects)

ということは Object.prototype.valueOf()が呼ばれるはずでこれは thisを返す。

var a = [1];
alert(a.valueOf() === a); // true

JScript5.5のいいかげんなリファレスを書いた人出てきなさい(はじめての言語だった JScriptHSPのヘルプには変数の概念から始まる丁寧な説明を受けました大変感謝していま)


20080212() エクスプローラがメモリを放さないプライベトワーキングセトは 14MBでもVistaより前のタスクマネージャが表示していた数字では 215MBになる仮想メモリ不足ってメッセージが何度も出るんですけど

最終更: 2010-03-21T03:27+0900

[javascript][SHJS] JSLint <http://www.jslint.com>

SHJSsh_main.jsを高速化したことを以前書いた(20080204p01)

 対応ブラウザ

SHJSのページには動作を確認したブラウザとして以下が挙げられている

  • Firefox 2
  • Internet Explorer 6
  • Internet Explorer 7
  • Opera 9
  • Safari 3

sh_main.jsの修正版は Firefox2IE7Opera9で正しく動作することの確認と速度の比較を行っている

IE6での確認は IE7から戻すのが面倒なので省略する

Sarari3Vistaで動くものがダウンロドできるので確認してみたところ動いた(表示も正)

いじったことで対応ブラウザが減っていなくて良かった(IE6)

 JSLint

SHJSの作者は Code Conventions for the JavaScript Programming Languagejslint: The JavaScript Verifier かそれに類似した文書を読んでいるに違いない(これらのページを今日発見し)

というのもsh_main.jsJSLintでチックしてみたがこういうエラーしか出なかった

Error:

Implied global: document 362, sh_languages 347, window 332

このエラーは JSLint向けにコメトを埋め込めば取り除けるものだしそうしないと不可避だともいえるもの

 さてさて自分がいじったことでどれだけお行儀の悪いスタイルが混入したのでしょうか
Error:

Implied global: document 207 360, sh_languages 332, window 329

Problem at line 73 character 48: Use the array literal notation [].

   matchCaches = language.matchCaches = new Array(language.length);

Problem at line 86 character 17: 'i' is already defined.

   for(var i = matchCaches.length-1; i !== -1; --i) {

Problem at line 97 character 22: 'i' is already defined.

   for (var i = state.length-1; i !== -1; --i) {

Problem at line 110 character 17: 'i' is already defined.

   var i = (pair[0] & 0x3F);

Problem at line 280 character 15: Use '!==' to compare with '0'.

   while(0 != this._currentStyles.length) {

Problem at line 389 character 14: 'node' is already defined.

   var node = this.free_;
 いいわけ
  • ーカル変数の再宣言に関するものは全て forープで初期化される変数が原因(inode)
  • var array = new Array(length);」をvar array = []; array.length = length;」やvar array = Array.prototype.slice.call({length:length}, 0); と書き換えることは拒否する

    (new Array(length)が一番簡潔で自然な書き)

    (JavaScript 1.7配列内包に書き換えるのには吝かでな)

  • != 0 の代わりに !== 0 と書け? 書き換えましたm( __ __ )m

(一つを除い) 無視できる警告*ばかりで良かった

* 無視したら警告の意味がないforープの変数なんて(古い VC使い以外には)スコープの誤解を招きやすいという理由で避けなければいけないものの筆頭ともいえる


20080208() 寝ているすきに腕まくらをされに来ていたにゃんここれだから冬は(≧∀)

[javascript] ArrayStringの故意に汎用的なメソドたち (1)

Under Translation of ECMA-262 3rd Edition を読んでいて見つけ「故意にに汎用的であると書かれたメソド群ArrayStringのほとんどのメソドが該当する

FirefoxArray.prototype.methodなどを Array.methodからも参照できるようにする(している)のも 仕様が汎用的で再利用が可能になっているからだろう

それら汎用的なメソドを使い回してやるためにその動作を javascriptのコドで表してみる

 Array.prototype.concat([item1[, item2[, ...]]])

function() {
  var array = [];
  var array_index = 0;
  var item = this;
  var arg_index = 0;
  do {
    if(item instanceof Array) { // (1)
      var item_index = 0;
      while(item_index !== item.length) {
        if(item_index in item) {
          array[array_index++] = item[item_index++];
        } else {
          ++array_index; ++item_index; // (2)
        }
      }
    } else {
      array[array_index++] = item;
    }
  } while(arg_index !== arguments.length &&
          (item = arguments[arg_index++] || true)
  );
  array.length = array_length;
  return array;
}
  • thisと引数は Arrayであるかどうかをチックされ扱いが変わる(1)
  • 新しい配列にコピーするときに(Arrayであ) thisや引数の疎な部分が省略されることはない(2)
  • thisArrayでない場合単に戻り配列の "0" プロパthisオブジトが入っているというだけである(余計な引数なしで呼び出してArrayでなければ配列化という使い方ができるうれしいか)

 Array.prototype.join(separator)

function(separator) {
  var length = this.length>>>0; // (1)-1
  if(typeof(separator) === "undefined") {
    separator = ",";
  }
  separator = ToString(separator);
  if(length === 0) {
    return "";
  }
  var result;
  var index = 0;
  var item = this[index++];
  item = (item == null) ? "" : ToString(item);
  result = item;
  while(index !== length) { // (1)-2
    item = this[index++];
    item = (item == null) ? "" : ToString(item);
    result += separator + item;
  }
  return result;
}
// argが数値の場合は厳密には違うかも。
// 以後もたびたび登場する予定。
function ToString(arg) {
  return ""+arg.valueOf();
}
  • 0 から数値化された lengthプロパの値までを処理する(1)
  • 戻り値は必ず文字列でありthis.length-1 個のセパレータを必ず含む
  • thisArrayでない場合例えば Array.prototype.join.call({length:10+1}, " ") で長さが 10 のスペースを得ることが期待される

[javascript] ArrayStringの故意に汎用的なメソドたち (2)

 Array.prototype.pop()

function() {
  var length = this.length>>>0;
  if(length === 0) {
    this.length = length; // (1)-1
    return; // undefined
  }
  length -= 1;
  var result = this[length];
  delete this[length];
  this.length = length; // (1)-2
  return result;
}
  • (数値化され) this.length1つデクリメトしたプロパを削除しその値を返す。
  • pop()を呼び出すと副作用で lengthプロパが数値になる(1)

 Array.prototype.push([item1[, item2[, ...]]])

function() {
  var length = this.length>>>0;
  for(var i = 0; i < arguments.length; ++i) {
    this[length++] = arguments[i];
  }
  this.length = length; // (1)
  return length;
}
  • (数値化され) this.lengthをインクリメトしながら引数をプロパに設定していく
  • push()を呼び出すと副作用で lengthプロパが必ず数値になる(1)

[javascript] ArrayStringの故意に汎用的なメソドたち (3)

 Array.prototype.reverse()

function() {
  var length = this.length>>>0;
  var mid = Math.floor(length/2);
  for(var p = 0; p !== mid; ++p) {
    var q = length-p-1;
    var P = this[p], Q = this[q];
    if(!(q in this)) {
      delete[p];
    } else {
      this[p] = Q;
    }
    if(!(p in this)) {
      delete[q];
    } else {
      this[q] = P;
    }
  }
  return this;
}
  • 0 から数値化された lengthプロパの値までを処理する
  • reverse呼び出し前後でプロパ(疎な要素など)が増えたり減ったりはしない

 Array.prototype.sort(comparefn)

sort()についてはthis.length>>>0 が用いられることとthisを変更して thisを返すことだけを書いておいてi, j要素を比較する手順について

function compare(i, j) {
  // (A) 存在しない要素を最後尾へ。
  if(!(i in this)) {
    if(!(j in this)) {
      return +0; // (1)
    } else {
      return 1;
    }
  } else if(!(j in this)) {
    return -1;
  }
  var I = this[i], J = this[j];
  // (B) undefinedな要素を後ろへ。
  if(typeof(I) === "undefined") {
    if(typeof(J) === "undefined") {
      return +0; // (1)
    } else {
      return 1;
    }
  } else if(typeof(J) === "undefined") {
    return -1;
  }

  // (C) ユーザー比較関数
  if(typeof(comparefn) !== "undefined") {
    return comparefn(I, J);
  }
  // (D) デフォルト比較方法 (文字列化して昇順)
  I = ToString(I), J = ToSTring(J);
  if(I < J) {
    return -1;
  } else if(I > J) {
    return 1;
  }
  return +0;
}
  • デフトの比較関数はやっぱり要素を文字列化していた(20080207p01数値配列を期待通りにソトすることはできな)
  • +0 と書いてみたがスクリトで +0-0 を区別することはできない(1)

[javascript] ArrayStringの故意に汎用的なメソドたち (4)

 Array.prototype.shift()

function() {
  var length = this.length>>>0;
  if(length === 0) {
    this.length = length; // (1)
    return; // undefined
  }

  var result = this[0];

  // ひとつずつ前へスライド
  for(var k = 1; k !== length; ++k) {
    if(k in this) {
      this[k-1] = this[k];
    } else {
      delete this[k-1];
    }
  }

  delete this[length-1];
  this.length = length-1;
  return result;
}
  • 0 から数値化された lengthプロパの値までを処理する
  • shift()を呼び出すと副作用で lengthプロパが必ず数値になる(1)

 Array.prototype.unshift([item1[, item2[, ...]]])

function() {
  var length = this.length>>>0;
  // 要素を引数の数だけ後ろへシフト。
  for(var k = length; k !== 0; --k) {
    var j = k-1;
    if(j in this) {
      this[j + arguments.length] = this[j];
    } else {
      delete this[j + arguments.length];
    }
  }
  // 先頭に引数をコピー
  for(var k = 0; k !== arguments.length; ++k) {
    this[k] = arguments[k];
  }

  this.length = length + arguments.length; // (1)
  return this.length;
}
  • 0 から数値化された lengthプロパの値までを処理する
  • unshift()を呼び出すと副作用で lengthプロパが必ず数値になる(1)

[javascript] ArrayStringの故意に汎用的なメソドたち (5)

 Array.prototype.slice(start, end)

function(start, end) {
  var array = [];
  var array_index = 0;
  var length = this.length>>>0;
  start = ToInteger(start);
  start = (start < 0) ? Math.max(length+start, 0) : Math.min(start, length);
  end = (typeof(end) === "undefined") ? length : ToInteger(end);
  end = (end < 0) ? Math.max(length+end, 0) : Math.min(end, length);
  for(var k = start; k < end; ++k) {
    if(k in this) {
      array[array_index++] = this[k];
    } else {
      ++array_index; // (1)
    }
  }
  array.length = array_index;
  return array;
}
function ToInteger(x) {
  x = +x;
  if(isNaN(x)) {
    return +0; // (2)
  }
  if(x === 0 || !isFinite(x)) {
    return x;
  }
  // 0 に近づける。(小数点以下を切り捨てる)
  return (0 <= x) ? Math.floor(x) : Math.ceil(x);
}
  • 数値化された this.lengthと引数 start, end を元に範囲を決定し処理する
  • startendには負数も使用可
  • thisの存在しない要素がコピーされることはないが無視されるわけではない(1)
  • +0 と書いたがスクリトが +0-0 を区別することはできない(2)

 Array.prototype.splice(start, deleteCount[, item1[, item2[, ...]]])

function(start, deleteCount) {
  var array = [];
  var length = this.length>>>0;
  start = ToInteger(start);
  start = (start < 0) ? Math.max(length+start, 0) : Math.min(start, le  deleteCount = ToInteger(deleteCount);
  deleteCount = Math.min(Math.max(deleteCount, 0), length-start);
  // 取り出す要素をコピー。(まだ削除はしない)
  for(var k = 0; k !== deleteCount; ++k) {
    var l = start+k;
    if(l in this) {
      array[k] = this[l];
    }
  }
  // (A) 要素を後ろへずらして空きを作る
  //     (後で上書きされてしまう要素までずらしてない?)
  if(deleteCount < arguments.length) {
    for(var k = length-deleteCount; k !== start; --k) {
      var l = k + deleteCount -1;
      var m = k + arguments.length -1;
      if(l in this) {
        this[m] = this[l];
      } else {
        delete this[m];
      }
    }
  // (B) 要素を前へ詰めて、空きを新要素と同じ数にする
  } else if(arguments.length < deleteCount) {
    for(var k = start; k !== length-deleteCount; ++k) {
      var l = k + arguments.length;
      var m = k + deleteCount;
      if(m in this) {
        this[l] = this[m];
      } else {
        delete this[l];
      }
    }
    // (なぜ逆順で削除する?)
    for(var k = length; k !== length-deleteCount+arguments.length; --k) {
      delete this[k-1];
    }
  }
  // 追加する要素で thisを上書き
  if(arguments.length === deleteCount) {
    for(var k = 0; k !== arguments.length; ++k) {
      this[start+k] = arguments[k];
    }
  }
  this.length = length - deleteCount + arguments.length;
  return array;
}
  • 数値化された this.lengthと引数 start を元に範囲を決定し処理する
  • startには負数も使用可
  • splice()を呼び出すと副作用で lengthプロパが必ず数値になる
  • splice()は仕事を抱え込みすぎ

[javascript] ArrayStringの故意に汎用的なメソドたち (6)

パターンがわかってきた

 Arrayのビトインメソドは concat()を除いてthis.length32-bit unsigned int(UINT32)に変換したものを処理範囲の上限として利用する(下限はもちろん 0)

  • concat()thisや引数が Arrayかどうかで処理を変えるから(利用するとき) this.lengthを直接用いる

 自身の長さを変更するメソ(pop(), push(), shift(), unshift(), splice())を呼び出すと lengthプロパは必ず UINT32に変更される

  • 自身の長さを変更しない reverse(), sort()自身を変更しない concat(), join(), slice()を呼び出しても lengthは変化しない

 あんまり使えない

 Arrayの多くのメソドは自己破壊的でStringに適用することができない

Firefox(JavaScript1.5?)では適用すると Array.prototype.method.call(string) is read-onlyという警告がいくつも出る

一度の呼び出しでいくつも出ることから read-onlyなのはメソドではなく自己破壊的な Array.prototype.method()を適用された stringだと思われる

警告が出るだけで戻り値は得られるので pop()で末尾の文字shift()で先頭の文字が得られる

unshift()push()の返す数値は使えない(その長さを持った文字列は存在しないの)

reverse(), sort()は全く役に立たない役に立つ値を返さないし並べ替えには失敗しているから

slice()String.prototypeに同名のメソドがすでに存在する

splice()がちっと面白くsplice(startdeleteCount) の引数はちょうど String.prototype.substr(start, length)と対応するがってくるのが substr()->"文字" なのに対しsplice()->["","","列"] となる

string.split("")の代わりに Array.prototype.splice.call(string, 0)としてみるのはいかが? (警告が出る上に IE7では使えません)

 そもそも IEJScript5.7では文字列に添え字を使ってアクセスできないので Arrayのメソドを適用しても意味がない

Stringではなく配列のようなオブジ(コレクションとか argumentsとか)に適用するのが正解

 concat()join()は広く使える

 配列化1 (びみ)
// unknown_objectが配列なら unknown_objectのコピー、
// それ以外なら unknown_objectを唯一の要素とする配列が返る。
var array = Array.prototype.concat.call(unknown_object);
 配列化2 (IEでは使えな)
// lengthプロパティと [] での要素アクセスが可能な、
// 配列っぽいオブジェクト(NodeListとか argumentsとか)を配列化。
var array = Array.prototype.slice.call(document.getElementsByTagName("pre"), 0);
 繰り返し文字列 (っこう使え)
// "        " が得られます。
var softtab = Array.prototype.join.call({length:8+1}, " ");
// softtabを使ったレベル3のインデントが得られます。
var indent = new Array(3+1).join(softtab); // prototypeいらねー

二番目の書き方を使うなら Arrayのビトインメソドを他のオブジトに使い回すという趣旨が……

[javascript] ArrayStringの故意に汎用的なメソドたち (7)

今回から String.prototypeのメソStringは自己破壊的なメソドを持っていないからArrayのビトインメソドと違って適用範囲が広いことを期待している

……と思ったがStringのビトインメソドはどれも事前に ToString(this)を呼んでしまう(ToString()については (1))

indexOfで配列の探索ができるんじゃないかと期待していたが無理だったっかり

これにて終了

split()に渡す正規表現のサブマッチに特別な意味があるとかsplit()はグローバルフラグを無視するとかグローバルフラグの立った正規表現で exec(string)を呼んで空文字列にマッチしたときはこちらで lastIndexプロパ1増やさないといけないとかもやもやしてたことが Under Translation of ECMA-262 3rd Editionにはいろいろ書いてありました訳者に感謝


20080207()

[javascript] 普通に使ってて驚いた JavaScriptのヘンなところ

switch-caseのラベル部分に何でも書ける*という変態的な部分は置いておいて1/20.5になるのと同じ類の話

 [1, 5, 10].sort()

返るのは [1, 10, 5]どうも文字列としてソトされている数字だけの配列だ(と自分が知っている)からって無駄な期待をしてはいけない

 for(var i in [1, 5, 10]) { alert(typeof i) }

stringと表示されるi に入るのが配列の要素 1, 5, 10 ではなく添え字(key)だというだけで意外だがさらに意表をついてそれが数字でもなく"0", "1", "2" i+1 としても隣の要素にはアクセスできないarray[1] = 5; と数字の添え字で代入した後でも同じだった

for-inープは遅いと評判だったので使っておらず最近まで知らなかった

ついでにいうと for-inとは別の in 演算子の存在もつい最近まで知らなかった(SHJSのソースを読んで発見し)

グローバル変数の存在確認方法も SHJSを読んで知った今までは typeof(global_var) == "undefined" とやっていたこれは存在確認とは微妙に意味が違う

deleteできるグローバル変数とできないグローバル変数については amachangのブログを読んで知った

 オブジトのプロパ連想配列のキ配列の添え字ぜんぶ同じぜんぶ文字列

  • プロパ名はすべて文字列化されてからオブジトに渡されること
  • 配列は特殊な lengthプロパを持った Object

ということを知っていれば for-inープで文字列が渡されても驚くことはない(ゃあなぜ驚い)

var object = {};
alert(""+ (1==="1")); // false
o[1] = 1;
o["1"] = "1";
alert(""+ (o[1]===o["1"])); // true

var a = [1,2,3];
var b = [1,2,3];
alert(""+ (a===b)); // false
o[a] = a;
o[b] = b;
alert(""+ (o[a]===o[b])); // true

var s = "1,2,3";
alert(""+ (a===s)); // false
o[s] = s;
alert(""+ (o[a]===o[s])); // true

* http://arton.no-ip.info/diary/20061224.html#p02


20080206() パスワドを間違えたときに Caps Lockがオンと教えてくれる Vista

[javascript] 継承prototypeへの代入

こんなやりとりがあった

  1. 404 Blog Not Found:javascript - 勝手に添削 - JavaScript入門
  2. 「勝手に添削 - JavaScript 入門を勝手に添削 - IT戦記

dankogaiの指摘の一つMyObject.prototype = { /* ... */ }は避けるべしについて

MyBox.prototype = Box.prototype; // ここで継承しているのに
MyBox.prototype = {              // ここで台無し
  speed:8
};

指摘には同意するが上の例だと親の Boxにも MyBoxと共通のクラス変数 speedが追加されている

amachangの反論にあるように、継承するなら次の書き方の方が優れている

MyBox.prototype = new Box; // new Box()と同じ

ところでamachangはこう続けているこれがプトタイプ継承の正しい形式であり

MyBox.prototype = {};
MyBox.prototype = new Object;

指摘を受けた上段の書き方は下段のシンタックスシュガーなので両方とも Objectからの正しい継承方法であるこのことがわかっていれば他から継承しておきながら Objectからも継承して台無しにするような間違いは犯さない(だから必要に応じて違う書き方をすれば良いし必要がなければ .prototype={}と書いても良い)

でも違う理由で MyObject.prototype = {}; という書き方は避けている 理由は一つで

MyObject = function(){};
MyObject.prototype = {/* MyObjectの定義 */};
alert(new MyObject().constructor); // function Object(){ [natiive code] } と表示

constructorプロパMyObjectではなくなってしまっているこれは MyObject.prototype = new MyParent; としたときも同じで constructorMyParentになる

constructorプロパだけを気にするなら

MyObject.prototype = { constructor:MyObject.prototype.constructor };

というように明示的にコピーすればごまかせるが一時しのぎ感がぷんぷんしている(constructor以外のプロパが追加されたらその都度書き換えるの)

だから、継承の仕方で逆につっこまれてしまったがdankogaiが提示した 3つの方法に自分は同意していてそのうちの一つ目を自分は使っている


20080204()

[SHJS][javascript] sh_main.jsの高速化

SHJSのブラウザでの実行時間を削るには sh_main.js(SHJSのメイスクリ)を速くするか正規表現を効率的なものにする方法がある(>遅い正規表現(20080116p01))

正規表現に関してできることは限られるうえ知識も少ない(『詳説 正規表現 第三版待ち)ので可能な限り文字クラスや文字集合といわれるものを使うように気を付けただけにとどまる(sh_ruby.js, sh_javascript.js)

メイスクリトの sh_main.jsに対してできることは多いこの日記の現在?の最新ページ(2008112日から7)を表示してsh_highlightDocument()前後での経過時間を表示したところこのようになった

Firefox2IE7(64-bit)IE7(32-bit)Opera9.25
sh_main.js (0.4.2)935ms1050ms1270ms1260±150ms
改変版600ms680ms865ms1200±150ms
削減率36%35%32%5%

ハイラト対象が少なくて数ミリ秒で処理が終わるような場合はオーバーヘドのために改変版の方が 1-2ミリ秒遅くなるがそれよりもスクリトがブラウザをロックする時間が長くなるような場合にこそ速度改善が必要なので OK

代償としてファイルサイズが sh_main.js10.5KiBから 12.7KiB+2.2KiBjsmin圧縮後の sh_main.min.js6.22KiBから 7.82KiB+1.60KiBApacheによる gzip圧縮やブラウザのキッシュに期待します。

 () Operaについて

普段は全く Operaを使わないし詳しくもないむしろ Operaではキーボドを使ったブラウジングもままならないそんな人間が Firefox+Firebugを頼りに sh_main.jsの修正を行ったので Operaの速度が改善しないのは仕方のない部分がある(IEは改善したが)(あんだけいじータルで変わらない方がすごいどこが足を引っぱっているのだろう)リテラル文字列と Stringオブジトの差が他のブラウザより大きいらしいがそれが原因?

EfficientJavaScript - Dev.Opera - 効率的な JavaScript (www.hyuki.com)

Operaでの JavaScriptの実行時間が他のブラウザに比べて長いのははっきりした理由があってOperaはスクリトが全力疾走中であってもユーザーの操作に対する反応を後回しにしたりしないこれは偉いーザーを待たせない代わりにスクリトが遅れるのは当然の代償で仕方がない

スクリトでなく再描画が律速してるから改善しないということ?

 (かんせいしたへびのえにあしをかきくわえるこういとまでは言わない) この日記で使用中のファイルへのリンク

(常に最新版だが一時的にバグが混入していることがあるか)

 追記@日:sh_main.jsをちっと修正

すぐ上のリンク先はすでに変更が反映されている

これら二つの記事を参考に escapeHTML()を変更した測定に使ったページでは 9000回ちかく呼び出されるメソドなので影響はバカにならないといっても 600msったのが 590msを切るようになったというレベルむしろ下請けfunctionを隠蔽できたことの方が嬉しい

escapeHTML()自体sh_builderのインターフェイスではないので外部から呼び出せないようにすべきかもしれないがfunctionをかぶせるたびに呼び出しのオーバーヘドが増える気がしてそうはしていない

 追記@今日

SHJSpatternStackオブジトは外部と完全に独立して動作するのにsh_highlightString()が呼ばれるたびに無名クラスとそのイスタスを作成するような方法がとられているトラクタと prototypeを書こう(sh_highlightString()HTML文書内の <pre class="sh_XXX">の数だけしか呼ばれないから影響は小さい件のページでは 58)

sh_highlightString()からしか使われないのにスタックの可視範囲が広がるのが気になるならっき覚えた無名functionで二つをくるんでしまえば良い

var sh_highlightString = (function(){
  var Stack = function(){
    this.stack_ = [];
  };
  Stack.prototype.getLength = function(){/* ... */};
  // ……
  return function(){
    var patternStack = new Stack();
    /* sh_highlightStringの中身がつづく…… */
  };
})();

まあ速度が改善するわけではないので書き直さないんだけど

 追記@2008-02-25

innerHTMLtextContentinnerTextの使用は堕落だという気もするが冗長な上に呼び出しを重ねることで遅くなる DOMメソドがいけない