彻底搞懂原型、原型链和继承

2022-12-27 0 538

一、为何有了蓝本?

️从缺省商业模式到蓝本商业模式

1、:memo:缺省商业模式

缺省需用来建立某一类别的第一类,能建立自订的缺省来表述自订第一类类别的特性和形式

如下表所示标识符:

function Person(name, age) { this.name = name; this.age = age; this.sayName = function () { console.log(this.name); } }const person1 = new Person(LiLi, 25); const person2 = new Person(Bob, 26);

透过缺省建立了自订第一类person1 person2,依次有他们的特性和形式,但此种建立第一类的形式有两个难题,是在每一Person示例中都要再次建立sayName形式,如下表所示,输入是false能断定

console.log(person1.sayName === person2.sayName)

彻底搞懂原型、原型链和继承

这原因在于表达式也是第一类,每表述两个表达式也是示例化两个第一类,即上面几段标识符是同构的。因此相同的示例第一类具备了相同的返回值链。总之,也能把sayName表达式的表述表述到缺省外面,能解决上面的难题,但此种形式不具备封装性,不利于标识符的维护。由此引出了蓝本商业模式。

this.sayName = function () { console.log(this.name); } }this.sayName = new Function(console.log(this.name))

2、:memo:蓝本商业模式

首先,每一表达式都有两个prototype(蓝本)属性,总之缺省中也有蓝本特性,这个特性是两个指针,指向两个第一类,而这个第一类中包含了某一类别的所有示例共享的特性和形式。也是prototype是调用缺省而建立的示例第一类的蓝本第一类。使用蓝本第一类的好处是能让所有的示例第一类共享它所包含的特性和形式。换句话说,不必在缺省中表述示例第一类的信息,而是能将这些信息直接添加到蓝本第一类中。

function Person() {} Person.prototype.name =LiLi; Person.prototype.age = 25; Person.prototype.sayName = function () { console.log(this.name); }; const person1 = new Person(); const person2 = new Person(); console.log(person1.sayName === person2.sayName)

结果为true,说明所有示例访问的都是同一组特性和同两个sayName()表达式

彻底搞懂原型、原型链和继承

:pushpin:理解蓝本第一类

1、无论什么时候,只要建立了两个新表达式,就会根据一组某一的规则为该表达式建立两个prototype特性,这个特性指向的是蓝本第一类。因此缺省中天然的带有两个指针prototype,指向两个第一类,我们就把这个第一类叫做蓝本第一类

以上面的为例来看一下Person.prototype具体是什么?

console.log(Person.prototype) console.log(Person.prototype.constructor)
彻底搞懂原型、原型链和继承

2、缺省一旦创

Person.prototype.constructor=Person

:triangular_flag_on_post:注意:缺省刚建立的时候,蓝本第一类中只有constructor特性,里面其它的形式都是从Object承继而来的

3、当调用缺省建立两个新示例后,该示例的内部将包含两个指针__proto__,指向缺省的蓝本第一类。

用图来直观的感受下缺省、蓝本第一类和示例三者之间的关系:

彻底搞懂原型、原型链和继承

到此,蓝本链的概念也就引出来了,任何第一类内部都有两个指针__proto__,指向缺省的蓝本第一类,透过这个__proto__特性连起来的蓝本第一类就叫蓝本链,蓝本链的尽头是缺省Object蓝本第一类的__proto__,为null。

这也是查找第一类中特性和形式的查找机制,搜索首先从第一类示例开始,如果没有找到,则继续搜索__proto__指针指向的蓝本第一类,依次在蓝本链上查找,直到找到为止,或者查找到null为止。

因为这个查找机制,第一类示例是不能改变蓝本第一类中的值,因为搜索的时候就直接查找到示例中的特性,相当于屏蔽了蓝本第一类中保存的同名特性。

二、承继

1、:memo:蓝本链实现承继

:pushpin:思想:

利用示例和蓝本第一类之间的关系(如果不清楚继续返回去看上一节),让两个引用类别承继另两个引用类别的特性和形式,即把子类的 prototype(蓝本第一类)直接设置为父类的示例。

function Parent() { this.name = “parent”; this.arr = [1, 2, 3]; } Parent.prototype.getName = function () { return this.name; } function Son() { this.type = “child”; } Son.prototype = new Parent(); Son.prototype.getType = function () { return this.type; } const s1 = new Son(); const s2 = new Son();

:pushpin:本质:

重写子类的蓝本第一类,替换成父类的示例。也是原来存在于父类Parent示例中的特性和形式,现在也存在于子类的蓝本第一类Son.prototype中了。

以下标识符的运行结果印证了这一点:

console.log(s1.__proto__) console.log(s1.__proto__.__proto__) console.log(s1.__proto__.constructor)
彻底搞懂原型、原型链和继承

:pushpin:存在的难题:

1、当父类的缺省中表述的示例特性会作为子类蓝本中的特性,因此子类所有的示例第一类都会共享这两个特性,当子类示例第一类上进行值修改时,如果是修改的原始类别的值,那么会在示例上新建这样两个值;但如果是引用类别的话,它就会去修改子类上唯一两个父类示例里面的这个引用类别,这会影响所有子类示例。

2、在建立子类别的示例时,不能向父类别的缺省中传递参数。

2、:memo:借用缺省法实现承继

:pushpin:思想:

在子类缺省的内部调用父类的缺省。

function Parent(_name) { this.name = _name; this.arr = [1, 2, 3]; } Parent.prototype.getName = function () { return this.name; } function Son(_name) { //承继了Parent 同时还传递了参数 Parent.call(this, _name) } Son.prototype.getType =function () { return this.type; } const s1 = new Son(); s1.arr.push(4) console.log(s1.arr)const s2 = new Son(Bob); console.log(s2.arr) console.log(s2.name)

:pushpin:运行结果:

彻底搞懂原型、原型链和继承

从运行结果清楚的看到,缺省法完美解决了蓝本链承继中存在的两个难题

:pushpin:本质:

表达式不过是在某一环境中执行标识符的第一类,因此透过apply()和call()形式能在将来新建立的第一类上执行缺省。

:pushpin:存在的难题:

父类蓝本链上的特性和形式并不会被子类承继

console.log(s2.__proto__) console.log(s2.__proto__.__proto__) console.log(s2.getName)
彻底搞懂原型、原型链和继承

3、:memo:组合承继

:pushpin:思想:

将蓝本链和借用缺省的技术组合到一起

function Parent(_name) { this.name = _name; this.arr = [1, 2, 3]; } Parent.prototype.getName = function () { return this.name; } function Son(_name) { Parent.call(this, _name) } Son.prototype = new Parent(); //Son.prototype = new Parent();导致Son.prototype.constructor指向改变 因此要改回来 Son.prototype.constructor = Son; Son.prototype.getType = function(){ return this.type; } const s1 = new Son(); s1.arr.push(4) const s2 = new Son(Bob); console.log(s2.name)console.log(s2.arr) console.log(s2.__proto__) console.log(s2.__proto__.__proto__) console.log(s2.getName())

:pushpin:运行结果:

彻底搞懂原型、原型链和继承

:pushpin:本质:

使用蓝本链实现对父类蓝本特性和形式承继,透过缺省来实现对示例特性的承继

:pushpin:存在的难题:

无论在什么情况下,都会调用两次父类缺省:一次是在建立子类别蓝本的时候,另一次是在子类别缺省内部

4、:memo:寄生组合式承继

:pushpin:思想:

不需要为了子类的蓝本而调用父类的缺省,只需要父类的__proto__提供查找组成蓝本链即可

function Parent(_name) { this.name = _name; this.arr = [1, 2, 3]; } Parent.prototype.getName =function () { return this.name; } function Son(_name) { //承继了Parent 同时还传递了参数 Parent.call(this, _name) }//提供__proto__就能了 // 不用此种形式Son.prototype = Parent.prototype; 原因在于子类 // 不可直接在 prototype 上添加特性和形式,因为会影响父类的蓝本 const pro = Object.create(Parent.prototype) // pro.__proto__即Parent.prototypepro.constructor = Son Son.prototype = pro Son.prototype.getType =function () { return this.type; } consts1 =new Son(); s1.arr.push(4) const s2 = new Son(Bob); console.log(s2.name) console.log(s2.arr) console.log(s2.__proto__)console.log(s2.__proto__.__proto__)

:pushpin:运行结果:

![]

彻底搞懂原型、原型链和继承

:pushpin:本质:

使用蓝本链的混成商业模式实现对父类蓝本特性和形式继承,透过缺省来实现对示例特性的承继

:pushpin:存在的难题:

是最理想的承继形式。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务