Javascript "поп" от объекта - PullRequest
17 голосов
/ 09 июля 2011

Я написал следующий код, чтобы «вытолкнуть» свойство из объекта, как если бы оно было массивом. Это похоже на код, который мог бы дать мне пощечину более серьезным программистам, поэтому мне было интересно, как правильно это сделать:

// wrong way to pop:
for( key in profiles ){
    var profile = profiles[key];  // get first property
    profiles[key] = 0;            // Save over property just in case "delete" actually deletes the property contents instead of just removing it from the object
    delete profiles[key];         // remove the property from the object
    break;                        // "break" because this is a loop
}

Я должен был упомянуть выше, что в отличие от настоящего «попса», мне не нужно, чтобы объекты появлялись в каком-то определенном порядке. Мне просто нужно достать один и удалить его из родительского объекта.

Ответы [ 7 ]

13 голосов
/ 09 июля 2011
for( key in profiles ){

Вы действительно должны объявить key как var.

profiles[key] = 0;            // Save over property just in case "delete" actually deletes the property contents instead of just removing it from the object

не требуется. Удалить не касается значения свойства (или в случае свойства, которое имеет установщик, но не получает, даже требует, чтобы оно имело значение).

Если у объекта есть какие-либо перечисляемые свойства в его прототипе, то это сделает что-то странное. Рассмотрим

Object.prototype.foo = 42;

function pop(obj) {
  for (var key in obj) {
    // Uncomment below to fix prototype problem.
    // if (!Object.hasOwnProperty.call(obj, key)) continue;
    var result = obj[key];
    // If the property can't be deleted fail with an error.
    if (!delete obj[key]) { throw new Error(); }
    return result;
  } 
}

var o = {};
alert(pop(o));  // alerts 42
alert(pop(o));  // still alerts 42
4 голосов
/ 09 июля 2011

Свойства объекта не хранятся в стеке, поэтому базовая концепция не будет работать надежно (за исключением других проблем, упомянутых в комментариях выше).

Если вам действительно нужна такая конструкция, попробуйте что-то вроде этого.

var ObjectStack = function(obj) {
    this.object = obj;
    this.stack=[];
};
ObjectStack.prototype.push = function(key,value) {
    this.object[key]=value;
    this.stack.push(key);
};
ObjectStack.prototype.pop = function() {
    var key = this.stack.pop();
    var prop = this.object[key];
    delete this.object[key];
    return prop;
};

var my_obj = {};
var my_stack = new ObjectStack(my_obj);
my_stack.push("prop1",val1);
my_stack.push("prop2",val2);

var last_prop = my_stack.pop(); //val2

Демо: http://jsfiddle.net/a8Rf6/5/

2 голосов
/ 24 декабря 2018

В настоящее время вы можете просто использовать оператор распространения с его способом отдыха:
const {key, ... profileWithoutKey} = анкеты;

Кредит этой записи блога

2 голосов
/ 09 июля 2011

В браузерах нет «правильного» порядка в том, что они дают для цикла for in.Некоторые делают их в том порядке, в каком они вставлены, другие сначала делают числовые индексы.Так что на самом деле нет способа сделать это без создания собственного пользовательского объекта

1 голос
/ 22 января 2019

Изучив все комментарии и решения выше, я могу предложить полностью готовое решение на их основе:

Object.prototype.pop = function() {
    for (var key in this) {
        if (!Object.hasOwnProperty.call(this, key)) continue;
        var result = this[key];
        if (!delete this[key]) throw new Error();
        return result;
    }
};

var obj = {
    a: '1',
    b: '2',
    c: '3'
};

console.log(obj.pop()); // 1
console.log(obj.pop()); // 2
console.log(obj.pop()); // 3
console.log(obj); // Object {  }

Возможно, кому-то пригодится; )


PS. Если вы используете предложенный мной код вместе с библиотекой jQuery, вы можете столкнуться с ошибками в консоли. В этом случае уместен вариант, указанный ниже:

function _pop() {
    for (var key in this) {
        if (!Object.hasOwnProperty.call(this, key)) continue;
        if (key === 'pop') continue;
        var result = this[key];
        if (!delete this[key]) throw new Error();
        return result;
    }
}

var obj = {
    a: '1',
    b: '2',
    c: '3'
};

obj.pop = _pop;

console.log(obj.pop()); // 1
console.log(obj.pop()); // 2
console.log(obj.pop()); // 3
console.log(obj); // Object { pop: _pop() }
1 голос
/ 02 апреля 2018

Лучший подход вместо прямой модификации входного массива. Например.

let arr = [{label: "a"}, {label: "b"}, {label: "p"}, {label: "c"}] 
let newArr = arr.filter(p => { return p.label !== "p";});
1 голос
/ 03 февраля 2017

Вы можете создать метод pop следующим образом:.

Object.defineProperty(Object.prototype, 'pop',{
    writable: false
    , configurable: false
    , enumerable: false
    , value: function (name) {
        var value = this[name];
        delete this[name];
        return value;
    }
});

по какой-то причине, используя просто Object.prototype.pop = function ... breaks JQuery

...