理解JS原型和原型链
本文通过对《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原型和原型链的更多相关文章
- 理解js中的原型链
对象有”prototype”属性,函数对象有”prototype”属性,原型对象有”constructor”属性. 关于原型 在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承 ...
- 理解js中的原型,原型对象,原型链
目录 理解原型 理解原型对象 实例属性与原型属性的关系 更简单的原型语法 原型的动态性 原型链 理解原型 我们创建的每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象, ...
- 深入理解JS对象和原型链
函数在整个js中是最复杂也是最重要的知识 一个函数中存在多面性: 1.它本身就是一个普通的函数,执行的时候形成的私有作用域(闭包),形参赋值,预解释,代码执行,执行完 成后栈内存销毁/不销毁. 2.& ...
- 理解js中的原型链,prototype与__proto__的关系
说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: 1 <script type="text/javascript"> 2 var Pers ...
- 【转】理解js中的原型链,prototype与__proto__的关系
说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: 1 <script type="text/javascript"> 2 var Pers ...
- [转]理解js中的原型链,prototype与__proto__的关系
本文转自:http://rockyuse.iteye.com/blog/1426510 说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: 1 <script typ ...
- 理解js的prototype原型对象
我们创建的每一个函数都有一个prototype(原型)属性.这个属性是一个指针,指向一个对象,而这个对象的用途是包括能够由特定类型的全部实例共享的属性和方法.假设依照字面意思来理解,那么prototy ...
- 深入理解js——隐式原型
每个函数都有一个prototye(原型),而每个对象都有一个_proto_,可成为隐式原型. _proto_是一个隐藏的属性,javascript不希望开发者用到这个属性值,有的低版本浏览器甚至不支持 ...
- 深入理解js——自由变量和作用域链
自由变量:在A作用域中使用变量X,却没有在A作用域中声明(在其他作用域中声明),对于A作用域来说X就是一个自由变量. var x=10; function fn(){ var b=20; consol ...
- JS基础-该如何理解原型、原型链?
JS的原型.原型链一直是比较难理解的内容,不少初学者甚至有一定经验的老鸟都不一定能完全说清楚,更多的"很可能"是一知半解,而这部分内容又是JS的核心内容,想要技术进阶的话肯定不能对 ...
随机推荐
- PHP中的排序函数sort、asort、rsort、krsort、ksort区别分析
sort() 函数用于对数组单元从低到高进行排序. rsort() 函数用于对数组单元从高到低进行排序. asort() 函数用于对数组单元从低到高进行排序并保持索引关系. arsort() 函数用于 ...
- 【转】Java中的static关键字解析
一.static关键字的用途 在<Java编程思想>P86页有这样一段话: “static方法就是没有this的方法.在static方法内部不能调用非静态方法,反过来是可以的.而且可以在没 ...
- C++设计模式——观察者模式
观察者模式 在GOF的<设计模式:可复用面向对象软件的基础>一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动 ...
- 【原创】大叔问题定位分享(10)提交spark任务偶尔报错 org.apache.spark.SparkException: A master URL must be set in your configuration
spark 2.1.1 一 问题重现 问题代码示例 object MethodPositionTest { val sparkConf = new SparkConf().setAppName(&qu ...
- ES6新语法
ES6新语法概览 简介 ES6是JavaScript语言的新一代标准,加入了一些新的功能和语法,正式发布于2015年6月,亦称ES2015:该标准由ECMA(欧洲计算机制造联合会)的第39号技术专家委 ...
- hibernate 保存报错 Hibernate operation: could not get next sequence value;
错误信息: [2017-09-28 18:51:38,854]-[org.hibernate.util.JDBCExceptionReporter:101] ERROR - Numeric Overf ...
- 多媒体开发(6):滤镜实现各种图片效果 | Video-Filters | avfilter | 变色
之前讲过使用FFmpeg的drawtext滤镜(把图片或文字加到视频上),而实际上,FFmpeg的滤镜很强大,远不止加字幕或加图片的功能.滤镜是很有趣的,可以把图片变模糊.变色.缩放旋转,等等. 本文 ...
- 为什么Dotnet Core的DI默认是在控制器中注入
转载请注明出处: https://www.cnblogs.com/zhiyong-ITNote/ DI的大概过程抽象成如下:接口对象 <-- 实现对象 <-- 抽象对象 在抽象对象中引入接 ...
- KaliLinux常用服务配置教程DHCP服务工作流程
KaliLinux常用服务配置教程DHCP服务工作流程 DHCP服务工作流程如图1.1所示. 具体的工作流程如下所示: (1)DHCP客户端以广播的方式发出DHCP Discover报文. (2)所有 ...
- 06-Python入门学习-元组、字典、集合类型
一.元组 一:基本使用:tuple 1 用途: 记录多个值,当多个值没有改的需求,此时用元组更合适 2 定义方式: 在()内用逗号分隔开多个任意类型的值 t=(1,1.3,'xx',('a','b') ...