一、原型与原型链的定义

  • 原型:为其他对象提供共享属性的对象

注:当构造器创建一个对象,为了解决对象的属性引用,该对象会隐式引用构造器的"prototype"属性。程序通过constructor.prototype可以直接引用到构造器的"prototype"属性。并且添加到对象原型里的属性,会通过继承与所有共享此原型的对象共享。

  • 原型链:每个由构造器创建的对象,都有一个隐式引用(叫做对象的原型)链接到构造器的"prototype"属性。再者,原型可能有一个非空隐式引用链接到它自己的原型,以此类推,这叫做 原型链

二、ES5中的Function与Object类型

理解Function与Object类型的之间的关系,对我们理解原型和原型链有很重要的帮助。

var fn = Function;
console.log("fn的原型:" + fn.prototype);
console.log("fn的原型链:" + fn.__proto__);
console.log("fn的原型等于fn的原型链:" + ( fn.prototype === fn.__proto__ ) );
console.log("fn的原型的原型链:" + fn.prototype.__proto__);
var obj = Object;
console.info("obj的原型:" + obj.prototype);
console.info("obj的原型链:" + obj.__proto__);
console.info("obj的原型不等于obj的原型链:" + (obj.prototype === obj.__proto__));
console.info("obj的原型的原型链:" + obj.prototype.__proto__);

输出结果如下:

fn的原型:function () {}
fn的原型链:function () {}
fn的原型等于fn的原型链:true
fn的原型的原型链:[object Object]
obj的原型:[object Object]
obj的原型链:function () {}
obj的原型不等于obj的原型链:false
obj的原型的原型链:null

根据输出结果我们不难看出,Function与Object存在相互引用的关系,以及其他特点总结如下:

  • Function.prototype.proto === Object.prototype:Function的原型的原型链等于Object的原型
  • Function.proto === Object.proto:Function与Object的原型链是相等的
  • Function.proto === Function.prototype:Function的原型等于Function的原型链,在ECMAScript5.1的规范中是如此说明的:Function的prototype是一个函数对象,他内部的[[prototype]]属性值是标准内置的Object的prototype对象
  • Object.prototype.proto === null:Object的原型的原型链为null

关系图:

  • Function的prototype的__proto__是引用的Object的prototype,这是Function的原型的原型链
  • 而Object的__proto__是引用了Function的prototype的。

2.1、其他原生类型

原生类型大致可以分两类,一类是继承于Function的,另一类是继承于Object。

  • 继承于Function类型:String、Number、Boolean、Array、Date、RegExp、Error等,他们的__proto__(原型链)都指向了Function,而他们的prototype是各自类型的标准内置对象,这也就证明他们的prototype是继承于Object的,所以prototype.__proto__指向Object的prototype。
  • 继承于Object类型:Math、JSON等。因为是对象,所以没有构造函数,也没有自己的内置原型对象(prototype属性)。但还是有原型链的,他的__proto__指向Object的prototype。

2.2、总结

  • Function是函数(类)的基础原型
  • Object是对象的基础原型
  • 运行时创建一个对象,会将构造器的prototype属性引用复制给对象的__proto__上,这里的创建一个对象,只能是new方式。
  • 用function关键字定义的类,做为Function类型的实例他本身有一个原型链(本身继承于Object),另外通过new创建的实例对象也有属于自己的原型链(prototype到__proto__的转换)。

三、实现继承(原型继承)

前面描述了Function、Object和其他原生类型的关系,在这里我们深入了解Function对象的类特性,这里我们使用function这个类,他是Function的实例,拥有Function类型的所有方法。

3.1、ES5.1

function Parent(){
this.name = 'parent';
}
Parent.prototype.getName = function(){
console.log(this.name);
} function Child(){
Parent.call(this); //在this对象上增加属性
this.cName = 'child';
}
Child.prototype = Parent.prototype; //复制parent的prototype所有的内容,包含构造器
Child.prototype.constructor = Child; //恢复构造器为子类,不恢复也不影响其new var _child = new Child();

实现继承的步骤:

  • Parent的prototype赋值给Child的prototype,使其Child拥有Parent的原型方法或属性(子类与父类的prototype进行合并)
  • 将Child.prototype.constructor指向Child函数,因为constructor是指向其构造器的方法,被Parent赋值后,其实是指向了Parent的构造器,所以需要改回来。
  • 在Child的构造器中用Call执行Parent的构造器,实例构造器的继承执行(顺序执行父类、子类的构造函数)。

总结:

  • 原型的继承实际上是共享原型上的属性和方法,所以更改基类原型上的属性和方法会影响到子类。但构造器中对this做的绑定则是实例独立的。
  • function关键字定义的类(Parent、Child)的__proto__都是指向function的构造函数
  • function关键字定义的类所有prototype的__proto__都是指向了Object的prototype。

3.2、ES2015(ES6)

在es6中实现继承就相当的简单了,不需要像es5中那么步骤来实现,继承实现如下:

class Parent {
constructor(){
this.name = 'parent';
}
getName(){
console.log(this.name);
}
}
class Child extends Parent {
constructor(){
super();
this.cName = 'child';
}
} var _child = new Child();
  • Class的__proto__指向父类的定义,包含构造函数。
  • Class的prototype.__proto__是指向父类的prototype,表示方法的继承。

四、产生的改变

  • ES5中用Function实现面向对象,而ES6提供了Class。
  • ES6的Class对原型与原型链更加规范化。
  • ES6提供了操作__proto__对象的方法,分别如下:
    • Object.setPrototypeOf(obj,protype):设置对象的__proto__(原型对象
    • Object.getPrototypeOf(obj):读取对象的__proto__(原型对象)
  • ES5中可以直接对__proto__赋值,但不建议这样使用。
  • ES5中对子类的prototype进行赋值后,还需要重定向prototype.constructor到子类的构造函数。

[我的理解]Javascript的原型与原型链的更多相关文章

  1. 深入理解Javascript中构造函数和原型对象的区别

    在 Javascript中prototype属性的详解 这篇文章中,详细介绍了构造函数的缺点以及原型(prototype),原型链(prototype chain),构造函数(constructor) ...

  2. 【JavaScript】深入理解JavaScript之强大的原型和原型链

    由于JavaScript是唯一一个被广泛使用的基于原型继承的语言,所以理解两种继承模式的差异是需要一定时间的,今天我们就来了解一下原型和原型链. AD: hasOwnProperty函数: hasOw ...

  3. 深入理解Javascript中构造函数和原型对象的区别(转存)

    Object是构造函数,而Object.prototype是构造函数的原型对象.构造函数自身的属性和方法无法被共享,而原型对象的属性和方法可以被所有实例对象所共享. 首先,我们知道,构造函数是生成对象 ...

  4. 理解Javascript的动态语言特性

    原文:理解Javascript的动态语言特性 理解Javascript的动态语言特性 Javascript是一种解释性语言,而并非编译性,它不能编译成二进制文件. 理解动态执行与闭包的概念 动态执行: ...

  5. 深入理解javascript原型和闭包 (转)

    该教程绕开了javascript的一些基本的语法知识,直接讲解javascript中最难理解的两个部分,也是和其他主流面向对象语言区别最大的两个部分--原型和闭包,当然,肯定少不了原型链和作用域链.帮 ...

  6. 深入理解javascript原型和闭包系列

    从下面目录中可以看到,本系列有16篇文章,外加两篇后补的,一共18篇文章.写了半个月,从9月17号开始写的.每篇文章更新时,读者的反馈还是可以的,虽然不至于上头条,但是也算是中规中矩,有看的人,也有评 ...

  7. 深入理解javascript原型和闭包(1)——一切都是对象

    “一切都是对象”这句话的重点在于如何去理解“对象”这个概念. ——当然,也不是所有的都是对象,值类型就不是对象. 首先咱们还是先看看javascript中一个常用的函数——typeof().typeo ...

  8. 深入理解javascript原型和闭包(2)——函数和对象的关系

    上文(理解javascript原型和作用域系列(1)——一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; co ...

  9. 深入理解javascript原型和闭包(3)——prototype原型

    既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的新朋友,我估计您也是javascript的新朋友. 在咱们的第一节(深入理解 ...

  10. 深入理解javascript原型和闭包(4)——隐式原型

    注意:本文不是javascript基础教程,如果你没有接触过原型的基本知识,应该先去了解一下,推荐看<javascript高级程序设计(第三版)>第6章:面向对象的程序设计. 上节已经提到 ...

随机推荐

  1. Oracle:select into 查询没有记录的解决办法

    在数据库编程中,select into 语句可以将数据库的某些值赋值给程序的变量,使用起来非常方便.但很多时候也会遇到查询出来没有记录的情况,这时程序会出错. 可以使用 exception when ...

  2. 代码对齐--string|stream

    https://vjudge.net/contest/185301#problem/A 学习了好多新函数,只要关注每个单词的列宽就行了.自动切分太厉害了吧~ #include<iomanip&g ...

  3. Linux-day1-pdf课件

    1.掌握Linux目录结构  2.掌握基础文件操作指令 3.vim常用操作命令 4.Linux用户和组

  4. 【转】腾讯云-解决Winscp permission denied的问题

    刚刚注册完腾讯云,因为要用来跑作业代码,所以操作系统选择的Ubuntu 16.04 32位 用Winscp登陆之后出现了错误代码为3的permission denied的错误,不能创建路径,也不能上传 ...

  5. CSS空心圆

    CSS代码:改变border的大小控制空心的大小 div { width: 100px; height: 100px; background: #ffffff; border-radius: 50%; ...

  6. go语言数据库操作,xorm框架

    待续............................................... 连接数据库 db, err := xorm.NewEngine("mysql", ...

  7. 使用Jacksum对文件夹和文件生成checksum

    Jacksum 是一个java开源工具, 用来 给单个文件生成checksum, 也可以给整个文件中所有文件生成checksum,生产的checksum 可以是MD系列,也可sha. 你可以参考​ 官 ...

  8. 发布版本Debug和Release的区别

    1.Debug是调试版本不会对项目发布的内容进行优化,并且包含调试信息容量会大很多 2.Release不对源代码进行调试,对应用程序的速度进行优化,使得发布的内容容量等都是最优的

  9. lodash 实现一些常见的功能

    排序 const sorted = _.orderBy(filtered, [sortColumn.path], [sortColumn.order]); 数组切片 普通的 slice 可传递两个参数 ...

  10. AWS MVC 详解

    由于新工作是在AWS PaaS平台上进行开发,为不耽误工作,先整理一下AWS MVS的使用规范,快速上手.对AWS PaaS平台的相关介绍留到以后再来补充.本文几乎是对官方学习文档的整理,有遗漏的后补 ...