## JavaScript之原型和原型链
在JavaScript的学习过程中,原型链肯定是一个很重要的知识点,下面我们就来深入的去看一下原型链
原型
首先看一个很简单的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | function Person(name, age) {             this.name = name;             this.age = age;             this.sayName = function () {                 console.log("i am "+this.name);             }         }         Person.prototype.sayAge = function () {             console.log("i am "+this.age);         }         var person1 = new Person("ljm",18)         person1.sayAge();         person1.sayName();         var person2 = new Person("lll",20);         person2.sayAge();         person2.sayName();
  | 
 
控制台输出的是,和大多数人预想的一样,输出了两个person的年龄和姓名

在这个过程中我们创建了两个实例对象(person1,person2),有一个构造函数(Person)和原型(Person.prototype),那么他们之间的关系应该是这样的
在这里插入图片描述
在这个关系上我们可以看出
- 每个函数上面都有一个属性(prototype)指向了函数的原型对象(Person.prototype)。
 
- 每个实例上面都有一个隐式原型(proto)指向了函数的原型对象,如本利的p1对象有一个隐式原型也指向了Person.prototype对象。
 
- 每个函数的原型对象上面都有一个constructor属性,指向了构造函数本身。
 
实例的(person1,person2)的__proto__也是Person.prototype

那么在实例访问属性或者方法的时候应该遵循什么样的原则?
- 如果实例上面存在,就用实例本身的属性和方法。
 
- 如果实例上面不存在,就会顺着
__proto__的指向一直往上查找,找到就停止,找不到就报错。 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | function Person(name, age) {             this.name = name;             this.age = age;             this.sayName = function () {                 console.log("i am "+this.name);             }         }         Person.prototype.sayAge = function () {             console.log("我是原型上的sayAge");         }         var person1 = new Person("ljm",18)         person1.sayAge = function () {             console.log("我是person1上的sayAge")         }         person1.sayAge();         person1.sayName();         var person2 = new Person("lll",20);         person2.sayAge();         person2.sayName(); 		person2.sayHello();
  | 
 
那么输出的结果就是

如果找不到这个方法,就报错
在这里插入图片描述
虽然person1和person2都输出了sayAge方法,可是这两个方法是不一样的

原型链
那么在刚刚这个输出sayAge过程大概可以这样描述:
在person1上有sayAge,所以输出的就是person1上的sayAge
在person2上没有sayAge,但是在person2的原型上有sayAge,所以输出的就是person2上的sayAge
简单点说就是,如果我自己有,我就用我自己的;如果我没有,则去我的上一级找;这样就形成了一条原型链。上一节中Person的原型其实还有一属性__proto__,他指向了上一级Object的原型对象。

Object.prototype可以说是原型中的最高层,那么最终原型链应该是这样的

原型和实例之间的判断
使用instanceof
1 2
   | console.log(person1 instanceof Person) console.log(person1 instanceof Object)
   | 
 
 
使用isPrototypeOf()方法
1 2 3
   | console.log(Object.prototype.isPrototypeOf(person1)) console.log(Person.prototype.isPrototypeOf(person1)) console.log(Function.prototype.isPrototypeOf(person1))
   | 
 
在ES6中的新运用
在ES6中,新运用了class来对JavaScript的语法更加加以完善。
在其他语言中,例如java,就有类(class),里面有构造函数(constructor),属性,方法等
所以在ES6中,为了弥补之前的不足,新推出了class
在以前的js中,生成一个对象实例,需要先定义构造函数,然后通过prototype 的方式来添加方法,再生成实例,但是现在ES6可以这样写
1 2 3 4 5 6 7 8 9 10 11 12 13
   | class Person{     constructor(age,name){         this.age = age;         this.name = name;     }     sayName(){         console.log("我是"+this.name)     } } var person1 = new Person(18,"ljm") console.log(person1.name) console.log(person1.age) person1.sayName()
  | 
 
在ES5中原本的构造函数被constructor 替代,本来需要定义在prototype上面的,方法直接定义在class里面即可。
继承
在ES6中可以使用extends来继承类(和java差不多)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | class Student extends Person{             constructor(age,name,className){                 super(age,name);                 this.className = className;             }             sayClass(){                 console.log("我是"+this.className)             }         }         var student1 = new Student(19,"ljm","四班");         console.log(student1.age)         console.log(student1.name)         console.log(student1.className)         student1.sayClass()         student1.sayName()
  | 
 
在ES5中prototype的继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | function Person(age,name) {     this.age = age;     this.name = name; } Person.prototype.sayName = function () {     console.log("我是"+this.name) } function Student(age,name,className) {     Person.call(this,age,name);     this.className = className; } Person.prototype.constructor = Student; Student.prototype = new Person; Student.prototype.sayClass = function () {     console.log("我是"+this.className) } var student1 = new Student(19,"ljm","四班") student1.sayClass(); student1.sayName();
  | 
 
在ES6语法上更加便捷