javascript必知必会之prototype
摘要
本系列博文主要谈一些在 javascript 使用中经常会混淆的高级应用,包括: prototype, closure, scope, this关键字. 对于一个需要提高自己javascript水平的程序员,这些都是必须要掌握的.
本节主要介绍prototype.
Contents
- 摘要
- 起由
- prototype
- 结论
- 参考资料
- 本文的rst源码
起由
最近在做一个项目,里面大量地使用 javascript 作为页面的动态生成脚本, 使用 json 与服务器进行通信. 在读之前遗留的代码时, 经常会弄不清楚, 作用域, this关键字在当前context下的指向等,于是便开始专门学习了 相关的知识,记录下来与大家分享.
下面的内容中会有一些代码,建议大家也去尝试修改和理解,这样更容易掌握. 点击 这儿 下载所涉及到的源码.
prototype
javascript 是一种 prototype based programming 的语言, 而与我们通常的 class based programming 有很大 的区别,我列举重要的几点如下:
- 函数是first class object, 也就是说函数与对象具有相同的语言地位
- 没有类,只有对象
- 函数也是一种对象,所谓的函数对象
- 对象是按 引用 来传递的
那么这种 prototype based programming 的语言如何实现继承呢(OO的一大基本要素), 这也便是 prototype 的由来.
看下面的代码片断:
function foo(a, b, c) { return a*b*c; } alert(foo.length); alert(typeof foo.constructor); alert(typeof foo.call); alert(typeof foo.apply); alert(typeof foo.prototype);
对于上面的代码,用浏览器运行后你会发现:
- length: 提供的是函数的参数个数
- prototype: 是一个object
- 其它三个都是function
而对于任何一个函数的声明,它都将会具有上面所述的5个property(方法或者属性).
下面我们主要看下prototype.
// prototype function Person(name, gender) { this.name = name; this.gender = gender; this.whoAreYou = function(){//这个也是所谓的closure, 内部函数可以访问外部函数的变量 var res = "I'm " + this.name + " and I'm a " + this.gender +"."; return res; }; } // 那么在由Person创建的对象便具有了下面的几个属性 Person.prototype.age = 24; Person.prototype.getAge = function(){ return this.age; }; flag = true; if (flag) { var fun = new Person("Tower", "male"); alert(fun.name); alert(fun.gender); alert(fun.whoAreYou()); alert(fun.getAge()); } Person.prototype.salary = 10000; Person.prototype.getSalary = function(){ return this.name + " can earn about " + this.salary + "RMB each month." ; }; // 下面就是最神奇的地方, 我们改变了Person的prototype,而这个改变是在创建fun之后 // 而这个改变使得fun也具有了相同的属性和方法 // 继承的意味即此 if (flag) { alert(fun.getSalary()); alert(fun.constructor.prototype.age);//而这个相当于你直接调用 Person.prototype.age alert(Person.prototype.age); }
从上面的示例中我们可以发现,对于prototype的方法或者属性,我们可以 动态地 增加, 而由其创建的 对象自动会 继承 相关的方法和属性.
另外,每个对象都有一个 constructor 属性,用于指向创建其的函数对象,如上例中的 fun.constructor 指向的 就是 Person.
那么一个疑问就自然产生了, 函数对象中自身声明的方法和属性与prototype声明的对象有什么差别?
有下面几个差别:
- 自身声明的方法和属性是 静态的, 也就是说你在声明后,试图再去增加新的方法或者修改已有的方法,并不会 对由其创建的对象产生影响, 也即 继承 失败
- 而prototype可以动态地增加新的方法或者修改已有的方法, 从而是 动态的 ,一旦 父函数对象 声明了相关 的prototype属性,由其创建的对象会 自动继承 这些prototype的属性.
继续上面的例子:
flag = true; // 函数内部声明的方法是静态的,无法传递的 Person.school = "ISCAS"; Person.whoAreYou = function(){ return "zhutao"; };//动态更改声明期的方法,并不会影响由其创建的对象的方法, 即所谓的 静态 if (flag) { alert(Person.school); alert(fun.school);//输出的是 "undefined" alert(Person.whoAreYou()); //输出 zhutao alert(fun.whoAreYou()); // I'm Tower and I'm a male. } Person.prototype.getSalary = function(){ return "I can earn 1000000 USD"; }; if (flag) { alert(fun.getSalary());//已经继承了改变, 即所谓的 动态 }
既然有函数对象本身的属性, 也有prototype的属性, 那么是由其创建的对象是如何搜索相应的属性的呢?
基本是按照下面的流程和顺序来进行.
- 先去搜索函数对象本身的属性,如果找到立即执行
- 如果1没有找到,则会去搜索prototype属性,有2种结果,找到则直接执行,否则继续搜索 父对象 的 父对象 的prototype, 直至找到,或者到达 prototype chain 的结尾(结尾会是Object对象)
上面也回答如果函数对象本身的属性与prototype属性相同(重名)时的解决方式, 函数本身的对象 优先 .
再看一个多重prototype链的例子:
// 多重prototype链的例子 function Employee(name) { this.name = ""; this.dept = "general"; this.gender = "unknown"; } function WorkerBee() { this.projects = []; this.hasCar = false; } WorkerBee.prototype = new Employee; // 第一层prototype链 function Engineer() { this.dept = "engineer"; //覆盖了 "父对象" this.language = "javascript"; } Engineer.prototype = new WorkerBee; // 第二层prototype链 var jay = new Engineer("Jay"); if (flag) { alert(jay.dept); //engineer, 找到的是自己的属性 alert(jay.hasCar); // false, 搜索到的是自己上一层的属性 alert(jay.gender); // unknown, 搜索到的是自己上二层的属性 }
上面这个示例的对象关系如下:
结论
javascript 的prototype给语言本身增加了很强的灵活性,但与 class based programming 相比整个思维逻辑还是有很大的不同,所以需要更多地思考和揣摩.
而 javascript是披着c语言外衣的函数式语言 的理解自然也需要更多地思考.
下一节我会继续讨论下 javascript 的另一个重要而且比较容易弄错的知识 closure.
欢迎大家留言讨论.
javascript必知必会之prototype相关推荐
- c2064 项不会计算为接受0个参数的函数_【JS必知必会】高阶函数详解与实战
本文涵盖 前言 高级函数概念 函数作为参数的高阶函数 map filter reduce sort详解与实战 函数作为返回值的高阶函数 isType函数与add求和函数 如何自己创建高阶函数 前言 一 ...
- 20道经典的AJAX面试题(必知必会)
1.什么是AJAX,为什么要使用Ajax(请谈一下你对Ajax的认识) 什么是ajax: AJAX是"Asynchronous JavaScript and XML"的缩写.他是指 ...
- 必知必会 | WebView 的一切都在这儿
必知必会 | WebView 的一切都在这儿 文章较长,且大部分说明包含在注释中,建议收藏后慢慢看~ 1 目录 相关API 1.1. 相关类介绍 1.2. WebView 1.3. WebSettin ...
- java面试必知必会
java面试必知必会 面向对象 成员变量成员方法 Integer相关 double 和 Double相关 多态,向上转型 hashcode.==.equals比较 java中子类继承父类时是否继承构造 ...
- JSON必知必会 学习笔记
JSON必知必会 读书笔记 术语 可移植性 平台和系统间传输信息的兼容性. JSON JavaScript Object Notation 对象表示法.这里主要是对象表示法,是一种数据交换格式,比XM ...
- 【计算机网络】网络基础必知必会
网络基础必知必会 网络协议的体系结构 OSI 参考模型:应用层.表示层.会话层.传输层.网络层.数据链路层.物理层 五层协议的体系结构:应用层.传输层.网络层.数据链路层.物理层 TCP / IP 体 ...
- Java架构师必知必会,带走不谢
可以说,Java是现阶段中国互联网公司中,覆盖度最广的研发语言,掌握了Java技术体系,不管在成熟的大公司,快速发展的公司,还是创业阶段的公司,都能有立足之地. 成为Java架构师,需要掌握哪些技能呢 ...
- MySQL必知必会教程:深入理解MySQL技术内幕
2019独角兽企业重金招聘Python工程师标准>>> MySQL必知必会教程:深入理解MySQL技术内幕 作为最流行的开源数据库软件之一,MySQL数据库软件已经是广为人知了.当前 ...
- mysql必知必会_《MySQL必知必会》学习小结
关于SQL,之前通过sqlzoo的题目,完成了入门,也仅仅是入门而已. 最近都在忙着投简历和找新的数据分析项目做(为了练python和面试的时候有的聊),所以SQL放了一段时间没练.目前的工作用不到, ...
- php7.2 开启mcy扩展,phper必知必会(二)
1.说说你对进程,线程以及协程的理解 进程:是系统进行资源分配和调度的基本单位,是基本操作系统结构的基础.进程是程序基本执行的实体.进程与进程之间是独立的,拥有完全独立的地址空间,进程的切换只发生在内 ...
最新文章
- tomcat启动后如何登录
- pythonsorted_[转].Python中sorted函数的用法
- Eschool校园网平台介绍
- vpython 贞测碰撞_python碰撞检测?
- 元宇宙对未来网络技术的挑战
- Ajax的简单使用方法
- 通过二进制方式_部署node节点_安装kubelet和kube-proxy---K8S_Google工作笔记0014
- “迷失自我”,请记住下面5个网站,让你受益终身
- 【转】Jmagick的使用例子
- HAOI2012高速公路bzoj2752 (线段树,数学)
- c语言printf输出格式
- “如何写好一篇学术论文?”这大概是最详实的一则攻略了!
- 2020经济学人电子版杂志分享资源
- 第十四周 项目1抽象基类
- python——matplotlib图形参数设置、大小、参考线
- 01.使用.svg格式图片生成app图标详细步骤和注意事项
- linux调度不执行,linux crond.d定时调度执行一段时间后不执行
- 游戏设计模式-原型模式
- AI常用框架和工具丨1. 科学计算库NumPy
- Linux权限不理解?看完这篇就够用了
热门文章
- 【OpenGL】十、OpenGL 绘制点 ( 初始化 OpenGL 矩阵 | 设置投影矩阵 | 设置模型视图矩阵 | 绘制点 | 清除缓冲区 | 设置当前颜色值 | 设置点大小 | 绘制点 )
- Win7无法远程桌面
- sqlserver ADO.net 查询数据库加锁,事务提交
- 进击的新版NavMesh系统:看我飞檐走壁
- 浅谈Socket编程
- 67. Add Binary
- 三层学习------实践篇
- Tomcat启动报错 Could not reserve enough space for object heap
- unity3d与eclipse协同工作环境
- python newbie——PE No.5