原型对象: 每一个函数都有一个 prototype属性,它就是原型对象。通过函数实例化出来的对象有个__proto__属性,指向原型对象。
作用: 为每一个实例对象存储共享的方法和属性。所有的实例都是共享同一个原型对象。原型对象只有一份。
var a = new A();
a.__proto = A.prototype;
在构造函数中,为了属性的私有性和方法的复用共享,提倡:属性封装在构造函数中;方法定义在原型对象上。
function A(){
this.name = name;//私有,不共享
}
A.prototype.say = function(){//定义在原型对象上的方法 共享 复用
console.log('hi');
}
关系:
继承的方式:
1.原型链继承
缺点:子类实例共享了父类构造函数的引用属性,eg:数组
function Person(){
this.name = "ht";
this.arr = [1,2,3];
}
Person.prototype.eat = 'chifan';
function Stu(){
this.age = 20;
}
Stu.prototype = new Person();//此时Stu.prototype.constructor == Person
Stu.prototype.constructor = Stu;//修正
var f1 = new Stu();
f1.arr.push(4);
console.log(f1.arr);//[1, 2, 3, 4]
var f2 = new Stu();
console.log(f2.arr);//[1, 2, 3, 4]
//给f1的arr加元素 f2也会变 所以只是继承了内存地址
console.log(f1.eat);//chifan
2.构造函数继承
缺点:不能继承原型链上的属性和方法
function Person(){
this.name = "ht";
this.say = function(){
console.log('hi');
}
}
Person.prototype.eat = 'chifan';
Person.prototype.run = function(){
console.log('run');
}
function Stu(){
Person.call(this);//让Person中的this指向Stu
this.age = 20;
}
var f1 = new Stu();
console.log(f1) //Stu {name: "ht", age: 20, say: ƒ}
console.log(f1.eat) //undefined
console.log(f1.run) //undefined
3.组合继承 :构造函数继承+原型链继承
function Person(){
this.name = "ht";
this.arr = [1,2,3];
this.say = function(){
console.log('hi');
}
}
Person.prototype.eat = 'chifan';
Person.prototype.run = function(){
console.log('run');
}
function Stu(){
Person.call(this);
this.age = 20;
}
Stu.prototype = new Person();
Stu.prototype.constructor = Stu;
var f1 = new Stu();
f1.arr.push(4);
console.log(f1.arr);//[1, 2, 3, 4]
var f2 = new Stu();
console.log(f2.arr);//[1, 2, 3]
console.log(f1.eat);//chifan