前两次总结了JavaScript中的基本数据类型(值类型<引用类型>,引用类型<复杂值>)以及他们在内存中的存储,对内存空间有了一个简单的了解,以及第二次总结了this深入浅出的用法,我们知道了this的用法取决于函数四种调用的方式。

这一次我们来对JavaScript中原型以及原型链做一个深入浅出的理解。

JavaScript深入浅出系列

1)复杂值vs原始值&&内存空间 - JavaScript深入浅出(一)

2)this的用法 – JavaScript深入浅出(二)

待续......关于原型的话题都会变得严肃。

实际上,原型只是一个被称为"原型"的空对象属性,它是由JavaScript在后台创建(当然我们知道了它的原理,可以手动完成这项工作);

当你创建一个函数时,这个函数都会有一个prototype属性(不管你是不把它当做一个构造函数使用)。

βヾ(,,・∇・,,川←那么我们具体来看一下吧!!!

原型链概要

prototype属性是JavaScript为每个Function实例创建的一个对象。

具体的说:"它将通过new关键字创建的<对象实例>链接回创建它们的<构造函数>" 。就这样,我们可以共享或继承通用的方法和属性。当我们在属性查找时,就会不自觉的开启了我们的原型链之旅

让我们通过一个简单的例子开启我们的原型链查询之旅:我们使用Array构造函数创建一个数组,然后调用join方法

我想上面的例子对于js入门者是非常简单的,那么但是我们再来仔细了解一下,你发现join方法并没有定义为myArray对象实例的属性,但是我们创建的数组却可以访问join()方法,就好像我们本来就可以访问似的。

join()是在哪个地方定义的呢?

事实上,我们经常使用的join(),slice(),push()...等这些内建的方法,都被定义为了Array()构造函数的prototype属性的属性。由于在我们创建的myArray数组中没有找到join(),因此JavaScript会在原型链中查找join()方法

其实这样做我们很容易就联想到了效率和重用,通过把该属性添加到原型中去,我们所有的数组都有充分利用了相同的join()函数,而不需要为每一个数组实例都创建函数的新实例。

原型在所有的function()实例上都是标准的

我们知道创建函数两种方法

1、调用Function构造函数法:

2、使用字面量法:

其实,即使不直接使用Function构造函数,而是使用字面量表示法,所有的函数也都是由Function()构造函数创建的

我们用字面量方法创建了一个函数,发现它的prototype和Function()构造函数一样,都指向了object(),这也就证实了我们上所说的.

默认的prototype属性是object()对象

上面我已经谈到,实际上,原型只是一个被称为'原型'的空对象属性,它在JavaScript的后台已经创建,并且通过Function()构造函数来使用。

我们可以手动完成这项在后面完成的工作,以便了解它的机制。

上面的代码非常简单,实际上也非常好用,它实质上复制了JavaScript在后面已经完成的工作。

将构造函数创建的实例链接至构造函数的prototype属性

将构造函数所创建的实例链接至构造函数的prototype属性,让我们开始这条神秘的_proto_链接

上面我们所原型只是一个对象,但是它是特殊的,因为原型链将每个实例都链接至其构造函数的prototype属性。

创建的对象实例创建对象的构造函数的prototype属性

当然,我们除了使用_proto_链接,还可以使用构造函数属性:

事实上,_proto_  ===  constructor.prototype

这样我们就不难理解,下面可以达到同样的效果:

上面的例子中我写到直接使用链也是可以的,下面会介绍它的查询顺序。虽然我相信对于入门者都是使用的链查询,但是我们有必然要知道它背后的那些机制。

其实有只看不见的手,在帮助着我们的代码完成任务

原型链的最后是Object.prototype

那么就让我们来看一下它的原型链查询吧。

由于prototype属性是一个对象,因此原型链或查询的最后一站是Object.prototype。

我想上面的代码,对于我们来说是丝毫不费力气的,但就借这个简单的例子,最后一个简单的undefined结果,却经历了一段不为我们所见的原型链查询;

我们创建了一个myArray空数组,然后我们试图访问未定义的myArray属性时,并不会直接返回undefined,而是要经历一段原型链查询。

①在myArray对象中查找foo属性;

如果没有找到

②则在Array.prototype中查找该属性;

但它在哪里也没有定义,

③最后查找的地方就是Object.prototype

三个对象中都没有定义,最后才给我们了一个undefined的回馈。所以请好好对待你的undefined吧,因为它的出现一波三折,还真不容易啊。。哈哈

用新对象替换prototype属性会删除默认的构造函数属性

我们可以用一个新值来替换prototype属性的默认值,但是需要特别注意的是:这么做会删除在"预制"原型对象中找到的默认的constructor属性,除非我们手动指定一个 ;

  

所以当你想要替换JavaScript设置的默认的prototype属性(与一些js oop模式类似),应该重新连接引用该构造函数的构造函数属性

下面我们简单的改一下上面的代码,以便构造函数属性能够再次为适当的构造函数提供引用

继承原型属性的实例总是能够获得最新值

其实prototype是动态的继承原型的属性的实例总是能够获得最新值,

这一点比较简单,不管是使用原型对象还是自己的对象覆盖它,继承原型属性的实例总是能够获得新值。

但是我们需要注意下面的一点:

用新对象替换prototype属性不会更新以前的实例

当你想用一个新对象完全替换prototype属性时,觉得所有的实例都会被更新,那么就即将要走向一条寻错的道路,可能会得到意想不到的结果。

创建一个实例时,该实例将在实例化时绑定至"刚完成"的原型,提供一个新对象作为prototype属性不会更新已创建的实例和原型之间的连接

这里的重点是,一旦开始创建实例,就不应用一个新对象那个来替换对象的原型,这样将会导致实例有一个指向不同原型的链接

自定义构造函数实现原型继承

当我们在自定义构造函数时,同样可以实现原型继承:

上面我们写的例子,很好的利用原型链,来创建一个构造函数。如果我们不提供参数的话,构造函数则可以继承legs和arms属性。如果传入参数,就遮盖继承的属性

创建继承链

我们自定义的构造函数实现了原型继承,设计原型继承的目的是要在传统的面向对象编程语言中找到模仿继承模式的继承链。继承只是一个对象可以访问另一个对象的属性。

接下来我们来创建一个简单的继承链:

事实上,上述代码我做的仅仅是利用一个已有的原生对象。

Person()和prototype属性的默认的object()值没有什么不同,这也正是一个prototype属性包含默认空object()值所发生的事情,查找用于创建对象的构造函数的原型(即object.prototype),以便查找所继承的属性。

::我们为什么要关注prototype属性呢?

(希望下面可以给<JavaScript入门者>一个了解prototype的理由)

你可能不喜欢原型继承,而是更多的喜欢采用另一种模式的对象继承。但是:

①原生构造函数(如Ocject(),Array(),Function()...)都使用了prototype属性,以便让你的实例可以继承属性和方法。

②如果想要更好的理解JavaScript,我们需要了解JavaScript本身是如何使用prototype对象的

③当你自定义一个构造函数时,可以像JavaScript原生对象那样使用继承,就必须要知道他是如何工作的

④通过使用原型继承,我们可以创建有效的对象实例。因为并非所有的数组对象都需要他们自己的join()方法<我想这就需要我们做些工作了>,但所有的实例都可以利用相同的join()方法,这就提高了效率和重用性。

写在后面

到这里我们的函数原型属性的深入浅出系列已经介绍完毕了,这篇博文希望可以帮助初学者--记住原型链层次结构的工作原理、对于易混淆的原型继承属性有一个分类,解决初学者心中的原型困惑

喜欢的话,关注一下吧,前辈们的关注和支持就是给我最大的动力

原型那些事 - JavaScript深入浅出(三)的更多相关文章

  1. 函数原型属性-JavaScript深入浅出(三)

    前两次总结了JavaScript中的基本数据类型(值类型<引用类型>,引用类型<复杂值>)以及他们在内存中的存储,对内存空间有了一个简单的了解,以及第二次总结了this深入浅出 ...

  2. 前端笔记知识点整合之JavaScript(三)关于条件判断语句、循环语句那点事

      一.条件分支语句 条件分支语句,也叫作条件判断语句,就是根据某种条件执行某些语句,不执行某些语句. JS中有三种语法是可以表示条件分支的 1.1 if……else…… 条件分支的主力语法,这个主力 ...

  3. JavaScript 继承——三种继承方法及其优劣

    原文地址   本文内容 目的 继承的第一步--最简单的继承 私有变量/成员和原型 三种继承方式及其优劣 基本的原型继承 Yahoo JavaScript 模块模式 创建闭包的构造函数 三种方法的代码执 ...

  4. JavaScript深入浅出6-函数和作用域

    慕课网教程视频地址:Javascript深入浅出 函数的概念:定义一次可调用多次的javascript代码段 创建函数:声明 function fuc(){}  声明前置   表达式 var fuc= ...

  5. JavaScript深入浅出4-对象

    慕课网教程视频地址:Javascript深入浅出 对象的结构:包含一系列无序的属性,每个属性都有字符串key和对应的值 创建对象:对象字面量.new/原型链.Object.create 对象的属性操作 ...

  6. JavaScript深入浅出1-数据类型

    慕课网教程视频地址:Javascript深入浅出 javascript是弱数据类型语言,不需要显式的定义类型,一共有如下六种数据类型 原始类型:number string boolean null u ...

  7. JavaScript学习总结(四)——this、原型链、javascript面向对象

    一.this 在JavaScript中this表示:谁调用当前函数this就指向谁,不知道调用者时this指向window. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是 ...

  8. 面向对象的JavaScript --- 原型模式和基于原型继承的JavaScript对象系统

    面向对象的JavaScript --- 原型模式和基于原型继承的JavaScript对象系统 原型模式和基于原型继承的JavaScript对象系统 在 Brendan Eich 为 JavaScrip ...

  9. JavaScript深入浅出第5课:Chrome是如何成功的?

    摘要: Chrome改变世界. <JavaScript深入浅出>系列: JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼? JavaScript深入浅出第2课:函数是一 ...

随机推荐

  1. 基于FPGA的均值滤波算法实现

    我们为了实现动态图像的滤波算法,用串口发送图像数据到FPGA开发板,经FPGA进行图像处理算法后,动态显示到VGA显示屏上,前面我们把硬件平台已经搭建完成了,后面我们将利用这个硬件基础平台上来实现基于 ...

  2. 菜鸟之路Vue----一

    Vue api 学习笔记之 全局配置 1.Vue全局配置 Vue.config是一个对象,它包含了Vue的全局变量配置. #silent  用来取消 Vue 所有的日志与警告,其值值类型为布尔值(Bo ...

  3. (简单易懂)Java的快速失败(fail-fast)与安全失败,源码分析+详细讲解

    之前在程序中遇到快速失败的问题,在网上找解释时发现网上的问题总结都比较片面,故打算自己总结一个,也可以供以后参考. --宇的季节 首先什么是快速失败? 快速失败是为了提示程序员在多线程的情况下不要用线 ...

  4. c# 后台get post请求

    //get请求 public static TResult Get<TResult>(string host, string url) { var httpClient = new Htt ...

  5. Maven详解(七)------ 创建Web工程以及插件原理

    1.什么是 Maven 插件? 上一篇博客我们将了 Maven 的生命周期,我们知道 Maven 的核心是生命周期,生命周期指定了 Maven 命令执行的流程顺序.但是真正实现流程的工程是由插件来完成 ...

  6. 一篇文章读懂Java类加载器

    Java类加载器算是一个老生常谈的问题,大多Java工程师也都对其中的知识点倒背如流,最近在看源码的时候发现有一些细节的地方理解还是比较模糊,正好写一篇文章梳理一下. 关于Java类加载器的知识,网上 ...

  7. github如何添加ssh

    1.运行git Bash 输入如下命令: $ cd ~/.ssh $ ls 输入这2个命令 ,我们可以看到 id_rsa.pub 或 id_dsa.pub 这2个文件已经存在了,id_rsa 是私钥, ...

  8. 2017最新的Python教程分享

    Python在数据科学盛行的今天,其易于阅读和编写的特点,越来越受编程者追捧.在IEEE发布的2017年编程语言排行榜中,Python也高居首位.如果你有学Python的计划,快来看看小编分享的Pyt ...

  9. ORACLE SEQUENCE的简单介绍

    先假设有这么一个表: create table S_Depart ( DepartId INT not null, DepartName NVARCHAR2() not null, DepartOrd ...

  10. Net分布式系统之七:日志采集系统(1)

    日志对大型应用系统或者平台尤其重要,系统日志采集.分析是系统运维.维护及用户分析的基础. 一.系统日志分类 一般系统日志可分为三大类: 1.用户行为日志:通过采集系统用户使用系统过程中,一系列的操作日 ...