-->

Javascript “pop” from object

2019-04-19 03:16发布

问题:

I wrote the following code to "pop" a property from an object as if it were an array. This looks like the kind of code that would get me slapped by more serious programmers, so I was wondering what is the proper way to do this:

// 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
}

I should have mentioned above, that unlike a true "pop", I don't need the objects to come out in any particular order. I just need to get one out and remove it from its parent object.

回答1:

for( key in profiles ){

You should really declare key as a var.

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

is unnecessary. Delete doesn't touch the value of the property (or in the case of a property that has a setter but no getter, even require that it have a value).

If the object has any enumerable properties on its prototype, then this will do something odd. Consider

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


回答2:

Properties in an object are not stored in a stack so the basic concept won't work reliably (aside from the other issues mentioned in the comments above).

If you really need such a construct try something like this.

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

Demo: http://jsfiddle.net/a8Rf6/5/



回答3:

There's no "correct" order across browsers in what they give for a for in loop. Some do them in the order they are put in, other do it numerical indexes first. So there really is no way to do this without creating your own custom object



回答4:

Nowadays you can simply using the spread operator with its Rest way:
const { key, ...profilesWithoutKey } = profiles;

Credit to this blog post



回答5:

You are able to create the pop method like this: .

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

for some reason using just Object.prototype.pop = function ... breaks JQuery



回答6:

A better approach instead of directly modifying the input array. Eg.

let arr = [{label: "a"}, {label: "b"}, {label: "p"}, {label: "c"}] 
let newArr = arr.filter(p => { return p.label !== "p";});


回答7:

Having studied all the comments and solutions above, I can offer a completely ready solution based on them:

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 {  }

Perhaps someone will come in handy ; )


PS. If you use the code I propose along with the jQuery library, you may encounter errors in the console. In this case, the option given below is appropriate:

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() }