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 ui1.7 dialog只能弹出一次问题
Aug 27 Javascript
为radio类型的INPUT添加客户端脚本(附加实现JS来禁用onClick事件思路代码)
Nov 11 Javascript
javascript权威指南 学习笔记之变量作用域分享
Sep 28 Javascript
jquery通过select列表选择框对表格数据进行过滤示例
May 07 Javascript
关于微信中a链接无法跳转问题
Aug 02 Javascript
vue.js学习之vue-cli定制脚手架详解
Jul 02 Javascript
基于jQuery Ajax实现下拉框无刷新联动
Dec 06 jQuery
解决JavaScript layui 下拉框不显示的问题
Aug 14 Javascript
如何将百度地图包装成Vue的组件的方法步骤
Feb 12 Javascript
vue实现点击隐藏与显示实例分享
Feb 13 Javascript
在 Vue 应用中使用 Netlify 表单功能的方法详解
Jun 03 Javascript
Node.js API详解之 os模块用法实例分析
May 06 Javascript
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
一个查看session内容的函数
2006/10/09 PHP
php生成的html meta和link标记在body标签里 顶部有个空行
2010/05/18 PHP
解析php中array_merge与array+array的区别
2013/06/21 PHP
非常实用的PHP常用函数汇总
2014/12/17 PHP
PHP自动生成表单代码分享
2015/06/19 PHP
yii使用bootstrap分页样式的实例
2017/01/17 PHP
ThinkPHP整合datatables实现服务端分页的示例代码
2018/02/10 PHP
PHP7引入的"??"和"?:"的区别讲解
2019/04/08 PHP
JS 的应用开发初探(mootools)
2009/12/19 Javascript
jquery 图片上传按比例预览插件集合
2011/05/28 Javascript
父元素与子iframe相互获取变量和元素对象的具体实现
2013/10/15 Javascript
jQuery过滤选择器:not()方法使用介绍
2014/04/20 Javascript
Javascript动画的实现原理浅析
2015/03/02 Javascript
JavaScript设置、获取、清除单值和多值cookie的方法
2015/11/17 Javascript
聊一聊JS中的prototype
2016/09/29 Javascript
ES2015 Symbol 一种绝不重复的值
2016/12/25 Javascript
原生js实现验证码功能
2017/03/16 Javascript
React Navigation 使用中遇到的问题小结
2018/05/08 Javascript
浅谈JS对象添加getter与setter的5种方法
2018/06/09 Javascript
Node批量爬取头条视频并保存方法
2018/09/20 Javascript
vue form check 表单验证的实现代码
2018/12/09 Javascript
JavaScript学习笔记之基于定时器实现图片无缝滚动功能详解
2019/01/09 Javascript
原生JS实现随机点名项目的实例代码
2019/04/30 Javascript
在vue中使用console.log无效的解决
2020/08/09 Javascript
Python 3.x 判断 dict 是否包含某键值的实例讲解
2018/07/06 Python
python3利用ctypes传入一个字符串类型的列表方法
2019/02/12 Python
详解python tkinter教程-事件绑定
2019/03/28 Python
在PyCharm中控制台输出日志分层级分颜色显示的方法
2019/07/11 Python
python处理大日志文件
2019/07/23 Python
Python高级编程之继承问题详解(super与mro)
2019/11/19 Python
keras 读取多标签图像数据方式
2020/06/12 Python
土耳其玩具商店:Toyzz Shop
2019/08/02 全球购物
周仰杰(JIMMY CHOO)法国官方网站:闻名世界的鞋子品牌
2019/09/27 全球购物
人力资源本科毕业生求职信
2014/06/04 职场文书
钢琴师观后感
2015/06/12 职场文书
运动会闭幕式主持词
2015/07/01 职场文书