以下のようにオブジェクトを作成するとします。
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
プロパティ regex
を削除して、次のように新しい myObject
を作成するには、どのようにすればよいでしょうか。
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI"
};
こんな感じで。
delete myObject.regex;
// or,
delete myObject['regex'];
// or,
var prop = "regex";
delete myObject[prop];
デモ <! -- begin snippet: js hide: false console: true babel: false -->
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
delete myObject.regex;
console.log(myObject);
<! -- スニペットの終了 -->
もっと詳しく知りたい方は、Stack Overflowのユーザーであるkangaxさんが、ご自身のブログ「Understanding delete」で、delete
文について驚くほど詳細なブログ記事を書いています。これはとてもお勧めです。
var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
delete myObject.regex;
console.log ( myObject.regex); // logs: undefined
<! -- スニペットの終了 -->
これは、FirefoxとInternet Explorerで動作し、他のすべての環境でも動作すると思います。
Update 2018-07-21: 長い間、この回答を恥ずかしいと思っていたので、そろそろ少し触ってみようと思います。この回答の無駄に長くて複雑な部分を読みやすくするために、ちょっとした解説や説明、フォーマットをしてみました。
obj // {"foo": "bar"}
delete obj["foo"]
obj // {}
obj["foo"] // undefined
配列から delete
を使ってはいけません。代わりに Array.prototype.splice
を使用してください。
arr // [1,2,3,4,5]
arr.splice(3,1); // 4
arr // [1,2,3,5]
var array = [1, 2, 3, 4];
delete array[2];
/* Expected result --> [1, 2, 4]
* Actual result --> [1, 2, null, 4]
*/
ご覧のとおり、delete
は必ずしも期待通りには動作しません。値は上書きされますが、メモリは再割り当てされません。つまり、array[4]
がarray[3]
に再配置されることはありません。これはArray.prototype.unshift
とは対照的です。Array.prototype.unshift
は配列の先頭に要素を挿入し、すべてをシフトアップします(array[0]
がarray[1]
になるなど)。
正直なところ、undefined
ではなくnull
に設定すること(これは本当に奇妙なことです)を除けば、この動作は驚くべきことではありません。なぜなら、delete
はtypeof
のような単項演算子で、言語にハードボイルドに組み込まれており、使用されるオブジェクトのタイプを気にしないことになっているのに対し、Array
はObject
のサブクラスで、配列を扱うために特別に設計された*メソッドを持っているからです。ですから、delete
に配列を再シフトするための特別なケースを用意する正当な理由はありませんし、それは無駄な作業で物事を遅らせるだけです。振り返ってみると、私の期待は現実的ではありませんでした。
もちろん、それは私を驚かせました。なぜなら、私は「null garbage」に対する私の聖戦を正当化するためにこのように書いたからです。
null
に内在する危険性や問題点、無駄になるスペースを無視して、配列が正確である必要がある場合には、これは問題になります。 これは
nullをなくすためのひどい正当化です。
null`は不適切に使用された場合にのみ危険であり、「精度」とは何の関係もありません。配列から「削除」してはいけない本当の理由は、ゴミだらけの厄介なデータ構造を放置しておくのは、ずさんでバグが発生しやすいからです。 この後の話は、かなり長いシナリオを想定していますので、「解決策」のセクションまで読み飛ばしていただいても構いません。このセクションを残す理由は、おそらく面白いと思う人がいると思うからで、「面白い」回答を投稿して、後でその「面白い」部分をすべて削除してしまうような「あの男」にはなりたくないからです。 ...バカですよね、私。♪ 工夫された長文のPDP-11のシナリオ
例えば、JSONシリアライズを使って、「タブ」に使う配列を文字列(ここでは
localStorage
)に格納するWebアプリを作っているとしましょう。また、コードでは、画面に描画する際に、配列のメンバーの数値インデックスを使用して「タイトル」を付けているとします。単に「タイトル」も保存するのではなく、なぜこのようなことをするのでしょうか?それは...理由です。 この人は1960年代のPDP-11ミニコンピュータでUNIXを動かしていて、X11は問題外なので、ElinksベースでJavaScriptに準拠したラインプリンタ対応のブラウザを自分で書いています。 ますます馬鹿げたエッジケースのシナリオはさておき、前記の配列にdelete
を使用すると、null
が配列を汚染することになり、おそらく後にアプリのバグの原因となるでしょう。また、null
をチェックすると、そのまま数字がスキップされてしまい、タブが[1] [2] [4] [5] ...
のようにレンダリングされてしまいます。 if (array[index] == null) 続けます。 else title = (index + 1).toString(); / 0 -> "1"
- 1 -> "2"
- 2 -> (無)
- 3 -> "4" */ ええ、これは間違いなくあなたが望んでいたものではありません。 ここで、
j
のような第2のイテレータを用意して、配列から有効な値が読み込まれたときだけインクリメントするようにすることは可能です。しかし、それではnull
の問題は正確には解決しませんし、PDP-11 のtrollユーザーを満足させなければなりません。残念ながら、彼のコンピュータには最後の整数を保持するのに十分なメモリがありません (可変幅の配列をどうやって処理するのかは聞かないでください...)。 そこで、彼はあなたに怒りのメールを送ります。 おい、お前のウェブアプリが俺のブラウザを壊したぞ!?あなたの馬鹿げたコードのせいでブラウザがセグメンテーションした後、私のlocalStorageデータベースをチェックしたところ、以下のことがわかりました。 tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, ... ] 。]" 貴重なデータをクリアした後、再びセグメンテーションが発生したので、バックトレースをしてみたところ、何が出てきたか?何を見つけたって?変数を使いすぎです。 var i = index; var j = 1; Grr, I am angry now. -Troll Davidson 今頃、あなたは途方に暮れていることでしょう。この人はあなたのアプリについて延々と文句を言っていて、あなたは彼に黙ってもっといいコンピュータを買いに行けと言いたいのです。解決策:
Array.prototype.splice
(Array.prototype.splice)幸いなことに、配列にはインデックスを削除してメモリを再割り当てするための特殊なメソッドがあります:
Array.prototype.splice()
.以下のように書くことができます。
Array.prototype.remove = function(index){
this.splice(index,1);
}
...
array = [1, 2, 3, 4];
array.remove(2);
// Result -> [1, 2, 4]
これで、PDP-11さんを喜ばせることができました。ばんざーい!(それでも私は彼を諭しますが...)。
この2つの似たような名前の関数の違いを指摘することは重要だと思います。
.splice()は、配列を変異させ、削除したインデックスを返します。配列はインデックス
startから始まり、
n個の要素が切り取られます。n が指定されていない場合は、
start以降の配列全体がスライスされます (
n = array.length - start`)。
let a = [5,4,3,2,1];
let chunk = a.splice(2,2);
// a [5,4,3,2,1]
// start 0 1 2 - -
// n - - 1 2 -
chunk; // [3,2]
a; // [5,4,1]
.slice()は非破壊で、
startから
endまでの指示されたインデックスを含む新しい配列を返します。end
が指定されていない場合は、.splice()
(end = array.length
) と同じ動作になります。なぜかend
は0ではなく1からインデックスを作成するので、この動作は少しトリッキーです。また、end <= start
とすると、結果は空の配列となります。
let a = [5,4,3,2,1];
let chunks = [
a.slice(2,0),
a.slice(2,2),
a.slice(2,3),
a.slice(2,5) ];
// a [5,4,3,2,1]
// start 0 1 2 - -
// end, for... - - - - -
// chunks[0] 0 - - - - -
// chunks[1] 1 2 - - -
// chunks[2] 1 2 3 - -
// chunks[3] 1 2 3 4 5
chunks; // [ [], [], [3], [3,2,1] ]
a; // [5,4,3,2,1]
実際にはそうなっていないのですが、その方が考えやすいですよね。MDNによると、実際に起こっていることは以下の通りです。
// a [5,4,3,2,1]
// start 0 1 2 - - -
// end, for... - - - - - -
// chunks[0] 0 - - - - -
// chunks[1] 0 1 2 - - -
// chunks[2] 0 1(2)3 - -
// chunks[3] 0 1(2 3 4)5
endで指定されたインデックスは、単純にスライスから除外されます。括弧で囲まれたインデックスは、何がスライスされるかを示しています。どちらにしても、この動作は直感的ではなく、1つ違いのエラーを引き起こす可能性があるので、
.splice()`の動作をより忠実に再現するラッパー関数を作るとよいでしょう。
function ez_slice(array, start = 0, n = null){
if(!Array.isArray(array) || !is_number(start))
return null;
if(is_number(n))
return array.slice(start, start + n);
if(n === null)
return array.slice(start);
return null;
}
ez_slice([5,4,3,2,1], 2, 1) // [3]
ez_slice([5,4,3,2,1], 2) // [3,2,1]
/* Fun fact: isNaN is unreliable.
* [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(isNaN)
* [NaN, {}, undefined, "Hi"]
*
* What we want is...
*
* [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(is_nan)
* [NaN]
*/
function is_nan(num){
return typeof num === "number"
&& num !== num;
}
function is_number(num){
return !is_nan(num)
&& typeof num === "number"
&& isFinite(num);
}
このラッパー関数は型に対して非常に厳密に設計されており、何か外れた場合には null
を返すことに注意してください。これには "3"
のような文字列を入れることも含まれます。型に関してはプログラマの努力に委ねられています。これは良いプログラミングの実践を促すためです。
is_array()
に関する更新これは、この(今は削除された)スニペットに関するものです。
function is_array(array){
return array !== null
&& typeof array === "object"
&& typeof array.length !== "undefined"
&& array.__proto__ === Array.prototype;
}
ECMAScript 5 (2009年12月) で導入された Array.isArray()
です。これを見つけたのは、配列とオブジェクトの見分け方についての質問があるかどうかを確認していたときで、私よりも優れた解決策があるかどうかを確認したり、何もなければ私の解決策を追加したりしていました。ですから、もしあなたがECMA 5より前のバージョンのJavaScriptを使っているのであれば、これがあなたのポリフィルです。なぜなら、古いバージョンのJavaScriptをサポートし続けることは、それを実装している古いブラウザをサポートし続けることを意味し、安全でないソフトウェアの使用を促進し、ユーザーをマルウェアのリスクにさらすことになるからです。ですから、Array.isArray()
を使ってください。また、let
やconst
を使ってください。言語に追加される新機能を使いましょう。ベンダープレフィックスを使わないでください。あなたのウェブサイトからIEポリフィルのゴミを削除してください。XHTMLの「<!CDATA[[...`]」も削除してください。私たちは2014年にHTML5に移行しました。皆が古いブラウザや難解なブラウザのサポートをやめれば、ブラウザベンダーはウェブ標準に沿って新技術を採用するようになり、より安全なウェブに移行できるようになります。