前端开发者进阶之ECMAScript新特性【一】--Object.create
Object.create(prototype, descriptors) :创建一个具有指定原型且可选择性地包含指定属性的对象
参数:
prototype 必需。 要用作原型的对象。 可以为 null。
descriptors 可选。 包含一个或多个属性描述符的 JavaScript 对象。
“数据属性”是可获取且可设置值的属性。 数据属性描述符包含 value 特性,以及 writable、enumerable 和 configurable 特性。
如果未指定最后三个特性,则它们默认为 false。 只要检索或设置该值,“访问器属性”就会调用用户提供的函数。 访问器属性描述符包含 set 特性和/或 get 特性。
var pt = { say : function(){ console.log(‘saying!‘); } } var o = Object.create(pt); console.log(‘say‘ in o); // true console.log(o.hasOwnProperty(‘say‘)); // false
如果prototype传入的是null,创建一个没有原型链的空对象。
var o1 = Object.create(null); console.dir(o1); // object[ No Properties ]
当然,可以创建没有原型链的但带descriptors的对象;
var o2 = Object.create(null, { size: { value: "large", enumerable: true }, shape: { value: "round", enumerable: true } }); console.log(o2.size); // large console.log(o2.shape); // round console.log(Object.getPrototypeOf(o2)); // null
也可以创建带属性带原型链的对象:
var pt = { say : function(){ console.log(‘saying!‘); } } var o3 = Object.create(pt, { size: { value: "large", enumerable: true }, shape: { value: "round", enumerable: true } }); console.log(o3.size); // large console.log(o3.shape); // round console.log(Object.getPrototypeOf(o3)); // {say:...}
最重要的是实现继承,看下面实例:
//Shape - superclass function Shape() { this.x = 0; this.y = 0; } Shape.prototype.move = function(x, y) { this.x += x; this.y += y; console.info("Shape moved."); }; // Rectangle - subclass function Rectangle() { Shape.call(this); //call super constructor. } Rectangle.prototype = Object.create(Shape.prototype); var rect = new Rectangle(); console.log(rect instanceof Rectangle); //true. console.log(rect instanceof Shape); //true. rect.move(); //"Shape moved."
不支持浏览器的兼容实现:
1、简单实现,也是最常见的实现方式,没有实现第二个参数的功能:
if (!Object.create) { Object.create = function (o) { if (arguments.length > 1) { throw new Error(‘Object.create implementation only accepts the first parameter.‘); } function F() {} F.prototype = o; return new F(); }; }
2、复杂实现,实现第二个参数的大部分功能:
if (!Object.create) { // Contributed by Brandon Benvie, October, 2012 var createEmpty; var supportsProto = Object.prototype.__proto__ === null; if (supportsProto || typeof document == ‘undefined‘) { createEmpty = function () { return { "__proto__": null }; }; } else { createEmpty = function () { var iframe = document.createElement(‘iframe‘); var parent = document.body || document.documentElement; iframe.style.display = ‘none‘; parent.appendChild(iframe); iframe.src = ‘javascript:‘; var empty = iframe.contentWindow.Object.prototype; parent.removeChild(iframe); iframe = null; delete empty.constructor; delete empty.hasOwnProperty; delete empty.propertyIsEnumerable; delete empty.isPrototypeOf; delete empty.toLocaleString; delete empty.toString; delete empty.valueOf; empty.__proto__ = null; function Empty() {} Empty.prototype = empty; // short-circuit future calls createEmpty = function () { return new Empty(); }; return new Empty(); }; } Object.create = function create(prototype, properties) { var object; function Type() {} // An empty constructor. if (prototype === null) { object = createEmpty(); } else { if (typeof prototype !== "object" && typeof prototype !== "function") { throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome } Type.prototype = prototype; object = new Type(); object.__proto__ = prototype; } if (properties !== void 0) { Object.defineProperties(object, properties); } return object; }; }
前端开发者进阶之ECMAScript新特性【一】--Object.create
Object.create(prototype, descriptors) :创建一个具有指定原型且可选择性地包含指定属性的对象
参数:
prototype 必需。 要用作原型的对象。 可以为 null。
descriptors 可选。 包含一个或多个属性描述符的 JavaScript 对象。
“数据属性”是可获取且可设置值的属性。 数据属性描述符包含 value 特性,以及 writable、enumerable 和 configurable 特性。
如果未指定最后三个特性,则它们默认为 false。 只要检索或设置该值,“访问器属性”就会调用用户提供的函数。 访问器属性描述符包含 set 特性和/或 get 特性。
var pt = { say : function(){ console.log(‘saying!‘); } } var o = Object.create(pt); console.log(‘say‘ in o); // true console.log(o.hasOwnProperty(‘say‘)); // false
如果prototype传入的是null,创建一个没有原型链的空对象。
var o1 = Object.create(null); console.dir(o1); // object[ No Properties ]
当然,可以创建没有原型链的但带descriptors的对象;
var o2 = Object.create(null, { size: { value: "large", enumerable: true }, shape: { value: "round", enumerable: true } }); console.log(o2.size); // large console.log(o2.shape); // round console.log(Object.getPrototypeOf(o2)); // null
也可以创建带属性带原型链的对象:
var pt = { say : function(){ console.log(‘saying!‘); } } var o3 = Object.create(pt, { size: { value: "large", enumerable: true }, shape: { value: "round", enumerable: true } }); console.log(o3.size); // large console.log(o3.shape); // round console.log(Object.getPrototypeOf(o3)); // {say:...}
最重要的是实现继承,看下面实例:
//Shape - superclass function Shape() { this.x = 0; this.y = 0; } Shape.prototype.move = function(x, y) { this.x += x; this.y += y; console.info("Shape moved."); }; // Rectangle - subclass function Rectangle() { Shape.call(this); //call super constructor. } Rectangle.prototype = Object.create(Shape.prototype); var rect = new Rectangle(); console.log(rect instanceof Rectangle); //true. console.log(rect instanceof Shape); //true. rect.move(); //"Shape moved."
不支持浏览器的兼容实现:
1、简单实现,也是最常见的实现方式,没有实现第二个参数的功能:
if (!Object.create) { Object.create = function (o) { if (arguments.length > 1) { throw new Error(‘Object.create implementation only accepts the first parameter.‘); } function F() {} F.prototype = o; return new F(); }; }
2、复杂实现,实现第二个参数的大部分功能:
if (!Object.create) { // Contributed by Brandon Benvie, October, 2012 var createEmpty; var supportsProto = Object.prototype.__proto__ === null; if (supportsProto || typeof document == ‘undefined‘) { createEmpty = function () { return { "__proto__": null }; }; } else { createEmpty = function () { var iframe = document.createElement(‘iframe‘); var parent = document.body || document.documentElement; iframe.style.display = ‘none‘; parent.appendChild(iframe); iframe.src = ‘javascript:‘; var empty = iframe.contentWindow.Object.prototype; parent.removeChild(iframe); iframe = null; delete empty.constructor; delete empty.hasOwnProperty; delete empty.propertyIsEnumerable; delete empty.isPrototypeOf; delete empty.toLocaleString; delete empty.toString; delete empty.valueOf; empty.__proto__ = null; function Empty() {} Empty.prototype = empty; // short-circuit future calls createEmpty = function () { return new Empty(); }; return new Empty(); }; } Object.create = function create(prototype, properties) { var object; function Type() {} // An empty constructor. if (prototype === null) { object = createEmpty(); } else { if (typeof prototype !== "object" && typeof prototype !== "function") { throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome } Type.prototype = prototype; object = new Type(); object.__proto__ = prototype; } if (properties !== void 0) { Object.defineProperties(object, properties); } return object; }; }