C++とはC#とどう違うのか?
正直な話「似たようなモノ」などとは思っていないが、全くの素人が始めるよりは少しはアドバンテージがあるだろうか?などと思いながらVS2008でC++を触ってみた。
C++を触ってみた
RGB値からHTMLカラーコードに変換する
RGB値(255,255,255 など)からHTMLカラーコード(#FFFFFFなど)に変換する。
ついでにできるだけ最速の方法を模索してみたいと思います。
JavascriptでpadLeft
C#で言うところの『padLeft』がほしい、ということで書いてみた。
String.prototype.padLeft = function(len, chr){ return len < 1 ? this : (function(c){ var ret = ''; while (ret.length < len) ret += c; return ret; })(chr.substr(0, 1) || '0') + this; } alert("1".padLeft(4, "0")); //0001
しかし、何か気に入らないのでWebで調べると、どうもprototype.jsで同じような関数があることが分かった。
必要なのは『
times
』関数。で、それに少々手を加えてみる。この中身を見ると、自身の文字列の長さを無視しているので、このままだと埋める文字の長さが一文字以上だとおかしな結果になるので『
this.substr(0, 1) || ''
』とした。まあ余計な対応かもしれないが不必要なら削除すれば良い。以下が最終的な形。
String.prototype.times = function(len){ return len < 1 ? '' : new Array(++len).join(this.substr(0, 1) || ''); } String.prototype.padRight = function(len, chr){ return this + chr.times(len - this.length); } String.prototype.padLeft = function(len, chr){ return chr.times(len - this.length) + this; }処理速度的には私が書いたものとほとんど変わらないが、コードはすっきりしているのでこちらの方が良いだろう。
padRight
が必要ないならtimes
を分けて書く必要がないので、下記のように併せてしまえばもっと処理は速くなる。String.prototype.padLeft = function(len, chr){ return len < 1 ? this : new Array(++len - this.length).join(chr.substr(0, 1) || '') + this; }
2進数、10進数、16進数の相互変換
Javascriptで2進数、10進数、16進数の相互変換を行う。
10進数が絡むと簡単なのだが、2進数から16進数やまたその反対への変換には一旦10進数を経由する必要がある。
もっと良くならないかといろいろ試し、自分で処理を書いてみたりしたが、結局素直に下記のようにするのが処理速度的にも一番速かった。
var foo; //16進数→2進数 foo = parseInt("a", 16).toString(2); //1010 //16進数→10進数 foo = parseInt("a", 16); //10 //10進数→2進数 foo = (10).toString(2); //1010 foo = 0xA.toString(2); //1010 //10進数→16進数 foo = (10).toString(16); //a //2進数→10進数 foo = parseInt("1010",2); //10 //2進数→16進数 foo = parseInt("1010",2).toString(16); //a
因みに16進数のリテラルは内部的には10進数に置き換えられちゃうようですね。要するに変換の必要なしで型は『Number』になり、例えば『0xA』を参照すると『10』が返ってきます。16進数を扱うときは大概文字列で扱ってたので知りませんでした。
参考
参考までに16進数から2進数に変換する処理を載せておきますが、ボツネタなんで適当にスルーして下さい。単純に16進数の一文字を2進数に変換するだけなら以下のようにすれば良い。
String.prototype.hexToBin = function(){ return { "0": "0000", "1": "0001", "2": "0010", "3": "0011", "4": "0100", "5": "0101", "6": "0110", "7": "0111", "8": "1000", "9": "1001", "A": "1010", "B": "1011", "C": "1100", "D": "1101", "E": "1110", "F": "1111" }[this.toUpperCase()] || ""; } alert("F".hexToBin()); //1111
しかし、符号やプレフィックス("0x")の有無、そして小数点を考慮すると以下のような処理が必要になる。
String.prototype.hexToBinary = function(){ var sep = this.match(/^-/) ? "-" : "", hxs = this.replace(/(-|0x)/g,"").split("."), ret = [], tmp, hx; for (var i = 0; i < hxs.length; i++) { tmp = ""; hx = hxs[i]; for (var k = 0; k < hx.length; k++) tmp += hx.charAt(k).hexToBin(); ret.push(tmp); } return sep + ret.join("."); } alert("-0xF.A7".hexToBinary()); //-1111.10100111
処理速度的に上に書いたシンプルなものには及ばないのでボツとなりました。
Javascript 型判定の方法とその処理速度について
わりといい加減だった型判定について、確認の意味も込めてここに。
今後のためにも、頭の中を整理してみる。
型の判定に良く使用するもの
- ===
- typeof
- instanceof
- constructor
それぞれに利点があり、状況によって使い分けることになるが、処理速度は上記の順の通り、『===』が最も速い。
つまり、『===』<『typeof』<『instanceof』<『constructor』
下図はFirebugで計測した結果です。環境によって数値は変わると思われ、参考値としてご覧下さい。
100万回 for loopで回した処理に掛った時間
※『*constructor』は後に説明します。
一部、扱う型によって処理速度に差が見られた。
その二つの例外を以下に説明します。
存在しない変数を参照した場合の『undefined』について
var a; alert(typeof a);通常は上記のような場合、"undefined"が返ります。
変数に何も入ってなくとも、変数自体は存在する場合、処理に掛る時間は上図の通り、14ms程度だったのが、この変数"a"が存在しなかった場合はそれとは異なる結果が出た。
alert(typeof a);//aは存在しないこのような場合、エラーとはならず、処理に980msほど掛った。
『constructor』で型判定する場合について
上図に『*constructor』という値があります。これは『
foo.constructor == Number
』などのように、以下の三つの型の変数のconstructor
で型判定を行う場合の処理に掛る時間です。- Boolean
- String
- Number
その処理にかかる時間が上のグラフの『*constructor』の値となります。
さすがにこれほど差があると気になりますね。
しかし、Firebugでしか計測してませんので、あくまで参考までに。
上記のことを考慮しながら、型判定を行う関数を書いてみます。
Sample Code
function getType(o){ //処理速度 6:14:115:385 //『===』<『typeof』<『instanceof』<『constructor』 // typeof null => object if (o === null) return 'null'; //o === undefined => undefinedに代入可能なため× //o == undefined => null == undefind はtrueなので× if (typeof o == 'undefined') return 'undefined'; if (typeof o == 'boolean') return 'boolean'; if (typeof o == 'string') return 'string'; if (typeof o == 'number') return 'number'; // typeof array => object if (o instanceof Array) return 'array'; // typeof regexp => object // regexp instanceof Object => true if (o instanceof RegExp) return 'regexp'; // typeof date => object if (o instanceof Date) return 'date'; if (typeof o == 'function') return 'function'; if (typeof o == 'object') return 'object' return 'unknown'; }この関数自体では処理速度を向上させることにはなりません。
あくまで処理速度を考慮しながら個々の型に対する正確な判定を行っているにすぎないということです。
因みにjQueryのメソッドには型判定を行う『isFunction』や『isArray』がある。
この中身は、というと以下のようになっている。
var toString = Object.prototype.toString; //... isFunction: function( obj ) { return toString.call(obj) === "[object Function]"; }, isArray: function( obj ) { return toString.call(obj) === "[object Array]"; },調べてないが果たしてこれが最速(最適)なのか?
undefinedについて
undefined
は何ともおかしな代物なので、私はundefined
をundefined
足らしめる、ということをたまに行います。例えば、こんな感じで。
undefined = function(){return}(); var a; alert(a === undefined);//trueとか
(function( undefined ){ var a; alert(a === undefined);//true })();みたいな感じで、確実に
undefined
がundefined
であることを意識します。