JS核心系列:原型对象

时间:2022-04-21 18:19:34

在JS中,每当创建一个函数对象f1 时,该对象中都会内置一些属性,其中包括prototype和proto, prototype即原型对象。

每一个构造函数都有一个与之相关联的对象,该对象称之为原型对象。
每个实例对象都能共享其原型对象上的属性和方法。
原型对象的作用主要用来实现属性的继承,让实例对象能共享原型对象的属性,减少内存分配。
所以,在上一节中,我们想在每个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
下图详细说明了各对象之间的关系:

JS核心系列:原型对象
面向对象中的核心概念
构造函数: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()方法,之后创建的所有的数组对象都拥有了该方法,搞定!
这种方式能够解决我们的问题,但是还是存在问题的:

  1. 在多人开发的环境中,如果使用这种方式对内置对象做扩展,可能会对其他开发人员造成影响
  2. 如果在原型对象上添加了过多的成员,会降低对象成员的搜索效率。
    安全的扩展内置对象
    上面扩展内置对象的方法存在一定的问题,问题的关键其实在于我们是直接在内置对象的原型上进行拓展的,这样导致对其他使用该对象的开发人员造成影响。
    所以,我们的解决思路就是,自定义一个对象,让该对象继承需要扩展的内置对象,然后只需要对自定的对象进行操作即可。
    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的开发人员操作影响了。看图理解:
    JS核心系列:原型对象
    原型链的结构图
    每个实例对象都是由构造函数创建出来的
    每一个构造函数都有默认关联的原型对象
    原型对象本身也是对象,所以它也有自己的构造函数
    原型对象的构造函数也有默认关联的原型对象
    以上就构成了一种链式访问结构,称之为原型链
    下面画出了Person对象和Array对象的原型链:

JS核心系列:原型对象
如果你仔细的读完本文,相信你对 JavaScript 中的原型,原型链会有新的认识。如果还想了解更多JS相关干货,记得持续关注我的更新!

JS核心系列:原型对象的更多相关文章

  1. JS核心系列:浅谈原型对象和原型链

    在Javascript中,万物皆对象,但对象也有区别,大致可以分为两类,即:普通对象(Object)和函数对象(Function). 一般而言,通过new Function产生的对象是函数对象,其他对 ...

  2. JS核心系列:浅谈 call apply 与 bind

    在JavaScript 中,call.apply 和 bind 是 Function 对象自带的三个方法,这三个方法的主要作用是改变函数中的 this 指向,从而可以达到`接花移木`的效果.本文将对这 ...

  3. JS核心系列:理解 new 的运行机制

    和其他高级语言一样 javascript 中也有 new 运算符,我们知道 new 运算符是用来实例化一个类,从而在内存中分配一个实例对象. 但在 javascript 中,万物皆对象,为什么还要通过 ...

  4. js之prototype 原型对象

    原型对象prototype可以这么理解,是该类的实例对象的模板,每个实例对象都是先复制一份该类的prototype,通过这个可以让类的实例拥有相同的功能   String.prototype.say= ...

  5. 浅谈JS中的原型对象和原型链

    我们知道原型是一个对象,其他对象可以用它实现属性继承,除了prototype,又有__proto__ 1. prototype和__proto__的区别 prototype是函数才有的属性      ...

  6. 理解js的prototype原型对象

    我们创建的每一个函数都有一个prototype(原型)属性.这个属性是一个指针,指向一个对象,而这个对象的用途是包括能够由特定类型的全部实例共享的属性和方法.假设依照字面意思来理解,那么prototy ...

  7. JS构造函数、原型对象、隐含参数this

    This 解析器再调用函数每次都会向函数内部传递一个隐含的参数this,this指向的是一个对象(函数执行的上下文对象) 1.以函数形式调用时,this永远是window. 2.以方法形式调用时,th ...

  8. js中的原型对象链

    由于原型对象也是一个对象,它也有自己的原型对象并继承对象中的属性,这就是原型对象链:对象继承其原型对象,而原型对象继承它的原型对象,以此类推. 我们创建的每一个函数都有一个prototype(原型)属 ...

  9. JS中的原型对象与构造器

    在Javascript中:原型对象是属于构造函数的,不属于实例:实例只能共享原型对象中的属性和方法(当然也可以有自己的属性和方法,或者覆盖原型中同名的属性和方法):构造器constructor属于原型 ...

随机推荐

  1. matplotlib 显示中文 与 latex冲突

    如果在使用中文之前包含了使用latex的语法: mpl.rcParams['text.usetex'] = True 将不能正确显示含有中文的图片. 附 显示中文的方法: from matplotli ...

  2. qt QMetaObject::connectSlotsByName()自动关联失效问题解决

    自己编写qt程序的时候,想使用qt on_objectName_signalName()命名规则自动关联信号和槽,老是发现失效.多方求解,答案事实上很简单就是没有理解objectName的含义. on ...

  3. JPA主键策略

    JPA 自带的主键策略有 4 种,在枚举 javax.persistence.GenerationType 中,分别是:TABLE.SEQUENCE.IDENTITY.AUTO. TABLE:通过表产 ...

  4. document.write()相关

    原文地址:http://www.cnblogs.com/dh616854836/articles/2140349.html document.write()脚本向窗口(不管是本窗口或其他窗口)写完内容 ...

  5. SpringSecurity权限表达式

    * 当我们想要使用多个权限表达式的时候,是不能直接级联调用的,也就是说,我们只能手写了. @Override protected void configure(HttpSecurity http) t ...

  6. hdpi对应分辨率

    ldpi  QVGA (240×320) mdpi  HVGA (320×480) hdpi  WVGA (480×800),FWVGA (480×854) xhdpi  720P(1280*720) ...

  7. .net视频教程代码之《提交注册内容》

    看我的视频之后感觉代码太多不好打或者容易打错的话可以来看我的这里的代码.我的视频地址是 https://www.bilibili.com/video/av12727717/ 类里面的代码: using ...

  8. 【Ray Tracing The Next Week 超详解】 光线追踪2-9

    我们来整理一下项目的代码 目录 ----include --hit --texture --material ----RTdef.hpp ----ray.hpp ----camera.hpp ---- ...

  9. css table第一列 宽度

    table{table-layout:fixed;}table tr td:first-child,table tr td:first-child{width:120px;} 首行第一个td定宽同列的 ...

  10. oracle简单存储过程以及如何查看编译错误

    oracle简单存储过程以及如何查看编译错误; CREATE OR REPLACE PROCEDURE procedure_test ISval VARCHAR2(200);BEGIN /* val ...