熟悉软件开发的朋友都知道, 原型是产品或数据系统的一个基本的实用模型, 通常为示范目的或开发程序的部份结构. 原型的重要性不言而喻, 接下来我就会为你讲解关于 JavaScript 中的原型概念.
原型对象释义
每一个构造函数都有一个与之相关联的对象, 该对象称之为原型对象.
每个实例对象都能共享其原型对象上的属性和方法.
原型对象的作用主要用来实现属性的继承, 让实例对象能共享原型对象的属性, 减少内存分配.
所以, 在上一节中, 我们想在每个 Person 对象中共享同一个 say 方法, 可以这样来实现.
- function Person(name, age) {
- this.name = name;
- this.age = age;
- }// 在原型对象上添加 say 函数, 实例对象共享该函数
- Person.prototype.say = function(){
- console.log("say hello");
- };var p = new Person("zs", 10, say);
- p.say();var p2 = new Person("zs", 10, say);
- p2.say();
在原型对象上添加成员的方法:
? 构造函数. prototype. 成员名 = 成员值;
为 Person 原型对象添加 say 方法后, 实现了在多个实例对象上共享该方法的功能.
获取原型对象的方法:
? 构造函数. prototype
? 实例对象. proto
在每个实例对象上都有一个 proto 的属性, 也是用来获取该对象的原型对象.
Person.prototype == p. proto ;//true
下图详细说明了各对象之间的关系:
面向对象中的核心概念
构造函数: Person, 和 new 关键字一起创建对象
构造函数的原型对象: Person.prototype,
原型对象: 和创建实例对象的构造函数相互关联的对象
实例对象: 由构造器创建出来的对象称之为实例对象
实例化: 由构造器创建实例对象的过程称之为实例化
对象的成员: 属性 + 方法
实例成员: 实例对象上的属性和方法, name,age, 只能当前实例对象才能访问
原型成员: 原型对象上的属性和方法, say(), 使用该原型对象对应构造器创建出来的所有实例对象都能访问
静态成员: 直接添加在构造函数上的属性和方法, 只能使用构造函数才能访问
proto 属性介绍
该属性是在 ES6 之后才纳入规范, 在这之前, 只有部分浏览器实现.
该属性可以获取指定实例对象的原型对象, p. proto , 和 Person.prototype 获取的一样
我们也可以使用 Object 构造器上的 getPrototypeOf(实例对象) 方法获取指定实例对象的原型对象
以上提到的三种获取原型对象的方法所得到的结果是一样的. 即:
Object.getPrototypeOf(p) == Person.prototype == p. proto
扩展内置对象
内置对象是 JS 中事先定义好的对象, 可以直接拿来使用的对象, 在这类对象中已经封装好了一堆的方法和属性, 方便开发者完成基本的功能.
但是在实际开发中, 这些属性或者方法不一定能够满足我们的需求, 此时就需要对这些内置对象做功能扩展.
需求: 为数组对象添加一个获取元素个数的方法
- var arr1 = [1, 2, 3];var arr2 = ["A", "B", "C","D"];
- arr1.getLength = function () {
- return this.length;
- }console.log(arr1.getLength());
上面为数组 arr1 添加了一个 getLength() 方法获取其元素个数, 那么此时的 arr2 对象上有这个方法吗? 相信大家心里都有答案. 如果想要 arr2 拥有同样的功能, 也需要同样的操作.
所以这种方式不可取, 如果 100 个数组都想都需要这样的功能, 操作起来就比较复杂了.
根据前面学过的知识点, 我们完全可以使用原型来解决这个问题.
- var arr1 = [1, 2, 3];var arr2 = ["A", "B", "C","D"];Array.prototype.getLength = function () {
- return this.length;
- }console.log(arr1.getLength());// 3console.log(arr2.getLength());// 4
我们直接在 Array 的原型对象上添加 getLength() 方法, 之后创建的所有的数组对象都拥有了该方法, 搞定!
这种方式能够解决我们的问题, 但是还是存在问题的:
在多人开发的环境中, 如果使用这种方式对内置对象做扩展, 可能会对其他开发人员造成影响
如果在原型对象上添加了过多的成员, 会降低对象成员的搜索效率.
安全的扩展内置对象
上面扩展内置对象的方法存在一定的问题, 问题的关键其实在于我们是直接在内置对象的原型上进行拓展的, 这样导致对其他使用该对象的开发人员造成影响.
所以, 我们的解决思路就是, 自定义一个对象, 让该对象继承需要扩展的内置对象, 然后只需要对自定的对象进行操作即可.
- function MyArray() {
- }// 让 MyArray 的原型指向 Array 对象 // 即继承 Array 中的所有成员
- MyArray.prototype= new Array();
- MyArray.prototype.getLength=function () {
- return this.length;
- }var arr1 = new MyArray();
- arr1.push("A","B","C","D","E");// 内置对象的初始方法 console.log(arr1.getLength());// 扩展之后的方法
接下来, 如果想要对数组做扩展, 我们只需要操作 MyArray 即可, 而不需要直接操作 Array, 如此, 就不会对其他使用 Array 的开发人员操作影响了. 看图理解:
原型链的结构图
每个实例对象都是由构造函数创建出来的
每一个构造函数都有默认关联的原型对象
原型对象本身也是对象, 所以它也有自己的构造函数
原型对象的构造函数也有默认关联的原型对象
以上就构成了一种链式访问结构, 称之为原型链
下面画出了 Person 对象和 Array 对象的原型链:
以上就是我对于原型和原型链的理解, 这也只是我自己的观点, 如果有不合适的还请大家指出. 如过有能帮助到你的地方我也会一一解答, 希望我们能够共同进步.
来源: http://www.bubuko.com/infodetail-3345135.html