原型链的原理:
JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototypechain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
准确地说,这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype属性上,而非对象实例本身。
例子
function doSomething(){}
doSomething.prototype.foo = "bar"; // add a property onto the prototype
var doSomeInstancing = new doSomething();
doSomeInstancing.prop = "some value"; // add a property onto the object
console.log( doSomeInstancing );
结果
{
prop: "some value",
__proto__: {
foo: "bar",
constructor: ƒ doSomething(),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}
}
- doSomeInstancing的_proto_指向doSomething的prototype;实例的_proto_==构造函数的prototype;
- 每个实例对象都从原型中继承了一个constructor属性,该属性指向了用于构造此实例对象的构造函数。也就是doSomeInstancing的构造函数是doSomething,doSomething的构造函数是Object;
new Object()和Object.create()区别
function Animal(name){
this.name = name;
}
var animal = new Animal("test");
var createAnimal1 = Object.create(Animal.prototype);
var createAnimal3 = Object.create(null);
console.log(animal)
{
name:'test',
__proto__: {
constructor: ƒ Animal(),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}
}
console.log(createAnimal1)
{
__proto__: {
constructor: ƒ Animal(name),
__proto__: {
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}
}
console.log(createAnimal3)
{}
特别需要指出的是Object.create(null)和new Object()的区别:两者都是创建空对象,但是new创建出的空对象会绑定Object的prototype原型对象,但是Object.create(null)的空对象是没有任何属性的。
- new了之后,animal的prototype指向了Animal的proto拥有了其全部属性及方法;
- Object.create()之后,createAnimal1的proto指向了Animal.prototype;
- Object.create()方法创建一个新对象,新创建的对象的__proto__指向现有对象。
- Object.create()的参数必须是对象,如果传入的是一个构造函数的话,该实例是无法继承的。