参考:https://www.cnblogs.com/lyy-2016/p/8916350.html
例子1:
const log = console.log;
function Parent() {
this.pname = "parent name";
}
function Old() {
this.oname = "old name";
}
Old.prototype = new Parent();
Old.prototype.runOld = function() {
log("Old runOld");
}
Old.prototype.constructor = Old;
function Animal() {
this.aname = "animal name";
}
Animal.prototype = new Old();
Animal.prototype.runAnim = function() {
log("Animal runAnim");
}
Animal.prototype.constructor = Animal;
let o = new Old();
let animal = new Animal();
let a = Object.create(Animal.prototype);
log("o = ", o);
log("o.getPrototypeOf(o) = ", Object.getPrototypeOf(o));
for (let k in o) {
log("o k = ", k, ", ", o[k]);
}
log("animal = ", animal);
log("a = ", a);
log("a.prototype = ", a.prototype);
log("Object.getPrototypeOf(a) = ", Object.getPrototypeOf(a));
log("Object.getPrototypeOf(animal) = ", Object.getPrototypeOf(animal));
animal.aname = "cccc";
animal.pname = "xxxx";
//没有打印出this.aname
for (let k in a) {
log("a k = ", k, ", ", a[k]);
}
结果:
$ node for.js
o = Old { oname: 'old name' }
o.getPrototypeOf(o) = Old {
pname: 'parent name',
runOld: [Function],
constructor: [Function: Old]
}
o k = oname , old name
o k = pname , parent name
o k = runOld , [Function]
o k = constructor , [Function: Old]
animal = Animal { aname: 'animal name' }
a = Animal {}
a.prototype = undefined
Object.getPrototypeOf(a) = Animal {
oname: 'old name',
runAnim: [Function],
constructor: [Function: Animal]
}
Object.getPrototypeOf(animal) = Animal {
oname: 'old name',
runAnim: [Function],
constructor: [Function: Animal]
}
a k = oname , old name
a k = runAnim , [Function]
a k = constructor , [Function: Animal]
a k = pname , parent name
a k = runOld , [Function]
例子2:
const log = console.log;
function cat(name) {
this.name = name ? name : "defaultname";
}
cat.skey = "test-skey";
cat.prototype.pinfo = function() {
return `name = ${this.name}`;
}
let b = new cat("bbb");
let c = new cat("ccc");
let e = Object.create(cat.prototype);
log("b = ", b);
log("c = ", c);
log("e = ", e);
log("Object.keys(c) = ", Object.keys(c))
log("Object.keys(e) = ", Object.keys(e))
log("c.pinfo() = ", c.pinfo());
log("e.pinfo() = ", e.pinfo());
e.name = "new-name";
log("c.pinfo() = ", c.pinfo());
log("e.pinfo() = ", e.pinfo());
log("c.skey = ", c.skey);
log("e.skey = ", e.skey);
结果:
$ node for.js
b = cat { name: 'bbb' }
c = cat { name: 'ccc' }
e = cat {}
Object.keys(c) = [ 'name' ]
Object.keys(e) = []
e k= pinfo , v = [Function]
e k= constructor , v = [Function: cat] { skey: 'test-skey' }
c.pinfo() = name = ccc
e.pinfo() = name = undefined
c.pinfo() = name = ccc
e.pinfo() = name = new-name
c.skey = undefined
e.skey = undefined
Object.create()方法是ECMAScript 5中新增的方法,这个方法用于创建一个新对象。被创建的对象继承另一个对象的原型,在创建新对象时可以指定一些属性。
语法: Object.create(proto[,propertiesObject])
proto: 对象,要继承的原型
propertiesObject: 对象,可选参数,为新创建的对象指定属性对象。该属性对象可能包含以下值:
属性 | 说明 |
---|---|
configurable | 表示新创建的对象是否是可配置的,即对象的属性是否可以被删除或修改,默认false |
enumerable | 对象属性是否可枚举的,即是否可以枚举,默认false |
writable | 对象是否可写,是否或以为对象添加新属性,默认false |
get | 对象getter函数,默认undefined |
set | 对象setter函数,默认undefined |
注意,使用Object.create()方法创建对象时,如果不是继承一个原有的对象,而是创建一个全新的对象,就要把proto设置为null。
来看一个简单的应用
const log = console.log;
function Old() {
this.origin = "原型";
log("Old::constructor");
}
// 基类
function Site() {
Old.call(this);
this.name = 'Site';
this.domain = 'domain';
log("Site::constructor");
}
Site.prototype = Object.create(Old.prototype);
Site.prototype.create = function(name, domain) {
this.name = name;
this.domain = domain;
};
// 子类
function Itbilu() {
Site.call(this); //调用基类的构造函数
}
// 继承父类
Itbilu.prototype = Object.create(Site.prototype);
Itbilu.prototype.constructor = Itbilu;
// 创建类实例
var itbilu = new Itbilu();
log("itbilu = ", itbilu);
log("itbilu instanceof Site = ", itbilu instanceof Site); // true
log("itbilu instanceof Itbilu = ", itbilu instanceof Itbilu); // true
itbilu.create('IT笔录', 'itbilu.com');
log("itbilu.name = ", itbilu.name); // 'IT笔录'
log("itbilu.domain = ", itbilu.domain); // 'itbilu.com'
结果:
$ node for.js
Old::constructor
Site::constructor
itbilu = Itbilu { origin: '原型', name: 'Site', domain: 'domain' }
itbilu instanceof Site = true
itbilu instanceof Itbilu = true
itbilu.name = IT笔录
itbilu.domain = itbilu.com
参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
Object.create()
方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 (请打开浏览器控制台以查看运行结果。)
const person = {
isHuman: false,
printIntroduction: function() {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
const me = Object.create(person);
me.name = 'Matthew'; // "name" is a property set on "me", but not on "person"
me.isHuman = true; // inherited properties can be overwritten
me.printIntroduction();
// expected output: "My name is Matthew. Am I human? true"
结果:
> "My name is Matthew. Am I human? true"
语法
Object.create(proto,[propertiesObject])
参数
proto
新创建对象的原型对象。
propertiesObject
可选。需要传入一个对象,该对象的属性类型参照Object.defineProperties()
的第二个参数。如果该参数被指定且不为 undefined
,该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。
返回值
一个新对象,带着指定的原型对象和属性。
例外
如果propertiesObject
参数是 null
或非原始包装对象,则抛出一个 TypeError
异常。
例子
用 Object.create
实现类式继承
下面的例子演示了如何使用Object.create()
来实现类式继承。这是一个所有版本JavaScript都支持的单继承。
// 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);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
如果你希望能继承到多个对象,则可以使用混入的方式。
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}
// 继承一个类
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function() {
// do a thing
};
Object.assign 会把 OtherSuperClass
原型上的函数拷贝到 MyClass
原型上,使 MyClass 的所有实例都可用 OtherSuperClass 的方法。Object.assign 是在 ES2015 引入的,且可用 polyfilled。要支持旧浏览器的话,可用使用 jQuery.extend() 或者 _.assign()。
使用 Object.create
的 propertyObject
参数
var o;
// 创建一个原型为null的空对象
o = Object.create(null);
o = {};
// 以字面量方式创建的空对象就相当于:
o = Object.create(Object.prototype);
o = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: {
writable:true,
configurable:true,
value: "hello"
},
// bar会成为所创建对象的访问器属性
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) {
console.log("Setting `o.bar` to", value);
}
}
});
function Constructor(){}
o = new Constructor();
// 上面的一句就相当于:
o = Object.create(Constructor.prototype);
// 当然,如果在Constructor函数中有一些初始化代码,Object.create不能执行那些代码
// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
o = Object.create({}, { p: { value: 42 } })
// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
o.p = 24
o.p
//42
o.q = 12
for (var prop in o) {
console.log(prop)
}
//"q"
delete o.p
//false
//创建一个可写的,可枚举的,可配置的属性p
o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});
Polyfill
这个 polyfill 涵盖了主要的应用场景,它创建一个已经选择了原型的新对象,但没有把第二个参数考虑在内。
请注意,尽管在 ES5 中 Object.create
支持设置为[[Prototype]]
为null
,但因为那些ECMAScript5以前版本限制,此 polyfill 无法支持该特性。
if (typeof Object.create !== "function") {
Object.create = function (proto, propertiesObject) {
if (typeof proto !== 'object' && typeof proto !== 'function') {
throw new TypeError('Object prototype may only be an Object: ' + proto);
} else if (proto === null) {
throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
}
if (typeof propertiesObject !== 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
function F() {}
F.prototype = proto;
return new F();
};
}