Js原型和原型链

JS原型和原型链

原型和原型链作为Js高级部分,同时又是前端开发中经常用到的知识点,很多朋友学习起来很是困惑和不解,因为现在的各种流行的Js框架,很多都涉及到原型相关的知识,一旦理解不透彻,开发时,便会有很多磕磕绊绊。

首先呢,要学习原型和原型链就要明白原型是什么,是做什么的,有什么用,接着再看原型链就容易理解了。

下面我就分享一下我对原型的理解......

前端开发中,大家都熟知的JavaScript是一门面向对象的编程语言,也是一门函数式的编程语言。Js呢同Java一类的后端语言不同,Java有类的概念,而Js没有。然而两者却都是面向对象的语言。什么是面向对象?相信大家都有基本的概念和认识,封装、继承、多态。有了面向对象,大家就不必去编写面向过程的代码了,繁琐且不好维护。

 

Js中,原型就是为实现面向对象而诞生的。funciton 大家再熟悉不过了(函数或者叫方法、Js中最为特殊的对象) 。一个对象呢有很多的属性和内置的方法(隐式的和显式的)。 函数function 作为特殊对象也有很多属性。 注意: prototype就是其中之一,prototype英文就叫原型,它是一个对象。并且它是只有函数function才有的属性。其作用就是为了实现资源共享,或者说叫代码复用。怎么个共享法,请看下面的示例。

一、创建对象

说道原型和面向对象呢,肯定绕不开对象Object,创建一个对象有很多中方式,下面就一一举例展示 并对原型展开说明。

1.对象直接量的方式创建

 

2.工厂方式的创建

 

3.构造函数的方式创建对象(重点

构造函数方式创建对象和工厂模式创建,从思维上来讲其实是一样的,都是利用函数复用代码创建对象,但是本质上确有很大不同的。

首先是形式上,构造函数的函数名首字母大写,这不是官方标准,只是一种开发规范,为了和普通函数作区分。

其次,构造函数内部使用this关键字  调用的时候使用new关键字,这两点尤为重要。因为JS引擎在内部还帮我们写了两段隐式的代码,有什么作用,后续讲解,下面就把两段隐式的代码展示出来,大家可以先研究研究

 

上述三种方式呢,都可以创建对象,但是需要注意的是,1、2两种方式创建出来每一个对象,但内存中,都会独自占据一片空间,其实浪费了很多内存开销。

二、原型

构造函数他可以结合着原型 prototype 来实现 资源的共享,从而减少系统的内存开销  示例如下

上面三种方式创建的对象,大家都可以看到,无论是姓名还是性别属性,我都需要重复的写。假设,我现在要创建100个对象,这个100个对象性别都是男。写100次姓名可以理解,因为姓名大部分都不一样,但性别已经确定了,重复写100次,不管是在代码量上还是在内存开销上,都是很麻烦的。这时,原型就起到作用了,我们可以把性别这个属性提取出来,放入原型。这样的话,通过new 构造符,创建出来的对象就都可以使用这个公有的性别属性了。

注意:

通过构造函数创建出来的对象,都可以使用该构造函数的原型上的属性和方法,但是,如果对象本身有该属性或者方法,则优先使用自己身上的,下面呢,我就给stu3自身添加一个sex属性。示例如下

上图,stu3手动添加了Sex属性为女,它读取的时候,就是优先从自身读,自身没有,再去原型上查找。直到这里,若是熟悉作用域链的朋友,应该能感知到原型链的一点内容了。

 

这里要补充一个特殊属性  constructor  构造器 

constructor  他是原型prototype 的 隐式属性,指向的是构造函数本身,一个对象若是想知道自己是被谁创建出来的,就通过这个属性查询。

示例: stu3.constructor  ===>   function Student    |    Student.prototype.constructor  ===> function Student

 

 三、原型链

看完了上面的内容,大家对原型 - prototype 应该都有了一个初步的了解。而原型链又涉及到一个属性(__proto__ )也可以叫双下划线proto,一般双下划的属性都是系统内置的隐式属性。

原型链和作用域链类似,但原型链呢可能相对复杂很多,但只要理解了__proto__,就变得简单了。

 

现在回归到对象身,上面说到,prototype是函数function独有的属性,而现在的__proto__他是所有的对象都有的属性

 

那么__proto__的作用是什么呢?

回想一下构造函数,JS中有很多构造函数比如,  new Array()  new Object()  new Function()  new Number() 等等 。当然,还有我们自定义的,比如上面的new Student()

我们可以利用这些构造函数函数来创建相应的实例对象。

 

什么是实例对象?

举个例子,上图通过new 构造符 调用构造函数Student() 创建了三个对象,这三个对象就是Student构造函数的实例对象。同样,通过new Object()创建出来的对象就是构造函数Object的实例对象,实例对象 实例对象 实例对象,实例对象可以该构造函数原型上的属性和方法。

 

为什么实例对象就能使用该构造函数原型上的属性和方法呢? 重点

__proto__的作用就是把实例对象和构造函数的prototype做关联,从而实现这个实例对象可以使用构造函数原型上的方法和属性。简而言之,对象的__proto__指向的就是该对象的构造函数的prototype,那么他们是怎样进行关联的呢?还记得上面的构造函数创建对象的方式吗,里面添加了两段隐式的代码,其实还少了最重要的一句。看下图

 

 

对比示例:

 

 

既然上图的两者相等,那stu就可以使用原型上的方法 ,下图 stu.say()输出的是小李

 

 

 

在举一个和__proto__相关的例子

 

 

 per 是Person构造函数的实例对象,然后obj是一个常规的直接量创建的对象。我修改了per的__proto__,使其指向了obj。相当于obj呢是per的原型对象了,所以per他可以用obj里面的属性的方法,因此per.name输出哈哈

 

说了这么多有关__proto__的内容,还是没有接触到原型链,不着急,主要是想一次性给大家讲解清楚。下面就是原型链示例

 

 

 

 简单讲解一下:

创建了三个构造函数,比较语义化,就是爷爷  爸爸  儿子  。不出意外的话呢,他们三都是同一个姓,对吧。 儿子跟父亲姓  父亲跟爷爷姓  爷爷姓王,自然,孙子肯定也姓王。

代码上呢,创建了一个child对象,他是Son()的实例对象,Son构造函数的原型呢指向的是father。father是通过new Father构造函数创建的,father的原型自然指向的就是Father.prototype。Father.prototype被我们修改为grand,grand是Grand的实例对象,他的原型就是Grand.prototype。

那么child.xing,他本身是没有xing这个属性的,他的查找过程是先找自身,自身没有去自身的原型上找,自身的原型是father也没有,就去自身原型的原型上找,找到了,就拿过来了,如果没有,那就没有呗。这种链式的查找方式,就是我们所谓的原型链。也类似作用域链。

注: prototype他是实现资源共享的对象,我们是可以往里面添加自定义方法和属性的,prototype的指向也是可以修改的  constructor作为原型的隐式属性也是可以修改的。

JS原型和原型链的基本只是大概就是这些,后续更多涉及到面向对象编程思想的用法,后续有时间,再给大家分享。本人技术不精,写得有误,理解有误的地方希望大家留言评论指教,大神勿喷。另外写这个还是比较费时,有心的朋友可以点个关注,谢谢大家!

posted @ 2022-03-06 15:19  web搬砖客  阅读(377)  评论(0编辑  收藏  举报