说说原型(prototype)、原型链和原型继承

2022-12-15 0 400

一、蓝本 prototype 和 __proto__

每一第一类都有两个__proto__特性,因此对准它的prototype蓝本第一类每一缺省都有两个prototype蓝本第一类

prototype蓝本对象里的constructor对准缺省这类
说说原型(prototype)、原型链和原型继承

有的是老师可能会问prototype 和 __proto__有甚么用呢?

示例第一类的__proto__对准缺省的prototype,进而同时实现承继。

prototype第一类相等于某一类别大部份示例第一类都能出访的公用罐子

说说原型(prototype)、原型链和原型继承

看呵呵标识符就确切了

function Person(nick, age){ this.nick = nick; this.age = age; } Person.prototype.sayName = function(){ console.log(this.nick); } var p1 = new Person(Byron, 20); var p2 = new Person(Casper, 25); p1.sayName() // Byron p2.sayName() // Casper p1.__proto__ === Person.prototype //true p2.__proto__ === Person.prototype //true p1.__proto__ === p2.__proto__ //true Person.prototype.constructor === Person //true

注意

1. 当Object.prototype.__proto__ 已被大多数浏览器厂商所支持的今天,其存在和确切行为仅在ECMAScript 2015规范中被标准化为传统功能,以确保Web浏览器的兼容性。为了更好的支持,建议只使用Object.getPrototypeOf()

2. Object.create(null) 新建的第一类是没有__proto__特性的。

二、蓝本链

请看以下标识符

var arr = [1,2,3] arr.valueOf() // [1, 2, 3]

我们再来看一张图

说说原型(prototype)、原型链和原型继承

按照之前的理论,如果自身没有该方法,我们应该去Array.prototype第一类里去找,但是你会发现arr.__proto__上压根就没有valueOf方法,那它是从哪里来的呢?

各位客官,请看这张图

说说原型(prototype)、原型链和原型继承

很奇怪我们在Array.prototype.__proto__里找到了valueOf方法,为甚么呢?

查找valueOf方法的过程

当试图出访两个第一类的特性时,它不仅仅在该第一类上搜寻,还会搜寻该第一类的蓝本,以及该第一类的蓝本的蓝本,依次层层向上搜索,直到找到两个名字匹配的特性或到达蓝本链的末尾。

查找valueOf大致流程

当前示例第一类obj,查找obj的特性或方法,找到后返回没有找到,通过obj. __proto__,找到obj缺省的prototype因此查找上面的特性和方法,找到后返回没有找到,把Array.prototype当做obj,重复以上步骤

当然不会一直找下去,蓝本链是有终点的,最后查找到Object.prototype时

Object.prototype.__proto__ === null,意味着查找结束
说说原型(prototype)、原型链和原型继承

我们来看看上图的关系

arr.__proto__ === Array.prototype true Array.prototype.__proto__ === Object.prototype true arr.__proto__.__proto__ === Object.prototype true // 蓝本链的终点 Object.prototype.__proto__ === null true

蓝本链如下:

arr —> Array.prototype —> Object.prototype —> null

这就是传说中的蓝本链,层层向上查找,最后还没有就返回undefined

三、JavaScript 中的承继

3.1 甚么是承继?

承继是指两个第一类直接使用另外两个第一类的特性和方法

由此可见只要同时实现特性和方法的承继,就达到承继的效果

得到两个第一类的特性得到两个第一类的方法

3.2 特性如何承继?

我们先创建两个Person类

function Person (name, age) { this.name = name this.age = age } // 方法定义在缺省的蓝本上 Person.prototype.getName = function () { console.log(this.name)}

此时我想创建两个Teacher类,我希望它能承继Person大部份的是特性,因此额外添加属于自己某一的特性;

两个新的特性,subject——这个特性包含了教师教授的学科。

定义Teacher的缺省

function Teacher (name, age, subject) { Person.call(this, name, age) this.subject = subject }

特性的承继是通过在两个类内执行另外两个类的缺省,通过call指定this为当前执行环境,这样就能得到另外两个类的大部份特性。

Person.call(this, name, age)

我们示例化呵呵看看

var teacher = new Teacher(jack, 25, Math) teacher.age 25 teacher.name “jack”

很明显Teacher成功承继了Person的特性

3.3 方法如何承继?

我们需要让Teacher从Person的蓝本第一类里承继方法。我们要怎么做呢?

我们都知道类的方法都定义在prototype里,那其实我们只需要把Person.prototype的备份赋值给Teacher.prototype即可

Teacher.prototype = Object.create(Person.prototype)

Object.create简单说就是新建两个第一类,使用现有的是对象赋值给新建第一类的__proto__

可能有人会问为甚么是备份呢?

因为如果直接赋值,那会是引用关系,意味着修改Teacher. prototype,也会同时修改Person.prototype,这是不合理的。

另外注意一点就是,在给Teacher类添加方法时,应该在修改prototype以后,否则会被覆盖掉,原因是赋值前后的特性值是不同的第一类。

最后还有两个问题,我们都知道prototype里有个特性constructor对准缺省这类,但是因为我们是复制其他类的prototype,所以这个对准是不对的,需要更正呵呵。

如果不修改,会导致我们类别判断出错Teacher.prototype.constructor = Teacher
Teacher.prototype = Object.create(Person.prototype) Teacher.prototype.constructor ƒ Person(name, age) { this.name = name this.age = age } Teacher.prototype.constructor = Teacher ƒ Teacher(name, age, subject) { Person.call(this, name, age) this.subject = subject }

承继方法的最终方案:

Teacher.prototype = Object.create(Person.prototype) Teacher.prototype.constructor = Teacher

3.4 hasOwnProperty

在蓝本链上查询特性比较耗时,对性能有影响,试图出访不存在的特性时会遍历整个蓝本链。

遍历第一类特性时,每一可枚举的特性都会被枚举出来。 要检查是否具有自己定义的特性,而不是蓝本链上的特性,必须使用hasOwnProperty方法。

hasOwnProperty是 JavaScript 中唯一处理特性因此不会遍历蓝本链的方法。

四、总结

prototype 和 __proto__

每一第一类都有两个__proto__特性,因此对准它的prototype蓝本第一类每一缺省都有一个prototype蓝本第一类

prototype蓝本第一类里的constructor对准缺省这类

蓝本链

每一第一类都有两个__proto__,它对准它的prototype蓝本第一类,而prototype蓝本第一类又具有两个自己的prototype蓝本第一类,就这样层层往上直到两个第一类的蓝本prototype为null

这个查询的路径就是蓝本链

JavaScript 中的承继

特性承继
function Person (name, age) { this.name = name this.age = age } // 方法定义在缺省的蓝本上 Person.prototype.getName = function () { console.log(this.name)} function Teacher (name, age, subject) { Person.call(this, name, age) this.subject = subject }
方法承继
Teacher.prototype = Object.create(Person.prototype) Teacher.prototype.constructor = Teacher

推荐JavaScript学习书籍

1. 《JavaScript高级程序设计(第3版)》

推荐理由:JavaScript技术经典名著,还用我多说甚么呢,我觉得你的床头应该有一本。

2. 《你不知道的 JavaScript》

推荐理由:将晦涩难懂的JS 细节深入浅出,能很好帮助理解 JS 细节,是真的很不错 。

五、参考链接

相关文章

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

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