- < Newer
- Older >
JavaScript: ビット反転とString#indexOf
if(~block.innerHTML.indexOf(this._key))
return;
hatebu - ’ellaneous
これは使える。
// 含むとき
if (~str.indexOf("http://")) {}
// 含まないとき
if (!~str.indexOf("http://")) {}
+1だと後者に括弧が1組増えるとか、含む含まないの判定なのに+1?みたいな違和感があるけど、これだとけっこうすっきりする。
慣れがいるかもだけど。
JavaScript: Iterator関数をhasOwnProperty代わりに使う
いちいちhasOwnPropertyを使わなくてよくする(ジェネレータの使いかた) - 素人がプログラミングを勉強するブログ
多分Firefox2/3限定。JavaScript1.7相当。
Iterator関数を噛ませる方法もあります。
Object.prototype.extend = function(){};
var o = {a:1,b:2,c:3};
for (var i in o) console.log(i);
/* ->
a
b
c
extend
*/
for (var i in Iterator(o)) console.log(i);
/* ->
["a", 1]
["b", 2]
["c", 3]
*/
for each (var i in Iterator(o)) console.log(i);
/* ->
["a", 1]
["b", 2]
["c", 3]
*/
こんな具合になってるので
for (var [i,v] in Iterator(o)) console.log(i); /* -> a b c */ for (var [i,v] in Iterator(o)) console.log(v); /* -> 1 2 3 */ [p[0] for (p in Iterator(o))] // -> ["a", "b", "c"] keys [p[1] for (p in Iterator(o))] // -> [1, 2, 3] values
とか。
微妙に形が変わるのが微妙といえば微妙。
yieldもletも使ってないので、Firefox2のFirebugコンソールでも使えるあたりが強み。
あとArrayでも順序が保証されている(はず)なのでbreakの効くforEachとしても使える。
関連リソース
Iterators and Generators - MDC
One advantage of using Iterator() to access the contents of an object is that custom properties that have been added to Object.prototype will not be included in the sequence.
Iterator() can be used with arrays as well:
JavaScript: document.evaluate、nodeValue、デフォルト名前空間
$gを更新した。
それ絡みで気付いたことのメモ。
nodeValueとtextContent
tmp = xp.snapshotItem(i); ret[i] = tmp.nodeValue || tmp.textContent;
第3引数にtypeofがobjectとなる引数を与えた場合の挙動を改良。
//a/@hrefのようにしてAttribute Nodeを集めたとき、それらのnodeValueプロパティを参照すると属性値(href属性の値)が得られる。
Element Nodeのときはnullになるので、この場合はtextContentをみる。
$g('//a', document, {})
// -> アンカーテキスト
// ["mayokara note", "Older >", ...]
$g('//a/@href', document, {})
// -> href属性値
// ["http://mayokara.info/note/", "http://mayokara.info/note/1", ...]
で、こういうことができる。
ただしa要素のhrefプロパティから取得した場合とは違い、Absolute URIにはならない。
Relative URIで書かれているものは、そのまま。
デフォルト名前空間について
var doc = context.ownerDocument || context, defaultNamespaceURI = (/xml$/).test(doc.contentType) ? doc.documentElement.getAttribute("xmlns") : "";
var resolver = function(prefix){
return doc.createNSResolver(context).lookupNamespaceURI(prefix) || defaultNamespaceURI;
};
XHTMLのみを対象とするのならhttp://www.w3.org/1999/xhtml決め打ちで良いのだけど、RSS 1.0を(GM_)XMLHttpRequestで取得してDOMParserに食わせたものにXPathを使いたいときはhttp://purl.org/rss/1.0/を返す必要がある。
Atomであればhttp://www.w3.org/2005/Atom。
そういうときのための修正。
デフォルトリゾルバは XML 文書のデフォルト名前空間を処理しません。
Introduction to using XPath in JavaScript - MDC # XML 文書のデフォルト名前空間を実装する
createNSResolverはdcやらrdfやらに引っ掛らなかったときにデフォルト名前空間のURIを返さない。nullが返る。
なので、documentElementのxmlns属性を見て、それを返すようにする。
namespaceURIプロパティは、RSS 1.0のようにdocumentElementのnodeNameがrdf:RDFのときxmlns:rdfのURIを返してくるので使えない。
デフォルト名前空間を含め、名前空間の接頭辞は宣言している要素とその子孫で有効ですが、子孫要素で同じ接頭辞(あるいはデフォルト)の名前空間が宣言されると、その内部では新しい宣言によって結びつきが上書きされます。
XML名前空間の簡単な説明 # デフォルト名前空間
厳密にはcontextから(取得されるノードから?)遡って調べなければならないのだけど、手を抜いた。
やるとすれば、contextの兄弟ノードとして適当なノードをinsertして、それのnamespaceURIプロパティを取るのが楽そう。
ついでに、きちんとcreateNSResolverを使うようにした(dc:dateなどのため)。
余録:Firefox2のDOMParser
RSS 1.0を食わせたとき、documentElementの子要素以下のノードが取れない。
Bugzillaにあたってみたけど、探すのに不得手なせいで見つけられなかった。
Firefox3だとちゃんと取れる模様。
JavaScript: コマンド文字列からC言語のargv相当を取得する
Core JavaScript 1.5 Reference:Global Objects:String:split - MDC
String.prototype.splitの罠 - 素人がプログラミングを勉強するブログ
String#splitの挙動と後方参照を利用すればできそう。
matchだとgフラグ立てたとき括弧の中身まで取れない。
正攻法だとRegExp#execでgフラグ立ててwhileなんだろうけど、while使いたくないし一時変数も用意したくないし1個1個pushとかもいや。
yフラグも同上。
var str = "grep \"ho\\\"ge\" 'fu\\'ga' piyo \"hello work!\"";
str
// -> "grep "ho\"ge" 'fu\'ga' piyo "hello work!""
str.split(/(["']?)((?:\\.|[^\\])*?)\1(?:\s+|$)/)
.filter(function(v,i){ return (i%3 === 2); })
.map(function(v){ return v.replace(/\\(["'\\])/g, "$1"); })
// -> ["grep", "ho"ge", "fu'ga", "piyo", "hello work!"]
追記
$ echo he\llo hello $ echo "he\llo" he\llo $ echo he\"llo he"llo $ echo 'he\"llo' he\"llo
Cygwinでやってみたんだけど、何か上のじゃだめっぽい……
JavaScript: 継承(attach、from)
JavaScript: Sub.prototype = Super.prototype; が駄目な理由 - mayokara note
以前書いたattach関数が何度もSuperClassって書かなきゃいけなくて微妙だったので手直し。
var attach = function(b,p){
var F = function(){};
F.prototype = b;
var o = new F();
for (var i in p) {
var g = p.__lookupGetter__(i), s = p.__lookupSetter__(i);
if (g || s) {
if (g) o.__defineGetter__(i, g);
if (s) o.__defineSetter__(i, s);
} else {
o[i] = p[i];
}
}
return o;
};
var from = function(b,c,p){
c.prototype = attach(b.prototype, p);
c.prototype.__super__ = b;
return c;
};
var Animal = function(){
console.log("Animal: called");
};
Animal.prototype = {
bark: function(){
console.log("Animal#bark: ...");
},
};
var Dog = from(Animal, function(){
this.__super__.apply(this, arguments);
console.log("Dog: called");
}, {
bark: function(){
console.log("Dog#bark: bowwow");
},
});
var animal = new Animal(); // -> Animal: called animal.bark(); // -> Animal#bark: ... var dog = new Dog(); // -> Animal: called // -> Dog: called dog.bark(); // -> Dog#bark: bowwow
dog instanceof Dog // -> true dog instanceof Animal // -> true animal instanceof Dog // -> false dog.__proto__ === Dog.prototype // -> true dog.__proto__.__proto__ === Animal.prototype // -> true dog.__proto__.__proto__.__proto__ === Object.prototype // -> true dog.__proto__.__proto__.__proto__.__proto__ === null // -> true
単に引数増やしてthis.__super__を用意しただけ。
まあ、this.__super__潰さなくてもAnimalって直接呼べばいいんだけど、毎回書き方変わるの気持ち悪いな、ってことで。
this.__super__.prototype.barkで親クラスのbarkが呼べたりとか、そんな感じ。
追記
致命的な欠陥があったので修正。
JavaScript: application/xhtml+xmlなページを扱う際の注意
application/xhtml+xmlなページでcontinue_reading.user.jsが動かない問題が解決した。
既に更新済。以下覚書。
Range#createContextualFragmentでillegal string例外が起こる
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
この2行のせい。
つまり、<\?\w+とか<!\w+でこけている。
<--(HTMLにおけるコメント)は通る。
というわけで
var html = str.replace(/^[\s\S]*<html[^>]*>|<\/html>[\s\S]*$/ig, "");
解決。
innerHTMLに代入しようとすると例外が起こる
innerHTML、読み取り専用っぽい。
というわけで、DOM関数で組み立ててappendChildして解決。
余録:document.implementation.createDocument
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-102161490
var doc = document.implementation.createDocument("", "html", null);
でOK。
第2引数はdocumentElementを参照するために必要。
余録:Range#createContextualFragment
html/body要素が消える。
Firefox2ではhead要素も消え、事前にrange.setStartAfter(document.body)などとして何らかの選択をしないと評価されない。
「continue_reading.user.js」更新 その2
Greasemonkey: continue_reading.user.js - mayokara note
- loadedURLsを保持するようにした
- from AutoPagerize
- 3→2→3→2→……みたいなパターンを回避できる
- Google Images用のDocumentFilterを添付した
- ソースの冒頭部でON/OFF可能(デフォルトはON)
- DocumentFilterはnextLinkを引数に取る
- iframeで読んでメインのtableを置き換える
- DOMContentLoaded使用
- from oAutoPagerize, AutoPageLoader
- パース時の処理をtry catchで括った
Google Imagesはウィンドウサイズに応じてカラム数を変えてくる
iframe.style.width = document.documentElement.clientWidth + "px"で対処。
overflow: hidden; width: 1px; height: 1px;なdiv要素で隠す。
document.adoptNode(node)とdocument.importNode(node, true)
外部ドキュメントからのノードは、現在のドキュメントに挿入する前に importNode() を使ってクローンを作る (あるいは adoptNode() を使って取り込む) べきです。
DOM:document.adoptNode - MDC
エラーは出さないけど、使うべきだそうな。
- document.adoptNode(node)
- 他のドキュメントのnodeをdocumentの所属にする
- 読み込み中のimg要素を移した後、元のドキュメントを閉じると、読み込みが完了しない
- document.importNode(node, true)
- 他のドキュメントのnodeをdocumentに複製する
- 読み込み中のimg要素を移した後、元のドキュメントを閉じても、読み込み続ける
iframe.contentWindow.addEventListener("DOMContentLoaded", F, false)
iframe.style.display = "none"だと発生しない(Firefox2だけ?
iframe.style.visibility = "hidden"の場合は問題ない。
application/xhtml+xmlなページのときRange#createContextualFragmentするとillegal characterエラー
相変わらず、さっぱり意味がわからない。
GM_xmlhttpRequestでoverrideMimeTypeをtext/htmlにしてるのがまずいのかなあ。
JavaScript: add/removeEventListenerラッパー
var ELController = function(target, type, handler, useCapture){
return {
on: function(){
target.addEventListener(type, handler, useCapture);
},
off: function(){
target.removeEventListener(type, handler, useCapture);
},
};
};
var onclick = new ELController(window, "click", function(){
alert(1);
}, false);
(click) // -> none
onclick.on();
(click) // -> alert(1)
onclick.off();
(click) // -> none
クロージャを使って直接オブジェクトを返す形にすると、this._typeなどとして値を保持する必要がなくなる。
Firefox上では、EventListenerという名前はDOM2 EventsのEventListenerインタフェースとして、既に使われているみたい。
複数の同一の EventListener が、同じ EventTarget に同じ引数で登録された場合、重複するインスタンスは反映されません。EventListener が 2 度呼び出されることはなく、重複するインスタンスは反映されないので、removeEventListener で手動で削除する必要はありません。
DOM:element.addEventListener - MDC
イベントターゲット上にある現在のどのイベントリスナーも指定していない引数付きの removeEventListener は、何の効果もありません。
DOM:element.removeEventListener - MDC
イベントリスナは関数(というより、EventListenerインタフェース)単位で管理されているようで、連続でonしても1度しか実行されず、onしていない状態でoffしても特にエラーにはならない。
なので、状態を記憶して実行を制御しなくてもOK。
コンストラクタ関数の返り値とnew
コンストラクタ関数は別のオブジェクトを返り値として返すことも可能で、その場合は返されたオブジェクトがnew式の値となる。thisの値であったオブジェクトは破棄される。
JavaScript 第5版 - 9章 クラスとコンストラクタとプロトタイプ(1) - (DxD)∞
newをハッタリに使える。結果は関数呼び出しのときと同じ。
インスタンス生成とオブジェクト返却の比較
- インスタンス生成
- __proto__にprototypeを繋ぐだけなのでコストが小さい
- 内部値がpublicになってしまう
- オブジェクト返却
- 毎回オブジェクトを作って返すのでわずかにコストがかかる
- 内部値をprivateにできる
livedoor Readerのj/kをマウスで

livedoor Readerのこの辺を
- 左クリックでj
- 右クリックでk
できるのに気づいた。
正確にはj/kじゃなくて、s/aも含めた前後移動機能みたいだけど。
ちゃんと先読みもしてくれるし、良い。
最速インターフェース研究会 :: livedoor Readerの自動スクロール機能
左クリック→左クリック押しっぱなしで、クリック間隔に応じた自動スクロールもできるとのこと。
この機能自体は知ってたんだけど、j/kの代わりにできるってことまでは考えてなかった。
追記
ホイール回すとs/aになる。
Re: GreasemonkeyからNode定数やKeyEvent定数を使う場合の注意点
GreasemonkeyからNode定数やKeyEvent定数を使う場合の注意点 - 素人がプログラミングを勉強するブログ
グローバル空間以外でクロージャを作って、自前でインスタンスを用意する方法もあります(クロージャを用意しないとエラーになる)。
// ==UserScript==
// @name use some constant values with evalInSandbox
// @namespace http://mayokara.info/
// @description sample script
// @include http://*
// ==/UserScript==
(function(){
const Node = document.createElement("div");
const KeyEvent = document.createEvent("KeyboardEvent");
alert(Node.TEXT_NODE);
// -> 3
alert(KeyEvent.DOM_VK_RETURN);
// -> 13
})();
varで宣言すればグローバル空間でもクロージャを作らなくてもいけるようですが、変更されると困る類のもの定数なのでおすすめしません。
関連リンク
http://mxr.mozilla.org/mozilla1.8/source/dom/public/idl/core/nsIDOMNode.idl
http://mxr.mozilla.org/mozilla1.8/source/dom/public/idl/events/nsIDOMKeyEvent.idl
追記
セキュリティ的に問題がありますが、一応以下の方法でも取得はできます。
危険なので使用すべきではありません。
alert(Node.wrappedJSObject.TEXT_NODE); // -> 3 alert(unsafeWindow.KeyEvent.DOM_VK_RETURN); // -> 13
- < Newer
- Older >