您的位置:首页 > 编程语言

犀牛书的实例代码:给对象添加freeze, hide, 查询descriptors

2016-05-30 18:18 507 查看
/*
* Define a properties() method in Object.prototype that returns an
* object representing the named properties of the object on which it
* is invoked (or representing all own properties of the object, if
* invoked with no arguments).  The returned object defines four useful
* methods: toString(), descriptors(), hide(), and show().
*/
(function namespace() {  // Wrap everything in a private function scope

// This is the function that becomes a method of all object
function properties() {
var names;  // An array of property names
if (arguments.length == 0)  // All own properties of this
names = Object.getOwnPropertyNames(this);
else if (arguments.length == 1 && Array.isArray(arguments[0]))
names = arguments[0];   // Or an array of names
else                        // Or the names in the argument list
names = Array.prototype.splice.call(arguments, 0);

// Return a new Properties object representing the named properties
return new Properties(this, names);
}

// Make it a new nonenumerable property of Object.prototype.
// This is the only value exported from this private function scope.
Object.defineProperty(Object.prototype, "properties", {
value: properties,
enumerable: false, writable: true, configurable: true
});

// This constructor function is invoked by the properties() function above.
// The Properties class represents a set of properties of an object.
function Properties(o, names) {
this.o = o;            // The object that the properties belong to
this.names = names;    // The names of the properties
}

// Make the properties represented by this object nonenumerable
Properties.prototype.hide = function() {
var o = this.o, hidden = { enumerable: false };
this.names.forEach(function(n) {
if (o.hasOwnProperty(n))
Object.defineProperty(o, n, hidden);
});
return this;
};

// Make these properties read-only and nonconfigurable
Properties.prototype.freeze = function() {
var o = this.o, frozen = { writable: false, configurable: false };
this.names.forEach(function(n) {
if (o.hasOwnProperty(n))
Object.defineProperty(o, n, frozen);
});
return this;
};

// Return an object that maps names to descriptors for these properties.
// Use this to copy properties along with their attributes:
//   Object.defineProperties(dest, src.properties().descriptors());
Properties.prototype.descriptors = function() {
var o = this.o, desc = {};
this.names.forEach(function(n) {
if (!o.hasOwnProperty(n)) return;
desc
= Object.getOwnPropertyDescriptor(o,n);
});
return desc;
};

// Return a nicely formatted list of properties, listing the
// name, value and attributes. Uses the term "permanent" to mean
// nonconfigurable, "readonly" to mean nonwritable, and "hidden"
// to mean nonenumerable. Regular enumerable, writable, configurable
// properties have no attributes listed.
Properties.prototype.toString = function() {
var o = this.o; // Used in the nested function below
var lines = this.names.map(nameToString);
return "{\n  " + lines.join(",\n  ") + "\n}";

function nameToString(n) {
var s = "", desc = Object.getOwnPropertyDescriptor(o, n);
if (!desc) return "nonexistent " + n + ": undefined";
if (!desc.configurable) s += "permanent ";
if ((desc.get && !desc.set) || !desc.writable) s += "readonly ";
if (!desc.enumerable) s += "hidden ";
if (desc.get || desc.set) s += "accessor " + n
else s += n + ": " + ((typeof desc.value==="function")?"function"
:desc.value);
return s;
}
};

// Finally, make the instance methods of the prototype object above
// nonenumerable, using the methods we've defined here.
Properties.prototype.properties().hide();
}()); // Invoke the enclosing function as soon as we're done defining it.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: