原型和原型链

一、原型的由来

  说到原型和原型链,就必须得先说一下面向对象。面向对象是为了描叙某个事物在整个解决问题的步骤中的行为,因此我们常常需要创建对象。创建对象就要用到构造函数,而每个创建的函数都有个属性,那就是原型,英文是prototype,它是一个对象。所以,要解释原型,就得先从构造函数说起。

二、创建函数

  构造函数:是一种特殊的方法。主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。通过构造函数我们就不用去反复定义属性和方法。要构造一个函数很简单,我举个小栗子就知道了。

<script>
    function Person(_name,_age,_sex){
    this.name=_name;
    this.age=_age;
    this.sex=_sex;
  }
  var per1=new Person("Alice",22,"女");
  console.log(per.name);
</script>

首先构造一个Person函数,然后加入name、age、sex属性,然后新建一个per1对象,这样就可以打印出所需要的per1的属性啦~接下来就是原形了。

三、原型

  之前说过,每个创建的函数都有一个原型属性,它是通过调用构造函数创建的那个对象的原型对象。原型的特点是包含可以由特定类型的所有实例共享的属性和方法,在内存中只有一份。使用原型的好处是可以让所有对象实例共享它所包含的属性和方法;也就是说,不必在构造函数中定义对象信息(属性/方法),而是可以直接将这些信息添加到原型中。那么如何设置原型属性呢?

Person.prototype={
    info:function(){
        console.log("我的名字是"+this.name);
    },
    walk:function(){
    console.log("I can walk");
    }
}
var per2=new Person("Rihanna",30,"女");
per2.info();

这就是原型的写法,在第一段代码的基础上,创建新的对象per2,就可以调用到Person原型中添加的函数了。

四、原型链

  当对象尝试获取某个属性或方法时,会先到该对象的构造函数中去找,若没有,就会到该构造函数的原型中去找,如果原型也没有,就到原型的原型中去找,最终找到顶层Object.prototype。若没有返回null。这个过程形成一条一步步找上去的路径,这就是原型链。

五、继承

  面向对象有三大特征,其中有一个就是继承。所谓继承是指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。

构造函数继承:

function Student(_name,_age,_sex,_grade){
  //Person.call(this,_name,_age,_sex);
    Person.apply(this,[_name,_age,_sex]);
  this.grade=_grade;
}
var stu1=new Student("Angela",12,"女",87);
console.log(stu1.name,stu1.grade);

还是在前面代码的基础上,新建一个Student函数,通过call或apply的方法,获取到Person函数中的属性,区别是this的指向不同。同时可以新增属性,因此打印出来的结果是Angela和87。

原型继承:

Student.prototype=new Person();
Student.prototype.test=function(){
    console.log("我的考试成绩是"+this.grade);
}
var stu2=new Student("Jessi",22,"女",100);
console.log(stu2.name);
stu2.info();
stu2.test();

同样在前面的基础上,让Student的原型作为一个新的Person对象,这样就可以获取到Person中的info函数,同时可以增加新的text函数,因此结果为“我的名字是Jessi”,“我的考试成绩是100”。

为了让大家看的更清楚,我发一遍完整的代码

<script>
    function Person(_name,_age,_sex){
        this.name=_name;
        this.age=_age;
        this.sex=_sex;
  }
  var per1=new Person("Alice",22,"女");
  console.log(per.name);
  Person.prototype={
    info:function(){
        console.log("我的名字是"+this.name);
    },
    walk:function(){
        console.log("I can walk");
    }
  }
  var per2=new Person("Rihanna",30,"女");
  per2.info();
 function Student(_name,_age,_sex,_grade){ //Person.call(this,_name,_age,_sex);   Person.apply(this,[_name,_age,_sex]); this.grade=_grade; } var stu1=new Student("Angela",12,"女",87); console.log(stu1.name,stu1.grade); Student.prototype=new Person(); Student.prototype.test=function(){ console.log("我的考试成绩是"+this.grade); } var stu2=new Student("Jessi",22,"女",100); console.log(stu2.name); stu2.info(); stu2.test(); </script>

六、其他属性
constructor,可以返回该对象的构造函数

<script>
    function Person(_name){
        this.name=_name;
    }
    Person.prototype={
        constructor:Person,
    info:function(){
        console.log("My name is "+this.name);
    }
    }
    var per=new Person("Yoyo");
    console.log(per.constructor);
</script>        

在原型中加入代码“constructor:Person,”然后新建per对象,直接打印per.constructor,就能得到per的构造函数,打印结果为

function Person(_name){

  this.name=_name;

}

还有个instanceof,可以检查实例化对象是不是由指定的构造函数构造出来的,返回值是布尔值。

<script>
  var arr=new Array();
  console.log(arr instanceof Array);//true
  console.log(arr instanceof Number);//false
</script>

因为arr是创建的数组对象,因此,用instanceof判断时,Array返回的是true,Number返回的是false。

七、结束语

  原型就是创建的函数的属性,每个函数都有,可以继承和增加属性。调用实例对象的属性或方法时找寻的过程构成原型链。原型和原型链其实很好理解,最主要的是继承部分,自己举例子多敲代码就明白了。

  至此,第四篇博客,OVER~

原文地址:https://www.cnblogs.com/sanweimiao/p/6534961.html