深入理解:JavaScript原型与继承
深入理解:JavaScript原型与继承
看过不少书籍,不少文章,对于原型与继承的说明基本上让人不明觉厉,特别是对于习惯了面向对象编程的人来说更难理解,这里我就给大家说说我的理解。
首先JavaScript是一门基于原型编程的语言,它遵守原型编程的基本原则:
- 所有的数据都是对象(javascript中除了字符串字面量、数字字面量、true、false、null、undefined之外,其他值都是对象!)
- 要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它
- 对象会记住它的原型
- 如果对象无法响应某个请求,它会把该请求委托给它自己的原型
这么说来,JavaScript一定有一个根对象,所有的对象的最终原型都将是它,它就是Object.prototype
,Object.prototype
也是一个对象,它是一个空的对象。(记住一点:所有的原型都是对象,但不是函数,虽然函数也是对象,Object对象其实就是一个函数)
以下代码创建空对象:
var obj1 = new Object();
var obj2 = {};
Object.getPrototypeOf(obj1) === Object.prototype; //true
Object.getPrototypeOf(obj2) === Object.prototype; //true
我们再来看下以下代码:
function Book(name){
this.name = name;
}
Book.prototype.getName = function(){
return this.name;
}
Book.num = 5;
var book1 = new Book('javascript权威指南');
book1.getName(); //javascript权威指南
Object.getPrototypeOf(book1) === Book.prototype; //true
我们通常说,使用了new Book()来创建了Book的实例book1,但是JavaScript并没有类的概念,这里的Book本质上只是一个函数而已,如果用new则把它当着构造函数对待,那么var book1 = new Book('javascript权威指南')
是怎么个执行过程呢?在这之前,我们来先看下Function与Object的关系
这里有张图:
Function与Object的关系
console.log(Function); //[Function: Function]
console.log(Function.constructor); //[Function: Function]
console.log(Function.__proto__); //[Function]
console.log(Function.prototype); //[Function]
console.log(Function.constructor.prototype); //[Function]
console.log(Object.__proto__); //[Function]
console.log(Object.prototype); //{}
console.log(Object.constructor); //[Function: Function]
console.log(Object.constructor.prototype); //[Function]
在JavaScript中:Function和Object就像是女娲和伏羲,Object提供种子(Object.prototype),Function负责繁衍。Object是由Object.prototype提供的种子经过Function打造出来的。Object.prototype会被一直继承下去,并一代一代增强。
- 每一个函数都有一个原型对象(prototype)和隐藏的__proto__属性,函数的__proto__属性指向Function.prototype,而原型对象(prototype)是一个对象,符合以下第2点(也有构造函数constructor和隐藏的__proto__属性);
- 每一个非函数对象(实例对象)都有一个构造函数(constructor)和隐藏的__proto__属性,constructor自然指的是它的构造函数,而__proto__指向的是它的构造函数的原型对象prototype
- 通过__proto__属性,每个对象和函数都会记住它的原型,这样就形成了原型链;
console.log(Book); //{ [Function: Book] num: 5 }
console.log(Book.__proto__); //[Function]
console.log(Book.prototype.__proto__); //{} 等于Object.prototype
console.log(Book.prototype); //Book { getName: [Function] }
console.log(Book.constructor); //[Function: Function]
console.log(Book.prototype.constructor); //{ [Function: Book] num: 5 }
console.log(Book.constructor.prototype); //[Function]
console.log(Book.__proto__.__proto__); //{} 等于Object.prototype
每一个函数都是通过Function构造出来的,函数的原型属性__proto__指向Function.prototype,而函数的原型对象prototype是代表着自身的函数对象,它的__proto__属性指向Object.prototype,它的constructor属性默认指向它自己构造函数(也可改为别的函数,如:Book.prototype.constructor = Person;)。
console.log(book1); //Book { name: 'javascript权威指南' }
console.log(book1.__proto__); //Book { getName: [Function] }
console.log(book1.prototype); //undefined
console.log(book1.constructor); //{ [Function: Book] num: 5 }
console.log(book1.constructor.prototype); //Book { getName: [Function] }
所以,我们通常说‘一个对象的原型’其实是不准确的,应该是‘一个对象的构造器的原型’,且对象是把它无法响应的请求委托给它的构造器的原型顺着原型链往上传递的。
现在来讲解一下var book1 = new Book('javascript权威指南')
的执行过程,是这样:new先从Object.prototype克隆一个空对象,先将空对象的构造函数指定为Book,然后将空对象的__proto__指向它的构造函数的原型Book.prototype,之后通过Book构造函数对这个空对象进行赋值操作,并将这个对象返回给变量book1。
我们再看如下代码:
var obj = {name: 'Sufu'};
var Person = function(){};
Person.prototype = obj;
var a = new Person();
console.log(a.name); //Sufu
这段是这样执行的:
- 首先尝试查找对象a的name属性,找不到,执行第2步
- 将查找name属性的这个请求委托给a的构造器的原型,a.__proto__记录的是Person.prototype,Person.prototype为对象obj
- 在对象obj中查找name,找到并返回它的值给a,假如还找不到,它就通过obj.__proto__找到Object.prototype,找不到就返回undefined,因为Object.prototype的原型不存在了,为null
好了,就介绍到这里了,以上是个人的理解,有不对的地方欢迎指出!
参考文献:《javascript权威指南》
深入理解:JavaScript原型与继承的更多相关文章
- 【前端知识体系-JS相关】深入理解JavaScript原型(继承)和原型链
1. Javascript继承 1.1 原型链继承 function Parent() { this.name = 'zhangsan'; this.children = ['A', 'B', 'C' ...
- 深入理解javascript原型和闭包(6)——继承
为何用“继承”为标题,而不用“原型链”? 原型链如果解释清楚了很容易理解,不会与常用的java/C#产生混淆.而“继承”确实常用面向对象语言中最基本的概念,但是java中的继承与javascript中 ...
- 彻底理解Javascript原型继承
彻底理解Javascript原型继承 之前写过一篇Javascript继承主题的文章,这篇文章作为一篇读书笔记,分析的不够深入. 本文试图进一步思考,争取彻底理解Javascript继承原理 实例成员 ...
- 深入理解javascript原型和闭包 (转)
该教程绕开了javascript的一些基本的语法知识,直接讲解javascript中最难理解的两个部分,也是和其他主流面向对象语言区别最大的两个部分--原型和闭包,当然,肯定少不了原型链和作用域链.帮 ...
- 深入理解javascript原型和闭包系列
从下面目录中可以看到,本系列有16篇文章,外加两篇后补的,一共18篇文章.写了半个月,从9月17号开始写的.每篇文章更新时,读者的反馈还是可以的,虽然不至于上头条,但是也算是中规中矩,有看的人,也有评 ...
- 深入理解javascript原型和闭包(5)——instanceof
又介绍一个老朋友——instanceof. 对于值类型,你可以通过typeof判断,string/number/boolean都很清楚,但是typeof在判断到引用类型的时候,返回值只有object/ ...
- 深入理解javascript原型和闭包(7)——原型的灵活性
在Java和C#中,你可以简单的理解class是一个模子,对象就是被这个模子压出来的一批一批月饼(中秋节刚过完).压个啥样,就得是个啥样,不能随便动,动一动就坏了. 而在javascript中,就没有 ...
- 深入理解javascript原型和闭包(完结)
原文链接:http://www.cnblogs.com/wangfupeng1988/p/3977924.html 说明: 该教程绕开了javascript的一些基本的语法知识,直接讲解javascr ...
- 深入理解javascript原型和闭包
目录: 深入理解javascript原型和闭包(1)——一切都是对象 深入理解javascript原型和闭包(2)——函数和对象的关系 深入理解javascript原型和闭包(3)——prototyp ...
随机推荐
- android中出现Error retrieving parent for item: No resource found that matches the Theme.AppCompat.Light
styles.xml中<style name="AppBaseTheme" parent="Theme.AppCompat.Light">提示如下错 ...
- Windows Azure Virtual Machine (1) IaaS用户手册
<Windows Azure Platform 系列文章目录> Azure IaaS用户手册 - Azure IaaS相关技术- Azure虚拟机成本分析- 创建Azure虚拟机- 使用 ...
- SQL Server代理(5/12):理解SQL代理错误日志
SQL Server代理是所有实时数据库的核心.代理有很多不明显的用法,因此系统的知识,对于开发人员还是DBA都是有用的.这系列文章会通俗介绍它的很多用法. 如我们在这个系列的前几篇文章所见,SQL ...
- win10系统下点击关机却自动重启的问题解决思路
第一步.进入win10系统后,我们点击开始菜单上鼠标右键,选择控制面板 第二步.找到电源选项,点击进去(如何没发现,点击右上角查看方式,更换为小图标) 第三步.点击选择关闭盖子的功能 第四 ...
- 使用Microsoft Fakes进行单元测试(2)
接上一篇使用Microsoft Fakes进行单元测试(1) 下面进行Shim的演示. 2.使用Shim替换静态方法 假设我们需要一个工具方法用来格式化当前时间为字符串,因为DateTime.Now一 ...
- 30天C#基础巩固------读写流(StreamWrite/StreamReader)
一:读写流的一些案例. --->关于StreamWrite 这里的一些常用的方法和我们之前的那个FileStream是一样的,参数很多都是一样的用法. Console.WriteLi ...
- C# 视频流操作
发送视频流 void SendVideoBuffer(object bufferIn) { try { TcpClient tcp = ); NetworkStream ns = tcp.GetStr ...
- Android流量控制——列表页面
1.最简单的模式: 设计: 1.将页码值传给服务器,让服务器返回对应的页码数据 2.数据缓存:只缓存第一页数据. 好处: 1.实现简单.无脑 坏处: 1.浪费流量,如果用户一直在等某个人发送消息的话. ...
- lua的string.gsub初使用
今天在学习lua,熟悉项目代码的过程中,发现string.gsub好高级,所以在此mark下. 以下是lua5.1的官方文档介绍. string.gsub (s, pattern, repl [, n ...
- iOS阶段学习第16天笔记(Category-NSSet-SEL-NSIndexSet 操作)
iOS学习(OC语言)知识点整理 一.NSSet.NSMutableSet集合的介绍 1)NSSet.NSMutableSet集合,元素是无序的,不能有重复的值. 2)用实例方法创建一个不可变集合对象 ...