原型
- 实例化出来的对象继承构造函数的原型。
- 所有这个构造函数构造出来的对象,都继承于他的原型。 ```javascript function Person() { }
//给Person原型上定义一个name赋值为Lucy Person.prototype.name = ‘Lucy’;
//实例化Person var p = new Person(); console.log(p);
<a name="uaom5"></a>
## 继承
1. 实例化对象继承了原型链上的**所有**属性。
1. 但是实例化对象**并没有继承自己本身含有的属性**。
```javascript
Professor.prototype = {
name: 'Mr Zhang',
tSkill: 'JAVA'
}
function Professor() {
}
var professor = new Professor();
/**
* professor:{
* __proto__:{
* name:'Mr Zhang',
* tSkill:'JAVA'
* }
* }
*/
function Teacher() {
this.name = 'Mr Li';
this.mSkill = 'JS/JQ';
}
//将Professor的实例化对象赋值给Teacher当原型。
Teacher.prototype = professor;
//实例化Teacher
var teacher = new Teacher();
console.log(teacher)
//将Teacher的实例化对象赋值给Student当原型。
Student.prototype = teacher;
function Student() {
this.name = 'xiao wang';
this.pSkill = 'HTML/CSS';
}
// 实例化student
var student = new Student();
//xiao wang 如果自身有这个属性。就不会往原型链上去找属性。
console.log(student.name);
apply,call
- call,apply都是通过改变this指向的、来借用别人的属性和方法。并不是继承。 ```javascript Teacher.prototype.wife = ‘Mrs Liu’;
function Teacher(name,mSkill) { this.name = name; this.mSkill = mSkill; }
function Student(name,mSkill,age,major) { Teacher.apply(this, [name, mSkill]);//通过改变this指向来借用Teacher的属性和方法。 this.age = age; this.major = major; }
//实例化student var student = new Student(‘Axi’, ‘HTML’, 16, ‘Computer’); console.log(student);//apply,call的方式并没有让 student 继承到Teacher的prototype 这种方式构造的student无法获取到teacher原型上的属性。
![image.png](https://cdn.nlark.com/yuque/0/2021/png/12831495/1616640028641-c8cb94ba-ea10-4a7f-ad55-dcb023732190.png#align=left&display=inline&height=291&margin=%5Bobject%20Object%5D&name=image.png&originHeight=291&originWidth=574&size=18533&status=done&style=none&width=574)
- Student.prototype = Teacher.prototype 这种方式 让student 继承了teacher 的原型。并不会继承teacher的属性
```javascript
function Teacher() {
this.name = 'Mr Wang';
this.mSkill = 'JS';
}
//将Teacher的原型重新赋值。
Teacher.prototype = {
pSkill: 'JQ'
}
//实例化一个teacher
var teacher = new Teacher();
//将Student的原型赋值为Teacher.prototype。
//这种方式 让student 继承了teacher 的原型上的方法和属性。但是并不会继承teacher的属性(name,mSkill)
Student.prototype = Teacher.prototype;
//学生构造函数
function Student() {
//构造函数隐式申明了一个this;并且隐式返回了一个this;
this.name = 'Mr Li';
}
var student = new Student();
console.log(student.name);//undefined
console.log(student.mSkill);//undefined
console.log(student.pSkill);//JQ;
//添加学生构造函数上的属性
Student.prototype.age = 18;
//老师的构造函数原型上也多了一个age属性。说明他俩prototype指向一个对象。
console.log(Teacher.prototype.age)
圣杯模式
方案:构建一个新的构造函数,这个构造函数去继承Origin的原型。而Target则去接收新的构造函数实例化的对象。这个时候Target的原型和Origin的原型就不是同一个对象了。而Target可以继承Origin的属性和方法。
// 声明一个构造函数Teacher。
function Teacher() { }//父类
// 往Teacher的原型上添加一个age属性,并且赋值为19
Teacher.prototype.age = 19;
// 申明一个构造函数Student
function Student() { }//子类
// 将缓冲类的Buffer的原型赋值为Teacher的原型。
Buffer.prototype = Teacher.prototype;
function Buffer() { }//缓冲类
//创建一个buffer实例。
var buffer = new Buffer();//缓冲类实例
//将这个实例赋值给Student的原型。
Student.prototype = buffer;
// 实例化Teacher
var teacher = new Teacher();
// 实例化student
var student = new Student();
// 往Student原型上添加sex 相当于给buffer添加sex属性。
Student.prototype.sex = 'male';
// 往Teacher原型上添加major 相当于给Buffer.prototype添加sex属性。
Teacher.prototype.major = 'JAVA';
console.log(student);
console.log(teacher);
//这个操作就不会造成修改一个构造函数原型上的属性。另外一个构造函数不会因此改变。
圣杯模式的企业级写法
Teacher.prototype.name = 'Mr Wang';
function Teacher() {}
function Student() { }
inherit(Student, Teacher);
//企业级写法
function inherit(Target,Origin) {
function Buffer() { }//缓冲区
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();//Buffer实例化赋值给目标源的prototype
Target.prototype.constructor = Target;//还原构造器。函数原型上的构造器一般都指向本身。
Target.prototype.super_class = Origin;//记录超类。在目标函数上记录继承源;
}
构造函数形成的闭包
function Compute() {
var num = 10;
this.add = function () {
num++;
console.log(num);
}
this.minus = function () {
num--;
console.log(num);
}
// 构造函数被实例化的时候隐式返回了一个this。这个this中包含了num,add,minus属性或方法。
// 这个构造函数被执行的时, this.add,this.minus被定义。此时this.add,this.minus创建了自己的作用域和作用域链,作用域链的第0位存的是Compute的AO,第二位是GO。
// 构造函数被实例化时 隐式返回了this。this中的add 和minus 都被返回出去了。所以形成了闭包。
}
var cp = new Compute();//实例化这个函数的时候相当于这个函数执行了一遍
cp.add();//11//
cp.add();//12
cp.add();//13