javascript的原型和继承(1)
原型与继承是javascript中基础,重要而相对比较晦涩难解的内容。在图灵的网上看到一篇翻译过的文章,有参考了一些知名博客。我自己总结了几篇。通过这次的总结,感觉自己对原型和继承的认识又增加了很多,究其原因,主要这次,是从语言设计者的角度,理解了当初的原型和继承为什么这么设计,
转换角度后,理解起来就简单多了。
先从历史介绍一下,看起来啰嗦,其实还挺有必要的。
1994年,网景公司(Netscape)发布了Navigator浏览器0.9版。是历史上第一个比较成熟的网络浏览器,轰动一时。但是,这个版本的浏览器只能用来浏览,不具备与访问者互动的能力。比如,如果网页上有一栏"用户名"要求填写,浏览器就无法判断访问者是否真的填写了,只有让服务器端判断。如果没有填写,服务器端就返回错误,要求用户重新填写,这太浪费时间和服务器资源了。
网景公司急需一种网页脚本语言,使得浏览器可以与网页互动。工程师brendan Eich负责开发这种新语言。他觉得,没必要设计的很复杂,这种语言只要能够完成一些简单的操作就够了,比如,判断用户有没有填写表单。
1994年正式面向对象编程最兴盛的时期。C++是当时最流行的语言。而java语言也即将推出。Brendan无疑受到了影响,Javascript里面所有的数据类型都是对象(Object)。这一点和java很相似。随即他就遇到了一个难题。到底要不要设计“继承”机制呢?
如果真的是简易的语言,是不需要有继承机制的。但因为javascript里面都是对象,为了将所有的对象联系起来,Brendan最后还是设计了继承。
但他并没有打算引入“类”的概念,引入类,Javascript就变成彻底的面向对象了。这好像太正式了,而且增加了初学者的难度。综合了c++和java,他也把new命令引入了javascript,用来从原型对象生成一个实例对象。
下一个问题,Javascript没有“类”,怎么来表示原型对象呢?
他想到,C++和java是用new命令时,都会调用“类”的构造函数(Constructor)。他就做了一个简化的设计,在javascript语言中,New命令后面跟的不是类,而是一个构造函数。
-----------------看到这里,是不是有一种一步步接近真相的感觉呢?
举例来说,现在有一个叫做dog的构造函数,表示狗对象的原型。
function Dog(name){
this.name = name;
}
对这个构造函数使用new,就会生成一个狗对象的实例。
var dogA = new Dog(“金毛”);
alert(dogA.name); //金毛
new运算符的缺点
用构造函数生成实例对象,有一个缺点。那就是无法共享属性和方法。
原博客这里介绍的不够仔细,我这边再着重说一下:
function DOG(name){
this.name = name;
this.dinner = ["meat","water"]; //看这里看这里
}
var dogA = new DOG(“大毛”); var dogB = new DOG(“二毛”); alert(dogA.dinner); //[“meat”,”water”] alert(dogB.dinner); //[“meat”,”water”]
看起来好像是他们共享了dinner这个属性,其实则不然,实例继承的属性都是互相独立的。
console.log(dogA.dinner == dogB.dinner); //false
看见了没,这也意味着,在创建实例的时候其实是这样的一个过程;
dogA.dinner = new Array(“meat”,”water”);
dogB.dinner = new Array(“meat”,”water”);
每一个实例都有自己的属性和方法的副本。这样的话,无法做到数据共享,肯定是极大的资源浪费。
prototype属性的引入
考虑到这一点,Brendan决定为构造函数设置一个prototype属性。这个属性包含一个对象,我个人的理解,这个属性就是一个对象。里面包含有所有实例可以共享的属性和方法。而那些不需要共享的属性方法,则放在构造函数里。
function DOG(name){
this.name = name;
}
DOG.prototype.dinner = [“meat”,”water”];
var dogA = new DOG(“大毛”);
var dogB = new DOG(“二毛”);
console.log(dogA.dinner); // [“meat”,”water”]
console.log(dogB.dinner); //[“meat”,”water”]
console.log(dogA.dinner == dogB.dinner); //true;
实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性方法分成两种,一种是本地的,一种是引用的,其实也就是继承的。由于所有的实例对象共享同一个prototype对象,那么从外界看起来。prototype对象好像就是实例对象的原型。而实例对象,也就继承了prototype对象。
Constructor属性的引入
构造函数和prototype对象之间也需要一个联系的桥梁。这个对象就是constructor。因此,prototype对象的constructor属性,指向prototype所属的构造函数。(听着好像有点别扭,其实也很好理解。)因为prototype对象中所有的属性和方法都可以由实例来共享。因此,实例的constructor属性也指向了实例对应的构造函数。这里真想感慨,看起来那么简单,又是多么神奇的prototype和constructor。
当然prototype属性也并非完美,下一节的时候会提到prototype的缺点以及解决方案。
prototype的缺点
所有的实例在默认的情况下共享属性和方法。这对共享函数非常合适。但是,对于包含引用类型的值来说,问题就比较突出了。
function DOG(name){ this.name = name; } DOG.prototype.dinner = [“meat”,”water”]; var dogA = new DOG(“大毛”); var dogB = new DOG(“二毛”); console.log(dogA.dinner); // [“meat”,”water”] console.log(dogB.dinner); //[“meat”,”water”] console.log(dogA.dinner == dogB.dinner); //true; dogA.dinner.push(“milk”); console.log(dogB.dinner); //[“meat”,”water”,”milk”]
因此,最常见的模式就是将构造函数模式和原型模式进行结合使用。实例的属性放在构造函数中。共享的属性和方法放在原型对象中。(应该还有其他的方法,先不扩展这里。)
javascript的原型和继承(1)的更多相关文章
- 【面试必备】javascript的原型和继承
原型.闭包.作用域等知识可以说是js中面试必考的东西,通过你理解的深度也就能衡量出你基本功是否扎实.今天来复习一下javascript的原型和继承,虽说是老生常谈的话题,但对于这些知识,自己亲手写一遍 ...
- 深入浅出JavaScript之原型链&继承
Javascript语言的继承机制,它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instanc ...
- JavaScript的原型链继承__propt__、prototype、constructor的理解、以及他们之间相互的关系。
回想自己已经工作了有一段时间了,但是自己对JavaScript的原型链.和继承的理解能力没有到位,最近他们彻底的整理并且复习了一遍. 本案例中部分文案来自网络和书籍,如有侵权请联系我,我只是把我的理解 ...
- JavaScript 面向对象 原型(prototype) 继承
1.对象的概念:无需属性的集合,属性可以为数值,对象或函数,ECMAscript中没有类的概念,这点是javascript与其他面向对象(OO)语言不同的地方. //创建一个自定义对象 var per ...
- JavaScript基于原型的继承
在一个纯粹的原型模式中,我们会摒弃类,转而专注于对象,基于原型的继承相比基于类的继承的概念上更为简单 if( typeof Object.beget !== 'function') { Object. ...
- javascript的原型与继承(2)
这是上一篇的后续. Javascript是一种基于对象的语言,遇到的所有东西几乎都是对象.如果我们想要把属性和方法封装成一个对象,应该怎么做呢: 假设我们把猫看成一个对象: var Cat = { n ...
- javascript高级:原型与继承
原型继承的本质就是一条原型链,对象会沿着这条链,访问链里的方法属性. 对象的__proto__属性就是用于访问它的原型链的上一层: 考虑以下对象: 1. 所有对象的原型: Object.prototy ...
- 🍓JavaScript 对象原型链继承的弊端 🍓
- javascript中继承(一)-----原型链继承的个人理解
[寒暄]好久没有更新博客了,说来话长,因为我下定决心要从一个后台程序员转为Front End,其间走过了一段漫长而艰辛的时光,今天跟大家分享下自己对javascript中原型链继承的理解. 总的说来, ...
随机推荐
- ServletContextListener使用详解
在 Servlet API 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期. 当Serv ...
- starUML 建模
1. starUML 序列图建模 参考: [1]. starUML 序列图建模. http://blog.csdn.net/u013474104/article/details/43818691
- dedecms代码研究四
partview php文件之前,我们像掉进沼泽一样,看到无尽的变量,数组元素,莫名其面的东西摆在我们面前.今天,我们继续艰难前行,想办法走出partview类的泥潭.上一篇,我们胡乱分析了partv ...
- 前端开发框架Bootstrap和KnockoutJS
江湖中那场异常惨烈的厮杀,如今都快被人遗忘了.当年,所有的武林同道为了同一个敌人都拼尽了全力,为数不多的幸存者心灰意冷,隐姓埋名,远赴他乡,他们将唯一的希望寄托给时间.少年子弟江湖老,红颜少女的鬓边也 ...
- python函数,lambda表达式,三目运算,列表解析,递归
一.自定义函数 定义函数时,函数体不执行:只有在调用函数时,函数体才执行.函数的结构: 1. def 2. 函数名 3. 函数体 def func_name(): 函数体 4. 返回值 如果没有声明返 ...
- 怎么去除google的 安全搜索
想要避开安全搜索 更改右上角的搜索设置,将搜索语言改为英文,然后保存搜索设置 第二次进入搜索设置里找Filter explicit results前的面的勾去掉即可.
- 29、shiro框架入门
1.建立测试shiro框架的项目,首先建立的项目结构如下图所示 ini文件 中的内容如下图所示 pom.xml文件中的内容如下所示 <project xmlns="http://mav ...
- {POJ}{树状数组}
总结一下树状数组的题目: {POJ}{3928}{Ping Pong} 非常好的题目,要求寻找一个数组中满足A[i]<A[k]<A[j]的个数,其中i<k<j(或者相反).很巧 ...
- Linux_09------Linux上系统扫描和安全策略
先谢慕课网/** * linux系统扫描技术 * * 主机扫描.路由扫描.批量服务扫描.系统安全策略(防SYN和ddos攻击) */ /** * 主机扫描 * ping fping hping * * ...
- codeforces731C Socks
C. Socks time limit per test 2 seconds memory limit per test 256 megabytes input standard input outp ...