Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>Update 2018-07-21:</strong> For a long time, I have felt embarrassed about this answer, so I think it's time that I touch it up a little bit. Just a little commentary, clarification, and formatting to help expedite the reading of the needlessly long and convoluted parts of this answer.</p> <hr> <h1>THE SHORT VERSION</h1> <h1>The actual answer to the question</h1> <p>As others have said, you can use <code>delete</code>. </p> <pre><code>obj // {"foo": "bar"} delete obj["foo"] obj // {} obj["foo"] // undefined </code></pre> <h1>Array equivalent</h1> <p>Don't <code>delete</code> from an array. Use <code>Array.prototype.splice</code> instead.</p> <pre><code>arr // [1,2,3,4,5] arr.splice(3,1); // 4 arr // [1,2,3,5] </code></pre> <hr> <h1>THE LONG VERSION</h1> <p>JavaScript is an OOP Language, so everything is an object, including <em>arrays</em>. Thus, I feel it necessary to point out a particular caveat.</p> <p>In arrays, unlike plain old objects, using <code>delete</code> leaves behind garbage in the form of <code>null</code>, creating a "hole" in the array.</p> <pre><code>var array = [1, 2, 3, 4]; delete array[2]; /* Expected result --&gt; [1, 2, 4] * Actual result --&gt; [1, 2, null, 4] */ </code></pre> <p>As you can see, <code>delete</code> doesn't always work as one might expect. The value is overwritten, but the memory is not reallocated. That is to say, <code>array[4]</code> isn't relocated to <code>array[3]</code>. Which is in contrast to <code>Array.prototype.unshift</code>, which inserts an element in the beginning of the array and shifts everything up (<code>array[0]</code> becomes <code>array[1]</code>, etc.) </p> <p>Honestly, aside from setting to <code>null</code> rather than <code>undefined</code>--which is legitimately weird--this behavior <em>shouldn't</em> be surprising, since <code>delete</code> is an unary operator, like <code>typeof</code>, that is hard-boiled into the language and is not supposed to care about the <em>type</em> of object it's being used on, whereas <code>Array</code> is a subclass of <code>Object</code> with methods <em>specifically designed for</em> working with arrays. So there's no good reason for <code>delete</code> to have a special case cooked in for re-shifting the array, as that would just slow things down with unnecessary work. In retrospect, my expectations were unrealistic.</p> <p>Of course, it <em>did</em> surprise me. Because I wrote this to justify my crusade against "null garbage":</p> <blockquote> <p>Ignoring the dangers and problems inherent in <code>null</code>, and the space wasted, this can be problematic if the array needs to be precise.</p> </blockquote> <p>Which is a terrible justification for getting rid of the <code>null</code>s--<code>null</code> is only dangerous if used improperly, and it has nothing to do with "precision". The real reason you shouldn't <code>delete</code> from an array is because leaving garbage-filled and messy data structures around is sloppy and bug-prone.</p> <p>What follows is a contrived scenario that gets pretty long-winded, so you can skip to the section, <strong>The Solution</strong>, if you want. The only reason I leave this section in is because I think some people probably think it's funny, and I don't want to be "that guy" who posts a "funny" answer and then deletes all the "funny" from it later on. </p> <p>...It's stupid, I know.</p> <h1>The contrived and long-winded PDP-11 scenario</h1> <blockquote> <p>For example, say you are creating a webapp that uses JSON-serialization to store an array used for 'tabs' in a string (in this case, <code>localStorage</code>). Let's also say that the code uses the numerical indices of the array's members to "title" them when drawing to the screen. Why are you doing this rather than just storing the "title" as well? Because... <em>reasons</em>.</p> <p>Okay, let's just say that you're trying to save memory at the request of this <em>one</em> user who runs a PDP-11 minicomputer from the 1960's running UNIX, and wrote his own Elinks-based, JavaScript-compliant, line-printer-friendly browser because X11 is <em>out of the question</em>.</p> <p>Increasingly stupid edge-case scenario aside, using <code>delete</code> on said array will result in <code>null</code> polluting the array, and probably causing bugs in the app later on. And if you check for <code>null</code>, it would straight up skip the numbers resulting in the tabs being rendered like <code>[1] [2] [4] [5] ...</code>. </p> <pre><code>if (array[index] == null) continue; else title = (index + 1).toString(); /* 0 -&gt; "1" * 1 -&gt; "2" * 2 -&gt; (nothing) * 3 -&gt; "4" */ </code></pre> <p>Yeah, that's definitely not what you wanted.</p> <p>Now, you <em>could</em> keep a second iterator, like <code>j</code>, to increment only when valid values are read from the array. But that wouldn't exactly solve the <code>null</code> issue, and you still have to please that <s>troll</s> PDP-11 user. Alas, his computer just <em>doesn't</em> have enough memory to hold that last integer <sub>(don't ask how he manages to handle a variable-width array...)</sub>.</p> <p>So, he sends you an email in anger:</p> <pre><code>Hey, your webapp broke my browser! I checked my localStorage database after your stupid code made my browser segfault, and this is what I found: &gt;"tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... ]" After clearing my precious data, it segfaulted again, and I did a backtrace, and what do I find? WHAT DO I FIND!? YOU USE TOO MANY VARIABLES! &gt;var i = index; &gt;var j = 1; Grr, I am angry now. -Troll Davidson </code></pre> <p>About now, you're at your wit's end. This guy has been complaining non-stop about your app, and you want to tell him to shut up and go get a better computer.</p> </blockquote> <h1>The Solution: <code>Array.prototype.splice</code></h1> <p>Luckily, arrays <em>do</em> have a specialized method for deleting indices and reallocating memory: <code>Array.prototype.splice()</code>. You could write something like this:</p> <pre><code>Array.prototype.remove = function(index){ this.splice(index,1); } ... array = [1, 2, 3, 4]; array.remove(2); // Result -&gt; [1, 2, 4] </code></pre> <p>And just like that, you've pleased Mr. PDP-11. Hooray! <sub>(I'd still tell him off, though...)</sub></p> <h2>Array.prototype.splice vs Array.prototype.slice</h2> <p>I feel it's important to point out the difference between these two similarly-named functions, as they are both very useful.</p> <h3>Array.prototype.splice(start, n)</h3> <p><code>.splice()</code> mutates the array, and returns the removed indices. The array is sliced starting from the index, <code>start</code>, and <code>n</code> elements are sliced out. If n is unspecified, the entire array after <code>start</code> is sliced out (<code>n = array.length - start</code>).</p> <pre><code>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] </code></pre> <h3>Array.prototype.slice(start, end)</h3> <p><code>.slice()</code> is non-destructive and returns a new array containing the indicated indices from <code>start</code> to <code>end</code>. If <code>end</code> is left unspecified, the behavior is the same as <code>.splice()</code> (<code>end = array.length</code>). The behavior is a bit tricky since, for some reason, <code>end</code> indexes from 1 instead of 0. I don't know why it does this, but that's how it is. Also, if <code>end &lt;= start</code>, the result is an empty array.</p> <pre><code>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] </code></pre> <p>That actually isn't what's happening, but it's easier to think of that way. According to MDN, here's what's actually happening:</p> <pre><code>// 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 </code></pre> <p>The index specified by <code>end</code> is simply excluded from the slice. The parenthesized indices indicate what gets sliced. Either way, the behavior is not intuitive and it's bound to cause its fair share of off-by-one errors, so you might find it useful to make a wrapper function to more closely emulate the behavior of <code>.splice()</code>:</p> <pre><code>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" &amp;&amp; num !== num; } function is_number(num){ return !is_nan(num) &amp;&amp; typeof num === "number" &amp;&amp; isFinite(num); } </code></pre> <p>Note that the wrapper function is designed to be very strict about types, and will return <code>null</code> if anything is off. That includes putting in a string like <code>"3"</code>. It is left up to the programmer to be diligent about his types. This is to encourage good programming practice.</p> <h2>Update regarding <code>is_array()</code></h2> <p>This is in regard to this (now-removed) snippet:</p> <pre><code>function is_array(array){ return array !== null &amp;&amp; typeof array === "object" &amp;&amp; typeof array.length !== "undefined" &amp;&amp; array.__proto__ === Array.prototype; } </code></pre> <p>So as it turns out, there actually IS a built-in way to tell if an array is truly an array, and that is <code>Array.isArray()</code>, introduced in ECMAScript 5 (December 2009). I found this while looking to see if there was a question asking about telling arrays from objects, to see if there was either a better solution than mine, or to add mine if there were none. So, if you're using a version of JavaScript that is earlier than ECMA 5, there's your polyfill. However, I strongly recommend against using my <code>is_array()</code> function, as continuing to support old versions of JavaScript means continuing to support the old browsers that implement them, which means encouraging the use of insecure software and putting users at risk for malware. So please, use <code>Array.isArray()</code>. Use <code>let</code> and <code>const</code>. Use the new features that get added to the language. <em>Don't</em> use vendor prefixes. <em>Delete</em> that IE polyfill crap from your website. Delete that XHTML <code>&lt;!CDATA[[...</code> crap, too--we moved to HTML5 back in 2014. The sooner everybody withdraws support for those old/esoteric browsers, the sooner the browser vendors will actually follow the web standard and embrace the new technology, and the sooner we can move on to a more secure web.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload