本文通过对《JavaScript高级程序设计》第六章的理解,加上自己的理解,重组了部分内容,形成下面的文字。

理解了原型这个概念,你的JS世界会清明很多。

为什么要为JS创造原型这个概念


在没有原型概念之前,我们可以通过创建各种形式的函数来模拟类,但总有这样那样的不足,比如下面的

function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName(){
alert(this.name);
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.sayName===person2.sayName; // true

其中的sayName()函数虽然可以被构造函数Person的多个实例共享,但无法被其他构造函数继承。

什么是原型


要想弄清楚原型链,需要先理解原型。

所谓原型,是其他OO语言中类和继承的JS自家解决方案。JS以引用类型数据特性为基础,通过为构造函数自动创建prototype对象属性,实现类和继承,这个自动创建的prototype就是原型,也叫原型对象。所以要想搞清楚原型这个概念,首先要掌握引用类型、类、继承这几个概念。JS不像其他编程语言,如Java,类、构造方法、方法等概念之间有明确的界限,它用于模仿类和继承的原型对象本质是引用类型数据(Object),同样的,构造方法和成员方法也是。原型是JS引入的一个概念,用于解决实现类和继承,接下来看看是原型这个概念如何引入的。

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype 属性所在函数的指针。就拿下面的例子来说,Person.prototype. constructor 指向Person。

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas"
var person2 = new Person();
person2.sayName(); //"Nicholas"
alert(person1.sayName == person2.sayName); //true

如上代码涉及构造函数(Person)、原型对象(Person.prototype)和实例对象等三个概念。创建了自定义的构造函数之后,其原型对象默认只会取得constructor 属性;至于其他方法,则都是从Object 继承而来的。当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262 第5 版中管这个指针叫[[Prototype]]。虽然在脚本中没有标准的方式访问[[Prototype]],但Firefox、Safari 和Chrome 在每个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本则是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。如下图:

什么是原型链


前面说,JS引入原型来更好的模仿类的功能,而原型链则用于实现继承。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。简单回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是所谓原型链的基本概念。

function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true

如上,SubType.prototype = new SuperType(),实现继承的本质是用被继承构造函数(类)的实例重写原型对象。所有引用类型默认都继承了Object,而这个继承也是通过原型链实现的。大家要记住,所有函数的默认原型都是Object 的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这也正是所有自定义类型都会继承toString()、valueOf()等默认方法的根本原因。下图为我们展示了该例子中完整的原型链:

理解JS原型和原型链的更多相关文章

  1. 理解js中的原型链

    对象有”prototype”属性,函数对象有”prototype”属性,原型对象有”constructor”属性. 关于原型 在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承 ...

  2. 理解js中的原型,原型对象,原型链

    目录 理解原型 理解原型对象 实例属性与原型属性的关系 更简单的原型语法 原型的动态性 原型链 理解原型 我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象, ...

  3. 深入理解JS对象和原型链

    函数在整个js中是最复杂也是最重要的知识 一个函数中存在多面性: 1.它本身就是一个普通的函数,执行的时候形成的私有作用域(闭包),形参赋值,预解释,代码执行,执行完 成后栈内存销毁/不销毁. 2.& ...

  4. 理解js中的原型链,prototype与__proto__的关系

    说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: 1 <script type="text/javascript"> 2 var Pers ...

  5. 【转】理解js中的原型链,prototype与__proto__的关系

    说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: 1 <script type="text/javascript"> 2 var Pers ...

  6. [转]理解js中的原型链,prototype与__proto__的关系

    本文转自:http://rockyuse.iteye.com/blog/1426510 说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: 1 <script typ ...

  7. 理解js的prototype原型对象

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

  8. 深入理解js——隐式原型

    每个函数都有一个prototye(原型),而每个对象都有一个_proto_,可成为隐式原型. _proto_是一个隐藏的属性,javascript不希望开发者用到这个属性值,有的低版本浏览器甚至不支持 ...

  9. 深入理解js——自由变量和作用域链

    自由变量:在A作用域中使用变量X,却没有在A作用域中声明(在其他作用域中声明),对于A作用域来说X就是一个自由变量. var x=10; function fn(){ var b=20; consol ...

  10. JS基础-该如何理解原型、原型链?

    JS的原型.原型链一直是比较难理解的内容,不少初学者甚至有一定经验的老鸟都不一定能完全说清楚,更多的"很可能"是一知半解,而这部分内容又是JS的核心内容,想要技术进阶的话肯定不能对 ...

随机推荐

  1. Android Studio项目Gradle内网配置

    由于内网无法连接到外部网络,在使用Gradle编译Android Studio项目时就会面临一些问题: 1.Gradle安装文件无法下载 2.Gradle Android插件无法下载 3.项目依赖文件 ...

  2. 20175226 2018-2019-2 《Java程序设计》第三周学习总结

    20175226 2018-2019-2 <Java程序设计>第三周学习总结 教材学习内容总结 编程语言的几个发展阶段 类面向机器语言(汇编语言).面向过程语言(C语言).面向对象语言(J ...

  3. JavaScript入门学习笔记(表单验证)

    表单验证: 在数据被送到服务器之前对HTML表单中的输入数据进行验证,避免服务器频繁验证信息造成用户体验差. (1)表单数据是否为空 (2)输入的信息格式是否正确 (3)输入数据的类型是否正确 必填( ...

  4. apache基础

    apache基于多域名的虚拟主机 NameVirtualHost *:80<VirtualHost *:80> DocumentRoot "/var/www/html/xk/sh ...

  5. [原创]FPGA JTAG工具设计(二)

    经过前期打样 基于FT2232H的JTAG &UART板级已经初步形成 在Viado环境和ISE(13.2+)环境可以使用 速度支持10MHz/15MHz/30MHz 在ISE iMpact下 ...

  6. matplotlib注解-【老鱼学matplotlib】

    本节讲述在图片中添加注解. 直接上代码: import numpy as np import pandas as pd import matplotlib.pyplot as plt # 生成x轴上的 ...

  7. day17.初识递归函数

    在一个函数调用这个函数本身就是递归函数 递归函数默认深度最大997 n = 0 def func(): global n n += 1 print('hello,world') print(n) fu ...

  8. 咸鱼入门到放弃3--tomcat

    Tomcat学习与使用 一. Tomcat安装及配置 二.项目部署(虚拟目录映射) Web应用开发好后,若想供外界访问,需要把web应用所在目录交给web服务器管理,这个过程称之为虚似目录的映射. 虚 ...

  9. 微信小程序--家庭记账本开发--02

    代码文件的了解 对于一个程序的开发,代码的了解的必须的,不同的后缀名文件有着不同的作用,通过学习,对于微信小程序开发中的文件有了自己的理解. 文件概述 一个微信小程序一般有有pages文件夹,util ...

  10. chattr和lsattr的基本用法

    lsattr filename  查看一个文件的属性 chattr filename  改变一个文件的属性 主要用途:实现文件的原有内容不允许改变,但可以增加新行,则需通过改变文件的属性来实现. ch ...