JavaScript的面向对象编程基础


Posted in Javascript onAugust 13, 2015

重新认识面向对象
为了说明 JavaScript 是一门彻底的面向对象的语言,首先有必要从面向对象的概念着手 , 探讨一下面向对象中的几个概念:

  1. 一切事物皆对象
  2. 对象具有封装和继承特性
  3. 对象与对象之间使用消息通信,各自存在信息隐藏

以这三点做为依据,C++ 是半面向对象半面向过程语言,因为,虽然他实现了类的封装、继承和多态,但存在非对象性质的全局函数和变量。Java、C# 是完全的面向对象语言,它们通过类的形式组织函数和变量,使之不能脱离对象存在。但这里函数本身是一个过程,只是依附在某个类上。

然而,面向对象仅仅是一个概念或者编程思想而已,它不应该依赖于某个语言存在。比如 Java 采用面向对象思想构造其语言,它实现了类、继承、派生、多态、接口等机制。但是这些机制,只是实现面向对象编程的一种手段,而非必须。换言之,一门语言可以根据其自身特性选择合适的方式来实现面向对象。所以,由于大多数程序员首先学习或者使用的是类似 Java、C++ 等高级编译型语言(Java 虽然是半编译半解释,但一般做为编译型来讲解),因而先入为主地接受了“类”这个面向对象实现方式,从而在学习脚本语言的时候,习惯性地用类式面向对象语言中的概念来判断该语言是否是面向对象语言,或者是否具备面向对象特性。这也是阻碍程序员深入学习并掌握 JavaScript 的重要原因之一。
实际上,JavaScript 语言是通过一种叫做 原型(prototype)的方式来实现面向对象编程的。下面就来讨论 基于类的(class-based)面向对象和 基于原型的 (prototype-based) 面向对象这两种方式在构造客观世界的方式上的差别。
基于类的面向对象和基于原型的面向对象方式比较
在基于类的面向对象方式中,对象(object)依靠 类(class)来产生。而在基于原型的面向对象方式中,对象(object)则是依靠 构造器(constructor)利用 原型(prototype)构造出来的。举个客观世界的例子来说明二种方式认知的差异。例如工厂造一辆车,一方面,工人必须参照一张工程图纸,设计规定这辆车应该如何制造。这里的工程图纸就好比是语言中的 类 (class),而车就是按照这个 类(class)制造出来的;另一方面,工人和机器 ( 相当于 constructor) 利用各种零部件如发动机,轮胎,方向盘 ( 相当于 prototype 的各个属性 ) 将汽车构造出来。
事实上关于这两种方式谁更为彻底地表达了面向对象的思想,目前尚有争论。但笔者认为原型式面向对象是一种更为彻底的面向对象方式,理由如下:
首先,客观世界中的对象的产生都是其它实物对象构造的结果,而抽象的“图纸”是不能产生“汽车”的,也就是说,类是一个抽象概念而并非实体,而对象的产生是一个实体的产生;
其次,按照一切事物皆对象这个最基本的面向对象的法则来看,类 (class) 本身并不是一个对象,然而原型方式中的构造器 (constructor) 和原型 (prototype) 本身也是其他对象通过原型方式构造出来的对象。
再次,在类式面向对象语言中,对象的状态 (state) 由对象实例 (instance) 所持有,对象的行为方法 (method) 则由声明该对象的类所持有,并且只有对象的结构和方法能够被继承;而在原型式面向对象语言中,对象的行为、状态都属于对象本身,并且能够一起被继承(参考资源),这也更贴近客观实际。
最后,类式面向对象语言比如 Java,为了弥补无法使用面向过程语言中全局函数和变量的不便,允许在类中声明静态 (static) 属性和静态方法。而实际上,客观世界不存在所谓静态概念,因为一切事物皆对象!而在原型式面向对象语言中,除内建对象 (build-in object) 外,不允许全局对象、方法或者属性的存在,也没有静态概念。所有语言元素 (primitive) 必须依赖对象存在。但由于函数式语言的特点,语言元素所依赖的对象是随着运行时 (runtime) 上下文 (context) 变化而变化的,具体体现在 this 指针的变化。正是这种特点更贴近 “万物皆有所属,宇宙乃万物生存之根本”的自然观点。

JavaScript 面向对象基础知识

虽然 JavaScript 本身是没有类的概念,但它仍然有面向对象的特性,虽然和一般常见的面向对象语言有所差异。

简单的创建一个对象的方法如下:

function myObject() {

};

JavaScript 中创建对象的方法一般来说有两种:函数构造法和字面量法,上面这种属函数构造法。下面是一个字面量法的例子:

var myObject = {

};

如果仅仅需要一个对象,而不需要对象的其它实例的情况下,推荐用字面量法。如果需要对象的多个实例,则推荐函数构造法。
定义属性和方法

函数构造法:

function myObject() {
 this.iAm = 'an object';

 this.whatAmI = function() {
 console.log('I am ' + this.iAm);
 };
};

字面量法:

var myObject = {
 iAm : 'an object',

 whatAmI : function() {
 console.log('I am ' + this.iAm);
 }
};

以上两种方法创建的对象中,都有一个名为 “iAm” 的属性,还有一个名为 “whatAmI” 的方法。属性是对象中的变量,方法则是对象中的函数。

如何获取属性及调用方法:

var w = myObject.iAm;

myObject.whatAmI();

调用方法的时候后面一定要加上括号,如果不加括号,那么它只是返回方法的引用而已。
两种创建对象方法的区别

  •     函数构造法里面定义属性和方法的时候,都要用前缀 this,字面量法不需要。
  •     函数构造法给属性和方法赋值的时候用的是 =,字面量法用的是 : 。
  •     如果有多个属性或方法,函数构造法里面用 ; 隔开,字面量法用 , 隔开。

对于字面量法创建的对象,可以直接用对象的引用调用其属性或方法:

myObject.whatAmI();

而对于函数构造法而言,需要创建对象的实例,才能调用其属性或方法:

var myNewObject = new myObject();
myNewObject.whatAmI();

使用构造函数

现在再来回归一下之前的函数构造法:

function myObject() {
 this.iAm = 'an object';
 this.whatAmI = function() {
 console.log('I am ' + this.iAm);
 };
};

其实它看起来就是个函数,既然是函数,能不能给它传参数呢?将代码再稍作修改:

function myObject(what) {
 this.iAm = what;
 this.whatAmI = function(language) {
 console.log('I am ' + this.iAm + ' of the ' + language + ' language');
 };
};

再将对象实例化,并传入参数:

var myNewObject = new myObject('an object');
myNewObject.whatAmI('JavaScript');

程序最终输出 I am an object of the JavaScript language。
两种创建对象的方法,我该用哪种?

对于字面量方法而言,因为它不需要实例化,所以如果修改了某对象的值,那么这个对象的值就永久地被修改了,其它任何地方再访问,都是修改后的值。而对于函数构造法而言,修改值的时候是修改其实例的值,它可以实例化 N 个对象出来,每个对象都可以拥有自己不同的值,而且互不干扰。比较以下几段代码。

先看字面量法:

var myObjectLiteral = {
 myProperty : 'this is a property'
};

console.log(myObjectLiteral.myProperty); // log 'this is a property'

myObjectLiteral.myProperty = 'this is a new property';

console.log(myObjectLiteral.myProperty); // log 'this is a new property'

即便创建了一个新的变量指向这个对象,结果还是一样的:

var myObjectLiteral = {
 myProperty : 'this is a property'
};

console.log(myObjectLiteral.myProperty); // log 'this is a property'

var sameObject = myObjectLiteral;

myObjectLiteral.myProperty = 'this is a new property';

console.log(sameObject.myProperty); // log 'this is a new property'

再看函数构造法:

// 用函数构造法
var myObjectConstructor = function() {
   this.myProperty = 'this is a property'
};

// 实例化一个对象
var constructorOne = new myObjectConstructor();

// 实例化第二个对象
var constructorTwo = new myObjectConstructor();

// 输出
console.log(constructorOne.myProperty); // log 'this is a property'

// 输出
console.log(constructorTwo.myProperty); // log 'this is a property'

和预期一样,两个对象的属性值是一样的。如果修个其中一个对象的值呢?

// 用函数构造法
var myObjectConstructor = function() {
 this.myProperty = 'this is a property';
};

// 实例化一个对象
var constructorOne = new myObjectConstructor();

// 修改对象的属性
constructorOne.myProperty = 'this is a new property';

// 实例化第二个对象
var constructorTwo = new myObjectConstructor();

// 输出
alert(constructorOne.myProperty); // log 'this is a new property'

// 输出
alert(constructorTwo.myProperty); // log 'this is a property'

可以看到,用函数构造法实例化出来的不同对象,相互是独立的,可以各自拥有不同的值。所以说,到底用哪种方法来创建对象,需取决于各自实际情况。

Javascript 相关文章推荐
jQuery 第二课 操作包装集元素代码
Mar 14 Javascript
jquery的$getjson调用并获取远程的JSON字符串问题
Dec 10 Javascript
jQuery实现从身份证号中获取出生日期和性别的方法分析
Feb 25 Javascript
Bootstrap Navbar Component实现响应式导航
Oct 08 Javascript
微信小程序 location API接口详解及实例代码
Oct 12 Javascript
SpringMVC+bootstrap table实例详解
Jun 02 Javascript
微信小程序实现获取自己所处位置的经纬度坐标功能示例
Nov 30 Javascript
js实现敏感词过滤算法及实现逻辑
Jul 24 Javascript
JS实现图片上传多次上传同一张不生效的处理方法
Aug 06 Javascript
详解微信小程序canvas圆角矩形的绘制的方法
Aug 22 Javascript
关于js陀螺仪的理解分析
Apr 11 Javascript
jquery分页优化操作实例分析
Aug 23 jQuery
JavaScript简单判断复选框是否选中及取出值的方法
Aug 13 #Javascript
JavaScript实现将文本框的值插入指定位置的方法
Aug 13 #Javascript
JavaScript的jQuery库中function的存在和参数问题
Aug 13 #Javascript
js实现仿Discuz文本框弹出层效果
Aug 13 #Javascript
深入学习JavaScript中的原型prototype
Aug 13 #Javascript
javascript获取本机操作系统类型的方法
Aug 13 #Javascript
javascript中offset、client、scroll的属性总结
Aug 13 #Javascript
You might like
【COS正片】蕾姆睡衣cos,纯洁可爱被治愈了 cn名濑弥七
2020/03/02 日漫
php中get_cfg_var()和ini_get()的用法及区别
2015/03/04 PHP
用js实现的一个Flash滚动轮换显示图片代码生成器
2007/03/14 Javascript
FireFox中textNode分片的问题
2007/04/10 Javascript
javascript不同页面传值的改进版
2008/09/30 Javascript
Jquery index()方法 获取相应元素索引值
2012/10/12 Javascript
JS常见问题整理(持续更新)
2013/08/06 Javascript
jQuery怎么解析Json字符串(Json格式/Json对象)
2013/08/09 Javascript
js处理表格对table进行修饰
2014/05/26 Javascript
javascript作用域链(Scope Chain)用法实例解析
2015/11/30 Javascript
JavaScript中的this到底是什么(一)
2015/12/09 Javascript
Javascript实现单例模式
2016/01/24 Javascript
jquery中键盘事件小结
2016/02/24 Javascript
浅析javascript中的Event事件
2016/12/09 Javascript
用director.js实现前端路由使用实例
2017/01/27 Javascript
JavaScript定时器制作弹窗小广告
2017/02/05 Javascript
js实现简单的选项卡效果
2017/02/23 Javascript
详解在Vue中如何使用axios跨域访问数据
2017/07/07 Javascript
微信小程序 转发功能的实现
2017/08/04 Javascript
微信小程序页面滑动屏幕加载数据效果
2020/11/16 Javascript
node.js中stream流中可读流和可写流的实现与使用方法实例分析
2020/02/13 Javascript
JS中类的静态方法,静态变量,实例方法,实例变量区别与用法实例分析
2020/03/14 Javascript
python 读取文件并把矩阵转成numpy的两种方法
2019/02/12 Python
pyhanlp安装介绍和简单应用
2019/02/22 Python
Python数据类型之List列表实例详解
2019/05/08 Python
PyQt5显示GIF图片的方法
2019/06/17 Python
python3.6环境安装+pip环境配置教程图文详解
2019/06/20 Python
解决Django后台ManyToManyField显示成Object的问题
2019/08/09 Python
python小程序基于Jupyter实现天气查询的方法
2020/03/27 Python
Python操作Jira库常用方法解析
2020/04/10 Python
详解canvas在圆弧周围绘制文本的两种写法
2018/05/22 HTML / CSS
中学生的1000字检讨书
2014/10/11 职场文书
2014年后勤管理工作总结
2014/12/01 职场文书
委托书格式要求
2015/01/28 职场文书
会计主管竞聘书
2015/09/15 职场文书
WebWorker 封装 JavaScript 沙箱详情
2021/11/02 Javascript