JavaScript 对象、函数和继承


Posted in Javascript onJuly 07, 2009

1、 Javascript中的对象

JavaScript可以说是一个基于对象的编程语言,为什么说是基于对象而不是面向对象,因为JavaScript自身只实现了封装,而没有实现继承和多态。既然他是基于对象的,那么我们就来说说js中的对象。有人说js中所有的都是对象,这句话不完全正确。正确的一方是他强调了对象在js中的重要性,对象在js中无处不在,包括可以构造对象的函数本身也是对象。但是另一方面,js中也有一些简单的数据类型,包括数字、字符串和布尔值、null值和undefined值,而这些不是对象。那为什么这些类型的值不是对象呢,毕竟他们也有方法。那让我们来看一下,JavaScript中对于对象的定义,有两种定义。

(1)JavaScript中的对象是可变的键控集合(keyed collections) (此定义来自老道的那本书的第三章)

(2)JavaScript中的对象是无序(unordered)的属性集合,这些属性可以含有简单的数据类型、对象、函数;保存在一个对象属性中的函数也被称为这个对象的方法。 (来自ECMA-262 的4.3.3)(注:这里所说的属性是可以在js脚本中创建和访问的(我们称之为显性属性),不包括系统为对象自动分配的内部属性)

那为什么那个简单的数据类型不是对象呢,主要是因为这些数据类型的值中拥有的方法是不可变的,而一个对象的属性是应当可以被改变的。

2、 对象中的原型链[[proto]]

JavaScript中的每个对象创建的时候系统都会自动为其分配一个原型属性[[proto]],用来连接到他的原型对象。在JavaScript中就是通过每个对象中的[[proto]]来实现对象的继承关系的。但是对象的[[proto]]属性在JavaScript是不能访问和修改的,他是作为一个内部的属性存在的,而且是在对象被创建的同时由系统自动设定的。

当访问一个对象的某一属性,如果这个属性在此对象中不存在,就在他的[[proto]]所指的原型对象的属性中寻找,如果找到则返回,否则继续沿着[[proto]]链一直找下去,直到[[proto]]的连接为null的时候停止。

3、 函数也是对象

JavaScript中的函数本身就是一个对象(所以我们经常称之为函数对象),而且可以说他是js中最重要的对象。之所以称之为最重要的对象,一方面他可以扮演像其他语言中的函数同样的角色,可以被调用,可以被传入参数;另一方面他还被作为对象的构造器(constructor)来使用,可以结合new操作符来创建对象。

既然函数就是对象,所以必然含有对象拥有的全部性质,包括对象在创建时设定的原型链[[proto]]属性。

让我们来看看函数对象和普通对象有什么区别。我们前面说过,对象就是无序的属性集合,那么函数的属性和普通对象的属性有什么不同呢。根据ECMA-262中的13.2节所述,在函数对象创建时,系统会默认为其创建两个属性[[call]]和[[constructor]],当函数对象被当做一个普通函数调用的时候(例如myFunc()),“()”操作符指明函数对象的[[call]]属性就被执行,当他被当做一个构造器被调用的时候(例如new myConst()),他的[[constructor]]属性就被执行,[[cosntructor]]的执行过程我们将在下一节中介绍。除此之外,当一个函数被创建时,系统会默认的再为其创建一个显示属性prototype,并为其赋值为

this.prototype = {constructor:this}

具体内容可以参加老道的那本书的第五章。这个函数对象的prototype属性也是为了js把函数当做构造器来实现继承是准备的,但是这个属性是可以在js脚本中访问和修改的。在这里要强调的一点是,大家一定要区分对象中的[[proto]]属性和函数对象中的prototype属性,我在刚开始学习的时候就是因为没有很好的区分这两个东西,走了很多的弯路。

4、 对象的创建

在js中有两种创建对象的方法,一种是通过字面量来实现,如

var Person = {

“first_name”:'liang',

‘last_name':'yang'

}

另一种方法是通过构造器来创建

var my = new Person(‘liang','yang');

其实第一种方式的创建过程相当于调用Object构造器来实现,如下。

var Person = new Object();

Person.first_name = ‘liang';

Person.last_name = ‘yang'

所以我们可以把js中所有对象的创建都合并到使用构造器来实现,下面我么来详细说明构造器创建对象的过程:

第一步,先创建一个空的对象(既没有任何属性),并将这个对象的[[proto]]指向这个构造器函数的prototype属性对象

第二步,将这个空的对象作为this指针传给构造器函数并执行

第三步,如果上面的函数返回一个对象,则返回这个对象,否则返回第一步创建的对象

第四步,把函数当做一个类来使用

由上面的步骤我们可以看出,一般来说函数对象的prototype指向的是一个普通对象,而不是一个函数对象,这个普通对象中的属在由此函数构造器创建的对象中也可以访问。由此可以如此设计我们的代码,假设一个函数就可以代表一个类,这个构造器函数生成的对象就是这个类的实例对象,那么实例对象中应有的属性和方法应该放在这个构造器函数的prototype中,这个类的静态方法就可以直接放到这个函数作为对象的属性中,最后这个函数体就是我们平时在面向对象语言中所说的构造函数(在这里我们要区分连个词“构造函数”和“构造器函数”,所谓构造函数是指普通的面向对象语言中的类的构造函数,而构造器函数是指javascript中的一个函数被当做构造器使用)。

在第3节我们说过每个函数的prototype对象中总是含有一个constructor属性,这个属性就是连接到我们的这个函数本身。再加之,有这个函数生成的每个对象的[[proto]]属性都是指向构造器函数的prototype对象,所以通过[[proto]]链,每个由构造器函数生成的对象,都有一个constructor属性,指向生成他的构造器函数,因此我们可以通过这个属性来判断这个对象是有哪个构造器函数生成的。

5、 函数继承(类继承)

说了这么多,终于到了我们可以在javascript中讨论继承的时候了,我们先来考虑一下要实现类的继承我们都要做些什么,假设我们要从superClass继承到子类subClass

为了使得由subClass生成的对象中能够访问superClass生成的对象中的属性,那么可以使subClass.prototype为一个superClass构造函数生成的对象。

subclass.prototye = new superClass();

但是问题来了,根据我们在第4节说的new superClass()不仅复制了superClass.prototype中的所有方法,而且还运行了superClass()这个函数,这个函数起到的作用是类中的构造函数。我们知道应该在子类的构造函数中调用父类的构造函数来实现初始化。为此我们可以创建一个构造函数为空的,但是原型和superClass原型一致的函数,并使subClass.prototype指向这个函数生成的对象。

var F = function() {};

F.prototype = superClass.prototype;

subClass.protptype = new F();

这样我们就可以再不调用构造函数的同时完成属性复制的工作。但是还有一个问题,那就是我们修改了subClass的prototype属性,从而也就删除了其中的constructor属性,这样我们就无法知道他是哪个构造器函数生成的对象了。我们可以再次给他赋值

subClass.prototype.constructor = subClass;

这样复制属性的问题就迎刃而解了。但是新的问题又出现了,在subClass中我们无法知道他的父类是哪个构造器函数,所以就无法在构造函数中调用父类的构造函数,为此我们可以为subClass添加一个属性,指明他的父类

subClass.superClass = superClass.prototype;

这样我么就可以在子类的构造函数中使用subClass.superClass.constructor来访问父类的构造函数了。最后我们把以上的思路写成一个函数

myPro.extend = function (subClass,superClass) {

var F = function() {};

F.prototype = superClass.prototype;

subClass.protptype = new F();

subClass.prototype.constructor = subClass;

subClass.superClass = superClass.prototype;

superClass.prototype.constructor = superClass;

}

Javascript 相关文章推荐
jQuery :nth-child前有无空格的区别分析
Jul 11 Javascript
深入理解Javascript作用域与变量提升
Dec 09 Javascript
JSONP跨域GET请求解决Ajax跨域访问问题
Dec 31 Javascript
JavaScript中的函数嵌套使用
Jun 04 Javascript
jQuery UI设置固定日期选择特效代码分享
Aug 27 Javascript
Js动态设置rem来实现移动端字体的自适应代码
Oct 14 Javascript
jQuery插件fullPage.js实现全屏滚动效果
Dec 02 Javascript
Vue.js实现微信过渡动画左右切换效果
Jun 13 Javascript
详解webpack 多入口配置
Jun 16 Javascript
Three.js利用orbit controls插件(轨道控制)控制模型交互动作详解
Sep 25 Javascript
JS浏览器BOM常见操作实例详解
Apr 27 Javascript
JS实现鼠标按下拖拽效果
Jul 23 Javascript
js 日期转换成中文格式的函数
Jul 07 #Javascript
javascript 面向对象思想 附源码
Jul 07 #Javascript
jquery BS,dialog控件自适应大小
Jul 06 #Javascript
javascript 浏览器判断 绑定事件 arguments 转换数组 数组遍历
Jul 06 #Javascript
javascript 写类方式之十
Jul 05 #Javascript
javascript 写类方式之九
Jul 05 #Javascript
javascript 写类方式之八
Jul 05 #Javascript
You might like
PHP常用数组函数介绍
2014/07/28 PHP
php不使用copy()函数复制文件的方法
2015/03/13 PHP
老生常谈文本文件和二进制文件的区别
2017/02/27 PHP
PHP有序表查找之二分查找(折半查找)算法示例
2018/02/09 PHP
游戏人文件夹程序 ver 4.03
2006/07/14 Javascript
基于JQuery框架的AJAX实例代码
2009/11/03 Javascript
jquery中使用$(#form).submit()重写提交表单无效原因分析及解决
2013/03/25 Javascript
jquery中表单 多选框的一种巧妙写法
2015/09/06 Javascript
js实现控制textarea输入字符串的个数,鼠标按下抬起判断输入字符数
2016/10/25 Javascript
js数组方法reduce经典用法代码分享
2018/01/07 Javascript
vue结合axios与后端进行ajax交互的方法
2018/07/06 Javascript
JavaScript闭包原理与用法实例分析
2018/08/10 Javascript
vue3.0 CLI - 2.6 - 组件的复用入门教程
2018/09/14 Javascript
Element input树型下拉框的实现代码
2018/12/21 Javascript
JavaScript对JSON数组简单排序操作示例
2019/01/31 Javascript
vue store之状态管理模式的详细介绍
2019/06/13 Javascript
JS 数组和对象的深拷贝操作示例
2020/06/06 Javascript
vue监听浏览器原生返回按钮,进行路由转跳操作
2020/09/09 Javascript
利用Python命令行传递实例化对象的方法
2016/11/02 Python
Python利用递归和walk()遍历目录文件的方法示例
2017/07/14 Python
对pandas的行列名更改与数据选择详解
2018/11/12 Python
对web.py设置favicon.ico的方法详解
2018/12/04 Python
WxPython建立批量录入框窗口
2019/02/27 Python
python求一个字符串的所有排列的实现方法
2020/02/04 Python
详解Pycharm出现out of memory的终极解决方法
2020/03/03 Python
浅谈numpy中函数resize与reshape,ravel与flatten的区别
2020/06/18 Python
纽约现代艺术博物馆商店:MoMA STORE(室内家具和杂货商品)
2016/08/02 全球购物
金士达面试非笔试
2012/03/14 面试题
印刷技术专业自荐信
2014/09/18 职场文书
家长给老师的感谢信
2015/01/20 职场文书
应届生求职自荐信范文
2015/03/04 职场文书
个人年度总结报告
2015/03/09 职场文书
销售经理岗位职责范本
2015/04/02 职场文书
2015年高校保卫处工作总结
2015/07/23 职场文书
同学聚会开幕词
2019/04/02 职场文书
一条 SQL 语句执行过程
2022/03/17 MySQL