Припустимо, я створюю об'єкт наступним чином:
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];
Демонстрація
var myObject = {
"ircEvent": "PRIVMSG",
"method": "newURI",
"regex": "^http://.*"
};
delete myObject.regex;
console.log(myObject);
Для тих, кому цікаво почитати про це детальніше, користувач Stack Overflow kangax написав неймовірно глибоку статтю про оператор `delete у своєму блозі, Розуміння delete. Настійно рекомендується до прочитання.
var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
delete myObject.regex;
console.log ( myObject.regex); // logs: undefined
Це працює в Firefox і Internet Explorer, і я думаю, що працює у всіх інших.
Оновлення 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[0]
стає array[1]
і т.д.).
Чесно кажучи, окрім того, що він встановлюється в null
, а не в undefined
, що дійсно дивно, така поведінка не повинна дивувати, оскільки delete
є унарним оператором, як і typeof
, який жорстко вбудований в мову і не повинен перейматися типом об'єкту, над яким він використовується, тоді як Array
є підкласом Object
з методами, спеціально призначеними для роботи з масивами. Отже, немає жодної вагомої причини для delete
мати спеціальний випадок для повторного переміщення масиву, оскільки це лише сповільнило б роботу непотрібною роботою. Оглядаючись назад, мої очікування були нереалістичними.
Звичайно, це мене здивувало. Тому що я писав це, щоб виправдати свій хрестовий похід проти &quo ;нульового сміття&quo ;:
Ігноруючи небезпеки і проблеми, властиві
null
, і простір, що витрачається даремно, це може бути проблематично, якщо масив повинен бути точним. Що є жахливим виправданням для позбавлення відnull
-null
небезпечний тільки при неправильному використанні, і це не має нічого спільного з "точністю". Справжня причина, по якій не слід "видаляти" з масиву, полягає в тому, що залишати навколо себе засмічені та безладні структури даних - це неохайно і може призвести до помилок. Далі буде описано надуманий сценарій, який стає досить затяжним, тому ви можете перейти до розділу Рішення, якщо хочете. Єдина причина, чому я залишаю цей розділ, полягає в тому, що я думаю, що деякі люди, ймовірно, вважають це смішним, і я не хочу бути "тим хлопцем", який публікує "смішну" відповідь, а потім видаляє все "смішне" з неї пізніше. ...Це безглуздо, я знаю.Надуманий і довгограючий сценарій НДП-11
Припустимо, ви створюєте веб-додаток, який використовує JSON-серіалізацію для зберігання масиву, використовуваного для вкладок, в рядку (в даному випадку
localStorage
). Припустимо також, що код використовує числові індекси членів масиву для "заголовка" їх при виведенні на екран. Чому так робиться, а не просто зберігається "заголовок"? Тому що... причини. Гаразд, давайте просто скажемо, що ви намагаєтеся заощадити пам'ять на прохання цього одного користувача, який працює на міні-комп'ютері PDP-11 1960-х років під управлінням UNIX і написав свій власний браузер на основі Elinks, сумісний з JavaScript, дружній до рядкового принтера, тому що про X11 не може бути й мови. Якщо не брати до уваги все більш безглузді крайні випадки, то використанняdelete
для вказаного масиву призведе до забруднення масивуnull
, що, ймовірно, спричинить помилки в додатку пізніше. А якщо ви перевірите наnull
, то просто пропустите числа, в результаті чого табуляція буде виглядати як[1][2][4][5] ...
. if (array[index] == null) продовжити; інакше title = (index + 1).toString(); /* 0 - > "1";
- 1 - > "2"; 2 - > "3"; 1 - > "4";
- 2 - > (нічого)
- 3 - > "4" (нічого); / Так, це точно не те, чого ви хотіли. Можна було б залишити другий ітератор, наприклад,
j
, щоб він збільшувався тільки тоді, коли з масиву зчитуються допустимі значення. Але це не зовсім вирішило б проблему "нуля", і вам все одно доведеться догоджати томутролюкористувачу PDP-11. На жаль, його комп'ютеру просто не* вистачає пам'яті, щоб вмістити це останнє ціле число (не питайте, як йому вдається працювати з масивом змінної ширини...). Отже, він в гніві відправляє вам електронного листа: Привіт, твій веб-додаток зламав мій браузер! Я перевірив свою базу даних localStorage після того, як твій дурний код змусив мій браузер впасти в сегфолт, і ось що я знайшов:""вкладки:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, ... Я не знаю, що це таке, але я знаю, що це таке; Після очищення моїх дорогоцінних даних, він знову дав збій, я зробила бектрейс, і що ж я знаходжу? ЩО Я ЗНАХОДЖУ!? ВИ ВИКОРИСТОВУЄТЕ ЗАНАДТО БАГАТО ЗМІННИХ! var i = index; var j = 1; Гм, я тепер злий. Тролль Девідсон Зараз ти вже на межі свого розуму. Цей хлопець безперервно скаржиться на ваш додаток, і ви хочете сказати йому, щоб він заткнувся і пішов шукати кращий комп'ютер.
Рішення:
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. Ура! (Я б його ще відчитав, хоча...)
Вважаю важливим вказати на різницю між цими двома однойменними функціями, оскільки вони обидві дуже корисні.
Функція .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
індексує з 1, а не з 0. Я не знаю, чому так відбувається, але це так. Також, якщо 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
, просто виключається зі зрізу. Індекси у круглих дужках вказують на те, що буде вирізано. У будь-якому випадку, така поведінка не є інтуїтивно зрозумілою і може спричинити значну кількість помилок, тому вам може бути корисно написати функцію-обгортку, яка б більш точно імітувала поведінку .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;
}
Отже, як виявляється, насправді існує вбудований спосіб визначити, чи є масив дійсно масивом, і це Array.isArray()
, представлений в ECMAScript 5 (грудень 2009). Я знайшов це, коли шукав, чи є питання про те, як відрізнити масиви від об'єктів, щоб побачити, чи є краще рішення, ніж моє, або додати моє, якщо його немає. Отже, якщо ви використовуєте версію JavaScript, яка є більш ранньою, ніж ECMA 5, то ось вам поліфункція. Однак, я настійно рекомендую не використовувати мою функцію is_array()
, оскільки продовження підтримки старих версій JavaScript означає продовження підтримки старих браузерів, які їх реалізують, що означає заохочення використання небезпечного програмного забезпечення і піддає користувачів ризику зараження шкідливим програмним забезпеченням. Тому, будь ласка, використовуйте Array.isArray()
. Використовуйте let
і const
. Використовуйте нові можливості, які додаються до мови. Не використовуйте префікси виробників. Видаліть зі свого веб-сайту це лайно з поліфіллом IE. Видаліть це лайно XHTML <!CDATA[[...
теж - ми перейшли на HTML5 ще в 2014 році. Чим швидше всі відмовляться від підтримки цих старих/езотеричних браузерів, тим швидше виробники браузерів будуть дотримуватися веб-стандарту і приймуть нову технологію, і тим швидше ми зможемо перейти до більш безпечного Інтернету.