Helpex - Trao đổi & giúp đỡ Đăng nhập
107

Trong JavaScript, chúng ta có một số cách để lấy các thuộc tính của một đối tượng, tùy thuộc vào những gì chúng ta muốn lấy.

1) Object.keys(), trả về tất cả các thuộc tính riêng, có thể liệt kê của một đối tượng, một phương thức ECMA5.

2) một for...invòng lặp, trả về tất cả các thuộc tính có thể liệt kê của một đối tượng, bất kể chúng là thuộc tính riêng hay được kế thừa từ chuỗi nguyên mẫu.

3) Object.getOwnPropertyNames(obj)trả về tất cả các thuộc tính riêng của một đối tượng, có thể liệt kê hoặc không.

Chúng tôi cũng có các phương thức như hasOwnProperty(prop)cho phép chúng tôi kiểm tra xem một thuộc tính được kế thừa hay thực sự thuộc về đối tượng đó, và propertyIsEnumerable(prop)như tên cho thấy, cho phép chúng tôi kiểm tra xem một thuộc tính có thể liệt kê được không.

Với tất cả các tùy chọn này, không có cách nào để có được thuộc tính không thể liệt kê, không thuộc sở hữu của một đối tượng, đó là điều tôi muốn làm. Có cách nào để làm điều này? Nói cách khác, bằng cách nào đó, tôi có thể lấy danh sách các thuộc tính không liệt kê được kế thừa không?

Cảm ơn bạn.

107 hữu ích 2 bình luận 19k xem chia sẻ
120

getOwnPropertyNamescó thể mang lại cho bạn các thuộc tính không thể liệt kê, bạn có thể sử dụng nó và kết hợp nó với việc đi lên chuỗi nguyên mẫu.

function getAllProperties(obj){
    var allProps = []
      , curr = obj
    do{
        var props = Object.getOwnPropertyNames(curr)
        props.forEach(function(prop){
            if (allProps.indexOf(prop) === -1)
                allProps.push(prop)
        })
    }while(curr = Object.getPrototypeOf(curr))
    return allProps
}

Tôi đã thử nghiệm điều đó trên Safari 5.1 và nhận được

> getAllProperties([1,2,3])
["0", "1", "2", "length", "constructor", "push", "slice", "indexOf", "sort", "splice", "concat", "pop", "unshift", "shift", "join", "toString", "forEach", "reduceRight", "toLocaleString", "some", "map", "lastIndexOf", "reduce", "filter", "reverse", "every", "hasOwnProperty", "isPrototypeOf", "valueOf", "__defineGetter__", "__defineSetter__", "__lookupGetter__", "propertyIsEnumerable", "__lookupSetter__"]

Cập nhật: Đã cấu trúc lại mã một chút (thêm dấu cách và dấu ngoặc nhọn, và cải thiện tên hàm):

function getAllPropertyNames( obj ) {
    var props = [];

    do {
        Object.getOwnPropertyNames( obj ).forEach(function ( prop ) {
            if ( props.indexOf( prop ) === -1 ) {
                props.push( prop );
            }
        });
    } while ( obj = Object.getPrototypeOf( obj ) );

    return props;
}
120 hữu ích 5 bình luận chia sẻ
16

Một giải pháp sạch hơn bằng cách sử dụng đệ quy:

function getAllPropertyNames (obj) {
    const proto     = Object.getPrototypeOf(obj);
    const inherited = (proto) ? getAllPropertyNames(proto) : [];
    return [...new Set(Object.getOwnPropertyNames(obj).concat(inherited))];
}

Biên tập

Các chức năng chung khác:

function walkProtoChain (obj, callback) {
    const proto     = Object.getPrototypeOf(obj);
    const inherited = (proto) ? walkProtoChain(proto, callback) : [];
    return [...new Set(callback(obj).concat(inherited))];
}

function getOwnNonEnumPropertyNames (obj) {
    return Object.getOwnPropertyNames(obj)
        .filter(p => !obj.propertyIsEnumerable(p));
}

function getAllPropertyNames (obj) {
    return walkProtoChain(obj, Object.getOwnPropertyNames);
}

function getAllEnumPropertyNames (obj) {
    return walkProtoChain(obj, Object.keys);
}

function getAllNonEnumPropertyNames (obj) {
    return walkProtoChain(obj, getOwnNonEnumPropertyNames);
}

Có thể áp dụng cùng một mẫu này bằng cách sử dụng Object.getOwnPropertySymbols, v.v.

16 hữu ích 0 bình luận chia sẻ
4

Việc tận dụng các Bộ dẫn đến một giải pháp gọn gàng hơn, đó là IMO.

const own = Object.getOwnPropertyNames;
const proto = Object.getPrototypeOf;

function getAllPropertyNames(obj) {
    const props = new Set();
    do own(obj).forEach(p => props.add(p)); while (obj = proto(obj));
    return Array.from(props);
}
4 hữu ích 0 bình luận chia sẻ
3

Lặp lại chuyển tiếp thẳng trong ES6:

function getAllPropertyNames(obj) {
    let result = new Set();
    while (obj) {
        Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
        obj = Object.getPrototypeOf(obj);
    }
    return [...result];
}

Chạy ví dụ:

Hiển thị đoạn mã

3 hữu ích 0 bình luận chia sẻ
1

Để có được tất cả các thuộc tính hoặc phương thức được kế thừa trong một số trường hợp, bạn có thể sử dụng một cái gì đó như thế này

var BaseType = function () {
    this.baseAttribute = "base attribute";
    this.baseMethod = function() {
        return "base method";
    };
};

var SomeType = function() {
    BaseType();
    this.someAttribute = "some attribute";
    this.someMethod = function (){
        return "some method";
    };
};

SomeType.prototype = new BaseType();
SomeType.prototype.constructor = SomeType;

var instance = new SomeType();

Object.prototype.getInherited = function(){
    var props = []
    for (var name in this) {  
        if (!this.hasOwnProperty(name) && !(name == 'constructor' || name == 'getInherited')) {  
            props.push(name);
        }  
    }
    return props;
};

alert(instance.getInherited().join(","));
1 hữu ích 4 bình luận chia sẻ
0

Đây là giải pháp mà tôi đã đưa ra khi nghiên cứu đề tài này. Để có được tất cả các thuộc tính không phải của objđối tượng không liệt kê đượcgetProperties(obj, "nonown", "nonenum");

function getProperties(obj, type, enumerability) {
/**
 * Return array of object properties
 * @param {String} type - Property type. Can be "own", "nonown" or "both"
 * @param {String} enumerability - Property enumerability. Can be "enum", 
 * "nonenum" or "both"
 * @returns {String|Array} Array of properties
 */
    var props = Object.create(null);  // Dictionary

    var firstIteration = true;

    do {
        var allProps = Object.getOwnPropertyNames(obj);
        var enumProps = Object.keys(obj);
        var nonenumProps = allProps.filter(x => !(new Set(enumProps)).has(x));

        enumProps.forEach(function(prop) {
            if (!(prop in props)) {
                props[prop] = { own: firstIteration, enum_: true };
            }           
        });

        nonenumProps.forEach(function(prop) {
            if (!(prop in props)) {
                props[prop] = { own: firstIteration, enum_: false };
            }           
        });

        firstIteration = false;
    } while (obj = Object.getPrototypeOf(obj));

    for (prop in props) {
        if (type == "own" && props[prop]["own"] == false) {
            delete props[prop];
            continue;
        }
        if (type == "nonown" && props[prop]["own"] == true) {
            delete props[prop];
            continue;
        }

        if (enumerability == "enum" && props[prop]["enum_"] == false) {
            delete props[prop];
            continue;
        }
        if (enumerability == "nonenum" && props[prop]["enum_"] == true) {
            delete props[prop];
        }
    }

    return Object.keys(props);
}
0 hữu ích 0 bình luận chia sẻ
0
function getNonEnumerableNonOwnPropertyNames( obj ) {
    var oCurObjPrototype = Object.getPrototypeOf(obj);
    var arReturn = [];
    var arCurObjPropertyNames = [];
    var arCurNonEnumerable = [];
    while (oCurObjPrototype) {
        arCurObjPropertyNames = Object.getOwnPropertyNames(oCurObjPrototype);
        arCurNonEnumerable = arCurObjPropertyNames.filter(function(item, i, arr){
            return !oCurObjPrototype.propertyIsEnumerable(item);
        })
        Array.prototype.push.apply(arReturn,arCurNonEnumerable);
        oCurObjPrototype = Object.getPrototypeOf(oCurObjPrototype);
    }
    return arReturn;
}

Ví dụ về việc sử dụng:

function MakeA(){

}

var a = new MakeA();

var arNonEnumerable = getNonEnumerableNonOwnPropertyNames(a);
0 hữu ích 0 bình luận chia sẻ
0

nếu bạn đang cố gắng ghi lại các thuộc tính không liệt kê được của một đối tượng mẹ, ví dụ: theo mặc định, các phương thức được định nghĩa bên trong một lớp trong es6 được đặt trên nguyên mẫu nhưng được đặt là không thể liệt kê.

Object.getOwnPropertyNames(Object.getPrototypeOf(obj));
0 hữu ích 0 bình luận chia sẻ
0

Một triển khai theo sở thích cá nhân của tôi :)

function getAllProperties(In, Out = {}) {
    const keys = Object.getOwnPropertyNames(In);
    keys.forEach(key => Object.defineProperty(In, key, {
        enumerable: true
    }));
    Out = { ...In, ...Out };

    const Prototype = Object.getPrototypeOf(In);
    return Prototype === Object.prototype ? Out : getAllProperties(Proto, Out);
}
0 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ javascript oop object properties , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading