浅谈原型、原型链与继承

    xiaoxiao2023-09-30  208

    一、原型

    1.那么首先,什么是原型呢?

    每一个javascript对象在创建的时候就会有一个与之关联的对象B产生,对象B就是所说的“原型”。 (1) 原型也是一个对象,其他对象可以通过原型实现属性继承, (2) js中的继承就是基于原型的继承; (3) 所有对象在默认情况下都有一个原型,因为原型也是一个对象,所以每个原型自身 又有一个原型,默认的对象原型在原型链的顶端;

    2.原型的定义及一些特点:

    (1) 定义:原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。 通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。 (2) 利用原型特点和概念,可以提取共有属性。 (3) 对象如何查看原型 — > 隐式属性 __proto__。 (4) 对象如何查看对象的构造函数 — > constructor。 (5) 每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性

    3.原型相关属性

    (1) prototype:存在于构造函数中,指向这个构造函数的原型对象 (2) __proto__:存在于实例对象中,指向这个实例对象的原型对象 (3) constructor:存在于原型对象中,指向构造函数 (4) 若一个构造函数没有指定其原型,则其原型默认为Object.prototype 举例: function Pro(name,age){ this.name=name; this.age=age; } var pro1=new Pro(); var pro2=new Pro(); pro1.__proto__==pro2. __proto__; pro1.__proto__==Pro.Prototype; Pro.prototype.constructor==Pro(); Pro.prototype.__ptoto__==Object.prototype; Object.prototype.constructor==Object(); 结论: (1) pro1.__proto__和pro2.prototype都指向构造函数Pro的原型对象; (2) 如果使用new Person()创建多个对象,则多个对象都会同时指向Person构造函数的原型对象;

    4. 原型方法

    (1) getPrototypeOf():获取一个对象的原型 格式:Object. getPrototypeOf(对象) (2) setPrototypeOf():设置一个对象的原型 格式:Object. setPrototypeOf(对象) (3) hasOwnProperty():用于判断一个属性是本地属性,还是继承梓prototype对象的属性 格式:对象. hasOwnProperty(’属性名’): (4) isPrototypeOf():判断对象a是否存在于另一个对象prototypeObject的原型链中( 只有存在继承关系时该方法才有用) 格式:prototypeObject.prototype.isPrototypeOf(a) (5) instanceof:判断a是否是b的实例对象 格式:a.instanceof.b

    二、原型链

    1.那么首先,什么是原型链呢?

    请看图:

    A.protorype = { name: 'a' } function A() ( this.name = 'A'; ) B.prototype = new A(); function B() { this.name = 'B'; } C.prototype = new B(); function C(){ this.name = 'C'; } - C继承B,B继承A,形成C->B->A的一条以原型为继承方式的原型链。 - 一个实例,至少应该拥有指向原型的proto属性,这是JavaScript中的对象系统的基础。 不过这个属性是不可见的,我们称之为“内部原型链”,以便和构造器的prototype所组成的 “构造器原型链”(亦即我们通常所说的“原型链”)区分开

    2.原型链上属性的增删改查:

    - 查:优先去实例对象上寻找是否有该属性,若没有,则再去其对应的原型上去寻找该属性, 若都没有,则返回undefined      - 增:直接给实例对象增添属性,则仅仅在实例对象上增添属性,若在原型上增添属性, 则在原型上增添属属性,则在原型上增添属性,其实例继承原型增添的属性。     - 删:delete仅仅能删除实例对象的属性,即构造函数原有的自己的属性和后来实例对象 增添的属性,还有关于delete的一点需注意,delete无法删除原型的属性和用var 定义的变量(即非window的属性) - 改:更改实例对象的属性,则仅仅更改实例对象的属性值;更改原型的属性值, 则更改原型的属性值,继承该原型的对象对应属性值也会被更改;

    三、继承

    1.原型链是ECMAScript标准指定的默认继承方式

    对象继承的发展:

    (1) 传统模式:即正常的通过构造函数创建实例对象,来继承原型 缺点:继承了过多不必要的属性 (2) 借用其他构造函数(即通过call / apply来改变构造函数内this对象的引用) 缺点:无法继承借用构造函数的原型

         A.prototype = { name: 'a', age: 18, class: 1 } function A(){ this.name = 'A'; } function B(){ A.call(this); } var b = new B(); console.log(b.name); // A console.log(b.age) // undefined

    (3) 共享原型:即将其他构造函数的原型直接赋值给本构造函数的原型 缺点:两个原型会想回影响,更改其中一个原型,更一个对应的原型也会被更改。

    A.prototype = { name: 'a', age: 18, class: 1 } function A(){ this.name = 'A'; } B.prototype = A.prototype; function B(){ this.name = 'B'; }   C.prototype = A.prototype;   function C() {     this.name = "C";   } var a = new A(); var b = new B(); var c = new C(); console.log(a.age); // 18 console.log(b.age); //18 console.log(c.age); //18 // 原型继承成功 B.prototype.age = 20; //更改其中一个原型的age属性 console.log(b.age);//20 console.log(c.age); //20 // 继承A原型的B和C相互影响

    (4) 圣杯模式:

    每次继承的都是新创建的F构造函数实例,相互之间不会影响。其实此处针对F形成了闭包,Child引用了F,导致F不会销毁。

    正常函数形式:

    function inherit (Child, Parent) { // 借用F这个中间量来继承,而不是直接共享原型 var F = function (){} F.prototype = Parent.prototype; Child.prototype = new F(); // 自定义构造函数原型时,同时要更正自定义原型的constructor,否则一般默认为Object(),次函数若不指定constructor,则constructor为Parent Child.prototype.constructor = Child; Child.prototype.uber = Parent; //记录真正继承的是谁 }

    闭包形式:

       var inherit = (function(){ var F = function (){}; return function (Child, Parent) { F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; Child.prototype.uber = Parent; } })();
    最新回复(0)