原型和原型链

在 ES5 中,有的人可能对原型,原型对象,及其原型链不是很清楚,今天我就说说对这些的深入认识下。(如果有什么不懂得欢迎留言探讨,当然如果有什么写的不恰当的也希望大家留言备注。)

首先,再说原型与原型对象之前,当然有必要清楚构造函数,实例,原型与原型对象之间的关系。其实他们的关系也很简单。

构造函数,实例,原型与原型对象之间的关系:

构造函数有它自己的属性及其方法,其中包括自己定义的属性和方法外,还有两个特殊属性(prototype、constructor);而每个他的实例都会拥有它的所有属性和方法(包括prototype、constructor)constructor则是指向每个实例的构造函数,而prototype 原型 则是一个地址指向原型对象,这个原型对象创建了实例后,只会取得constructor属性,其他的都是从Object继承而来;在Firefox 、 chrome在对象上都支持一个属性"proto";这个原型对象的属性和方法是所有该类实例共享的任何该类实例够可以访问该原型对象的属性和方法(后面会介绍访问原型对象属性和方法的三个方式)

如上图,p1 ,p2的的实例都有Person的属性和方法,并且prototype都指向原型对象,p1\p2共享prototype原型对象的属性和方法,各自的constructor都指向Peson,这便是构造函数、实例、原型(对象)三者的关系。

现在我来说一说访问原型对象属性和方法的三个方式:

1.通过Person.prototype 属性

console.log(Person.prototype.name);//输出----->person

  2.通过 属性屏蔽 delete (屏蔽构造函数属性或者方法)

    p1.sayName();       //输出----->构造函数对象

      delete p1.name;

    console.log(p1.name); //输出----->原型属性

    delete p1.sayName;

    p1.sayName(); //输出 --->原型对象方法

   3.通过Object.getPrototypeOf(p1)

    console.log(Object.getPrototypeOf(p1).name);//输出----->原型属性

上面我们需要注意就是当实例调用属性或者方法时,有一个”属性搜索机制“,所谓”属性搜索机制“就是当实例访问属性或者方法时首先会现在自身的实例中搜索,看是否有对应属性,有,则返回;如果没有那么它会通过prototype 到原型对象中寻找对应的属性和方法;

原型链:

其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。我们知道,每个构造函数都有一个原型对象,每个原型对象都有一个指向构造函数的指针,而实例又包涵一个指向原型对象的内部指针。

如果我们让原型对象(A.prototype) = 另一个类型的实例(new B()),那么,该原型对象(A.prototype)就有一个指向另一个原型对象(B.prototype)的指针,相应的,另一个原型对象(B.prototype)也包含指向另一个构造函数(B)的指针。 ------------->如果另一个的原型(B.prototype)又是另一个类型(C)的实例,上诉关系依然成立,就构成了实例与原型的链条,这就是原型链。

实现原型链的基本方法:

  

function Person () {
    this.name = "person";
}
 
Person.prototype.getPersonName = function () {
    return this.name;
};
 
function Student () {
    this.studentname = "student";
}
 
// 继承了Person
Student.prototype = new Person();
Student.prototype.getStudentName = function () {
    return this.name;
};
 
var stu = new Student();
console.log(stu.getPersonName());           //person
 

 如上就是通过将 Student()的prototype = new Person() 即子类的原型对象等于父类的实例,从而Student.prototype有了Person的所有属性和方法,实现了继承。通过实现原型链,再结合 “属性搜索机制“,则

stu.getPersonName()

会经过三个阶段:1.搜索实例 2.搜索Student.prototype 3.搜索Person.prototype;如果再没就会到Object 对象的prototype对象上寻找。因为所有的function和对象等引用类型都继承Object;这也就说明了为什么不是通过Object直接实例的对象(自定义类型)会有valueof(),toString()等方法。

需要注意的是,子类有时需要重写父类的方法或者新增心得方法,这些都要 替换了原型之后(也就是实现继承之后)。-----------stu 指向Student的原型,Student的原型又指向了Person的原型。从而实现了stu 继承Student Student继承Person

function Person () {
    this.name = "person";
}
 
Person.prototype.getPersonName = function () {
    return this.name;
};
 
function Student () {
    this.studentname = "student";
}
 
// 继承了Person
Student.prototype = new Person();
   // 新增方法
Student.prototype.getStudentName = function () {
    return this.name;
};
   // 重写父类方法
Student.prototype.getPersonName = function () {
    return false;
};
 
var stu = new Student();
console.log(stu.getPersonName());           //false

还有一点需要注意的是:在通过原型链实现继承时,不能用对象字面量创建原型方法,因为这样会重写原型链。 刚刚把Person的实例赋值给原型,紧接着使用字面量导致出错。------->因为现在的原型包含的是一个Object的实例,不是Person的实例,原型链被切断。

function Person () {
    this.name = "person";
}
 
Person.prototype.getPersonName = function () {
    return this.name;
};
 
function Student () {
    this.studentname = "student";
}
 
// 继承了Person
Student.prototype = new Person();
// 使用字面量添加新方法,会导致Student.prototype = new Person(); 无效
Student.prototype = {
    getStudentName :function  () {
        return this.name;
    },
    otherMethod :function  () {
        return false;
    }
 
};
 
var stu = new Student();
console.log(stu.getPersonName());           //stu.getPersonName is not a function
  

会报错  stu.getPersonName is not a function 因为此时Student和Person已经没有关系了。

所以理想的继承方式是”寄生组合式继承“,所谓寄生组合式继承通过借用构造函数来继承属性(父类构造函数里的属性+方法),通过原型链的形式继承方法(父类原型里的方法)。

// 寄生组合式继承(理想的继承方式)
function inherPrototype (Subobject,Superobject) {
    var prototype = Superobject.prototype;
    prototype.constructor = Subobject;
    Subobject.prototype = prototype;
}
 
 
function Person (name) {
    this.name = name,
    this.hand = ["right-hand","left-hand"],
    this.say = function () {
        alert("hi");
    }
 
}
Person.prototype.sayName = function () {
    alert(this.name);
}
 
function Student (name,age) {
    Person.call(this,name);
    this.age = age;
}
// 实现继承
inherPrototype(Student,Person);
Student.prototype.sayAge = function () {
    alert(this.age);
}
 
var stu1 = new Student("jack",20);
 
 
// 继承了属性(构造函数里的属性+方法)
console.log(stu1.hand[0]);                  //----------->输出right-hand
stu1.say();                         //输出 hi
//  继承了原型里的方法
stu1.sayName();                     //输出 jack      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值