【相关推荐:javascript视频教程、web前端】
原型是什么?原型是 JS 我们在基础学习中没有提到概念。原型是一般指标,主要包括 原型对象 (prototype) , 对象原型 (__proto__), 原型链 等等,据统计,这些概念也是面试中经常问到的。本文将带您了解和掌握原型的相关知识,使您不再困惑。
一、构造函数
我们学到了很多面向对象的语言,比如 java c 等等,但是 JavaScript 例外,在 ES6 以前没有类别的概念,那么我们以前是如何创建对象的呢? ES6 我们以前用过 构造函数 构建函数是一种包含对象公共特征的特殊函数,以创建实例对象 new 一起使用才有意义。
构造函数的注意事项:
- 构造函数名的首字母应大写
- 配合构造函数 new 一起使用
1.1 构造函数的使用方法
<script> function Animal(name,age){ //构造函数名首字母大写 this.name=name; this.age=age; this.eat=function(){ console.log(';我在吃饭'); } } var dog=new Animal('旺财',3) //要配合 new 共同使用创建对象 console.log(dog.name); console.log(dog.age); dog.eat() </script>
1.2 构造函数new的执行过程
new 执行过程如下:
- new 创建空对象时,会创建空对象
- 构造函数内 this 指向空对象
- 执行构造函数内的代码给空对象赋值,添加属性方法
- 返回这个对象
1.3 实例成员和静态成员
实例成员:
- 实例成员是观战属内部 this 添加的成员
- 实例成员只能通过实例对象进行调访,而不能通过构建函数名访问
<script> function Animal(name,age){ this.name=name; this.age=age; } var dog=new Animal('旺财',3) console.log(dog.name); console.log(Animal.name); </script>
静态成员:
- 静态成员是通过构建函数本身创建的成员
- 静态成员只能通过构造函数名访问,而不能通过实例对象访问
<script> function Animal(name,age){ this.name=name; this.age=age; } var dog=new Animal('旺财',3) Animal.color='黑色' console.log(Animal.color); console.log(dog.color); </script>
二: 原型对象 prototype
2.1 为什么有原型对象?
在我们开始解释原型对象是什么之前,解释一个案例,还是刚才的案例? Animal 类,我们创建了多个实例对象,输出实例对象的比较,我们发现输出 false,也就是说,复杂数据类型的地址不同,原因是什么?
<script> function Animal(name,age){ this.name=name; this.age=age; this.eat=function(){ console.log(';我在吃饭'); } } var dog=new Animal('旺财',3) var cat=new Animal('咪咪',3) var pig=new Animal('哼哼',3) var fish=new Animal('咕噜',3) var sheep=new Animal('咩咩',3) console.log(dog.eat==cat.eat); </script>
在创建实例对象的过程中,new 这个过程将首先创建一个新的对象,但复杂的数据类型将打开一个空间存储(对象、方法),这是结构函数中同样的方法打开了无数块内存,导致内存的极度浪费
2.2 使用原型对象
构造函数原型 prototype 它是构造函数中的一个属性,它的属性是一个指针,指向一个对象共方法,存在于对象中,然后通过构建函数创建实例对象可以公开使用该方法,不需要打开多个重复的内存空间。也可直接称为原型对象,以解决上述内存浪费问题。
上述案例解决方案:
我们使用原型对象存储公共方法,让实例对象调用该方法,并比较两者的地址是否相同
<script> function Animal(name,age){ this.name=name; this.age=age; } Animal.prototype.eat=function(){ console.log(';我在吃饭'); } var dog=new Animal('旺财',3) var cat=new Animal('咪咪',3) dog.eat() cat.eat() console.log(dog.eat==cat.eat); </script>
我们发现,这种方法不仅调用成功,而且调用方法的地址也是一样的,这证明其复杂的公共数据类型只开辟了一个内存空间,减少了以往公共方法在构造函数中写入的内部资源浪费。
三、对象原型 __proto__
3.1 对象原型是什么?
对象原型__proto__它的作用是让你发现一个问题:构造函数的原因prototype实例对象可以使用属性添加法吗?这是因为每个对象都有一个对象 __proto__属性(注意前后都有两条下划线),这个属性也是一个指针,指向相应构造函数的原型对象 prototype,这就解释了为什么实例对象可以调用原型对象中的方法。
或者可以理解为:
- 原型对象prototype 等价于 对象原型 __proto__
3.2 对象原型__proto__的注意点
要注意对象原型__protp__它的功能只是为找到原型对象中的内容提供一个方向。我们不需要使用它。我们只需要记住它指向相应构造函数的原型对象 prototype 即可
方法搜索原则:
- 首先,找出是否有实例化自身构造函数的目标方法。如果有,请调用它
- 如果没有自己的构造函数,因为对象本身有属性__protp__,其指向构造函数的原型对象prototype,你会找到原型对象的方法吗?
四、构造函数 constructor
4.1 为什么 constructor 又称构造函数
对象原型 __proto__ 身上和构造函数的原型对象 prototype 身上有一个 constructor 属性,之所以叫 constructor 称为构造函数,因为该属性指向相应的构造函数本身,主要用于记录实例对象引用的构造函数
打印二者的constructor属性:
<script> function Animal(name,age){ this.name=name; this.age=age; } Animal.prototype.eat=function(){ console.log(';我在吃饭'); } var dog=new Animal('旺财',4) console.log(dog.__proto__.constructor); console.log(Animal.prototype.constructor); </script>
我们发现打印的结果确实是构造函数本身
4.2 手动返回 constructor 的情况
更多的时候,我们需要手动返回 constructor 在构造函数的原型对象中以对象的形式存储多种公共方法时,会出现以下情况:
<script> function Animal(name,age){ this.name=name; this.age=age; } Animal.prototype={ eat:function(){ console.log(';我在吃饭'); }, run:function(){ console.log('我在跑'); } } var dog=new Animal('wangchai',3) console.log(Animal.prototype.constructor); console.log(dog.__proto__.constructor); </script>
我们发现它找不到相应的结构函数,因为我们添加了原型对象的方法,我们采用了这笔钱以.方式添加,是在原有基础上追加添加的,不会覆盖掉内部原有的内容。而我们采用=以对象形式添加的方法实际上是一个赋值过程,覆盖了原始内容,导致 prototype 内部原有的 constructor 该方法已被覆盖
此时,我们需要手动返回 constructor 来找到返回的是哪个的构造函数
<script> function Animal(name,age){ this.name=name; this.age=age; } Animal.prototype={ constructor:Animal, eat:function(){ console.log(';我在吃饭'); }, run:function(){ console.log('我在跑'); } } var dog=new Animal('wangchai',3) console.log(Animal.prototype.constructor); console.log(dog.__proto__.constructor); </script>
这样,我们就能成功地得到它 constructor 哪个构造函数指向?
其格式为:
- constructor : 构造函数名
【相关推荐:javascript视频教程、web前端】
以上是简单介绍JavaScript 请多关注原型和原型链的细节php中文网其他相关文章!
