原型是Javascript中的继承的基础,JavaScript的继承主要依靠原型链来实现的。html
在JavaScript中,咱们建立一个函数A(就是声明一个函数), 就会为该函数建立一个prototype属性。并且也会在内存中建立一个对象B,A函数的属性 prototype 指向这个对象B( 即:prototype的属性的值是这个对象 )。这个对象B就是函数A的原型对象,简称函数的原型。这个原型对象B 默认会有一个属性 constructor, constructor属性指向函数A ( 意思就是说:constructor属性的值是函数A )。java
/*
声明一个函数,则这个函数默认会有一个属性叫 prototype 。并且浏览器会自动按照必定的规则
建立一个对象,这个对象就是这个函数的原型对象,prototype属性指向这个原型对象。这个原型对象
有一个属性叫constructor 执行了这个函数
注意:原型对象默认只有属性:constructor。其余都是从Object继承而来,暂且不用考虑。
*/
function Person () {
}
复制代码
下面的图描述了声明一个函数以后发生的事情:浏览器
当把一个函数做为构造函数 (理论上任何函数均可以做为构造函数) 使用new建立对象的时候,那么这个对象就会存在一个默认的不可见的属性,来指向了构造函数的原型对象。 这个不可见的属性咱们通常用 [[prototype]] 来表示,只是这个属性没有办法直接访问到。bash
function Person () { }
/*
利用构造函数建立一个对象,则这个对象会自动添加一个不可见的属性 [[prototype]], 并且这个属性
指向了构造函数的原型对象。
*/
var p1 = new Person();
复制代码
观察下面的示意图:函数
__proto__ 是对象实例才有的属性,指向对象的原型。
prototype 是构造函数才有的属性,该属性指向了一个对象,这个对象正是调用该构造函数而建立的实例的原型
实例的__proto__属性 和 构造函数的 prototype 都指向该对象原型
复制代码
这几句话能解释一切关于原型方面的问题:优化
当 new 一个函数的时候会建立一个对象,『函数.prototype』 等于 『被建立对象.__proto__』
一切函数都是由 Function 这个函数建立的,因此『Function.prototype === 被建立的函数.__proto__』
一切函数的原型对象都是由 Object 这个函数建立的,因此『Object.prototype === 一切函数.prototype.__proto__』
复制代码
原型链基本思路:利用原型让一个引用类型继承另外一个引用类型的属性和方法。this
每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数想指针(constructor),而实例对象都包含一个指向原型对象的内部指针(__proto__)。
若是让原型对象等于另外一个类型的实例,此时的原型对象将包含一个指向另外一个原型的指针(__proto__),另外一个原型也包含着一个指向另外一个构造函数的指针(constructor)。
假如另外一个原型又是另外一个类型的实例……这就构成了实例与原型的链条。
复制代码
原型链基本思路(图解):spa
'__proto__'是对象的属性、'prototype'是函数的属性
null是对象原型链的终点,其值既有(是一个对象)又无(不引用任何对象),
表明着对象本源的一种混沌、虚无的状态,正与老子《道德经》中的“道”,有着同等的意义
(心中一万只艹尼玛奔腾而过,仍是写java爽啊)。
在JS中,undefined是全局对象的一个属性,它的初始值就是原始数据类型undefined,而且没法被配置,也没法被改变。
undefined从字面意思上理解为“未定义”,即表示一个变量没有定义其值。
而null是一个JS字面量,表示空值,即没有对象。
与undefined相比,null被认为是“指望一个对象,可是不引用任何对象的值”,而undefined是纯粹的“没有值”。
复制代码
从一张图看懂原型对象、构造函数、实例对象之间的关系prototype
prototype:构造函数中的属性,指向该构造函数的原型对象。
constructor:原型对象中的属性,指向该原型对象的构造函数
_proto_:实例中的属性,指向new这个实例的构造函数的原型对象
复制代码
优势:实现了继承属性,但值都不相同指针
缺点: 没法继承父级类别中原型上的方法
function Person(name,age,sex,weight){
this.name=name;
this.age=age;
this.sex=sex;
this.weight=weight;
}
Person.prototype.sayHi=function(){
console.log("您好")
}
function Student(name,age,sex,weight,score){
//将当前实例对象传入Person 借过来使用一次来达到继承效果
Person.call(this,name,age,sex,weight);
this.score=score;
}
var stu1=new Student("小明",10,"男","10kg","100")
复制代码
利用prototype,将Student 的prototype 指向 Person 来达到继承效果,
优势:继承了父级原型上的方法
缺点: 实例化多个Student 都必须共用相同的name 和 age
// 此处
Student.prototype.constructor=Student
复制代码
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.eat=function(){
console.log("Person 吃饭")
}
function Student(num,score){
this.num=num
this.score=score
}
//继承
Student.prototype=new Person("小红",10)
Student.prototype.constructor=Student
var stu =new Student(2016002288,80)
stu.eat()//Person 吃饭
复制代码
组合继承其实就是结合了上述的两种方法来实现继承,拥有两种方法的优势
function Person(name,age,sex){
this.name=name;
this.age=age;
this.sex=sex;
}
Person.prototype.sayHi=function(){
console.log("你好")
}
function Student(name,age,sex,score){
//借用构造函数
Person.call(this,name,age,sex)
this.score=score
}
// 改变了原型指向
Student.prototype=new Person();//不传值
Student.prototype.eat=function(){
console.log("吃东西");
}
var stu=new Student("小黑",20,"男","100分")
console.log(stu.name,stu.age,stu.sex,stu.score);
stu.sayHi()//你好
stu.eat()//吃东西
复制代码
相似于复制,把一个对象中的属性和方法直接复制到另外一个对象中
function Person(){
}
Person.prototype.name="小红"
Person.prototype.age=18
function Student(){
}
var p=Person.prototype;
var s=Student.prototype;
for(key in p){
s[key]=p[key]
}
console.dir(Student)
复制代码
每次都要for in 好累 , 能够进行优化封装一下
function extend(Child,Parent) {
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p) {
      c[i] = p[i];
      }
//这个属性直接指向父对象的prototype属性,能够直接调用父对象的方法,为了实现继承的完备性,纯属备用性质
    c.par = p;
  }
复制代码
优势 : 效率比较高
缺点 : 由于至关因而个传址过程 因此修改Student的属性 Person 的也会被更改
function Person(){};
Person.prototype.name="小红";
Person.prototype.age=18;
function Student(){};
Student.prototype=Person.prototype;
console.dir(Student);
console.dir(Person);
Student.prototype.age=25;
复制代码
用这种方式修改 Student 的prototype 不会影响到 Person的prototype
function Person(){};
Person.prototype.name="小红";
Person.prototype.age=11;
function Student(){};
var F=function(){};
F.prototype=Person.prototype;
Student.prototype=new F();
Student.prototype.constructor=Student;
Student.prototype.age=25;
console.dir(Person)
console.dir(Student)
复制代码