原型
- js上所有的对象都是通过new函数创建的,包括字面量定义的对象也是new的语法糖
- 所有的函数都是通过new Function创建的,包括Array object等
- 所有的函数都是对象
prototype
每个函数都存在的属性,指向它的原型
constructor
原型对象上存在一个指针constructor指向构造函数
proto
实例上存在的属性,指向其构造函数的原型
一图说明关系
举个例子
function Person() {}
function Animal() {}
Person.prototype = new Animal();
Person.prototype.name = "alan";
var person = new Person();
person.name = "tom";
console.log(person.name); // tom
delete person.name;
console.log(person.name); // alan
console.log(person.__proto__); // Animal
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
console.log(Person.prototype);
原型链
当访问一个对象的属性或方法时,如果找不到,就会查找与这个对象关联的原型中的属性,如果还找不到,就再去找原型的原型,一直找到最顶层(Object)为止,而由原型组成的这个链条就叫做原型链。
继承
原型继承
function father() {
this.a = 1;
}
father.prototype.say = () => {
console.log("hhh");
};
function child() {}
child.super = new father();
console.log(child.say);
缺点:
如果父方法里的某个属性是引用值,则会造成污染。
构造继承
function father() {
this.a = 1;
}
father.prototype.say = () => {
console.log("hhh");
};
function child() {
father.call(this);
this.b = 2;
}
const test = new child();
console.log(test.say); //undefined
缺点:
子函数无法使用父函数原型上的方法属性 父构造函数中方法需要在每个实例上创建一遍
组合继承
function father() {
this.a = 1;
}
father.prototype.say = () => {
console.log("hhh");
};
function child() {
father.call(this);
this.b = 2;
}
child.prototype = new father();
const test = new child();
test.say(); //hhh
缺点: father函数始终会被调用两次
组合寄生继承
function father() {
this.a = 1;
}
father.prototype.say = () => {
console.log("hhh");
};
function child() {
father.call(this);
this.b = 2;
}
child.prototype = Object.create(father.prototype);
child.prototype.constructor = child;
const test = new child();
test.say(); //hhh