探讨javascript面向对象编程
(个人blog迁移文章。)
前言:
下面将探讨javascript面向对象编程的知识。
请不要刻意把javascript想成面向对象编程是理所当然的。
javascript里面,对象思想不可少,但是不一定需要面向对象编程,有时候,我们需要的只是一个实例化了的对象,而不是一个创建对象的类。
偏要这样做的话,也行,请看下文。另外请勿与传统面向对象编程做对比,这没有可比性。
对于javascript来说,所有的变量都可以被称为对象。例如:
var a = 'hello world';
console.log(a.toUpperCase());
这里面,a为字符串对象。有其能直接调用的方法。但是这篇文章不讨论这一类的变量,而是讨论如何自定义对象。
声明一个对象:
var obj1 = {};
var obj2 = new Object();
通过上面这两种方式中任意一种,就就声明了一个对象变量,这是一个实例,而且,是一个空对象,不能继承。
何为空对象,就是这个对象里面没有定义任何成员和方法。
设置对象成员和方法:
var Person = {};
Person.name = 'Tom';
Person.gender = 'male';
Person.sayHello = function () {
console.log("Hello "+this.name+".");
}
这是一种最直观最简单的对象定义及成员方法添加的方法,里面定义了person对象,person有name和gender的成员,以及sayHello的方法。这也是一个实例,不能继承。通过person.name/persion.gender能直接引用该对象的成员,person.sayHello()能直接调用该对象的方法。这算基础。
在sayHello方法中,this指向的就是person,和其他的面向对象编程方法相同。
上面声明对象的方法太过于累赘,一般选择下面这种对象声明的方法。
var Person = {
name:'Tom',
gender:'male',
sayHello:function() {
console.log("Hello "+this.name+".");
}
}
这样的声明方法比上面的方法都简洁,首推方法。成员方法调用方式一样。
声明一个可继承的类:
情景一:
var Person = function (name) {
this.name = name || 'NoName';
};
Person.sayHello = function () {
console.log("Hello "+this.name+".");
}
var Tom = new Person();
这样子,就等于声明了一个person的类,Tom就是person的一个实例。但是person.sayHello方法就等于是私有属性,不能被继承,所有Tom没有sayHello的方法。
情景二:
var Person = function (name) {
this.name = name||"NoName";
this.sayHello = function () {
console.log("Hello "+this.name+".");
}
};
var Tom = new Person('Tom');
Tom.sayHello();
这样也是定义对象的一个方法,person是一个类,其name和sayHello可被实例继承。但是有一个缺陷,如果通过此类创建多个实例,那么这个类就存在多少份的复制,就如上面来说,创建多个实例:
var Tom1 = new Person("Tom1");
var Tom2 = new Person("Tom2");
var Tom3 = new Person("Tom3");
此时,Person就存在三个实例,每个实例有自己的成员和方法,内存中有三个sayHello方法的引用。sayHello作为一个通用的方法,这样定义的话,在新建多个实例时,就会造成内存的浪费。因此,应该把通用的方法使用原型链的方式定义,请看情景三。
情景三:
var Person = function (name) {
this.name = name||"NoName";
};
Person.prototype.sayHello = function () {
console.log("Hello "+this.name+".");
}
var Tom = new Person('Tom');
Tom.sayHello();
通过原型链的方式,基于这个类新建的实例,其方法就不会再内存里面存在多个实例。
但是此时,又涉及一个问题,如何知道Tom属于哪个类的呢,通过哪个构造函数来创建的呢?就引申到情景四了。
情景四:
这里,讨论的是实例的构造函数,每一个对象都有一个construcor的成员方法,指向的是创建该对象的那个函数。
例如:
var arr1 = [1,2,3,4,5]; //此时arr1.constructor就是Array。
var func = function() {};//此时func.constructor就是Function。
因此,情景三中的Tom.constructor 就是 Person,就是
function (name) {
this.name = name||"NoName";
};
这一个函数。通过new运算符创建的实例,该实例成员constructor所指向的就是new后面的变量。
题外话,说说new运算符,MDN上面关于new运算符的定义是这样的:
The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.
大意是:new运算符能为那些存在构造函数的用户自定义对象类型或者浏览器内部实现对象类型创建一个实例。
new的语法格式为
new constructor[([arguments])];
可以明显看出 实例的成员constructor就是创建该实例的对象类型。
上面的四个情景,都不能说是面向对象编程,因为,还没有实现类的继承,只实现了类的创建实例。下面情景五来探讨如何继承类。
情景五:
不推荐用原生的写法进行面向对象编程,因为确实非常麻烦,推荐使用coffeescript进行面向对象的编程,甚至所有的javascript的编写,能转coffeescript就全部转,你会发现,使用coffeescript写出来的代码非常的优雅,而且,你将全部精力投入的是如何巧妙的设计代码,而不是堆代码的时代。
当然,这里还是会讲讲如何通过原生javascript的方式实现javascript的继承。不过,真的很麻烦。
首先,得要一个extends,把它看成new级别的东西吧。
var __extends = function(child,father) {
for(var property in father) {
child[property] = father[property];
}
}
var Animal = function (name) {
this.name = name;
}
Animal.sayHello = function () {
console.log("Hello "+this.name);
}
var Cat = function (name) {
this.name = name;
}
__extends(Cat,Animal);
Cat.sayHello();
这是一种继承的方式,要完美实现,这还是不足的。代码量好大啊。还是使用coffeescript来写吧。
情景六:
在情景五中,Cat继承了Animal的sayHello的方法。但是,如果改成 Animal.prototype.sayHello = function () {}的话,Cat类就没法继承了,这就是上面那种简单写法的缺陷。
所以需要把prototype的属性也要继承,所以必须把__extends函数重新写,注意prototype对于所有其派生类都是指向同一个内存空间的,修改父类对象的prototype将影响所有的子类。
var __extends = function(child,father) {
for(var property in father) {
child[property] = father[property];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = father.prototype;
}
很麻烦是吧,而且也不知道会不会出错。那您也应该尝试coffeescript的写法了。
情景七:
所以,还是来试试coffeescript的写法吧
class Animal
constructor:(@name) ->
sayHello:->
console.log "Hello #{this.name}."
return
class Cat extends Animal
sayHello:->
console.log "喵喵喵喵喵喵,#{this.name}"
class Dog extends Animal
sayHello:->
console.log "汪汪汪汪汪汪,#{this.name}"
cat1 = new Cat "kitty"
dog1 = new Don "哈士奇"
通过coffeescript写出一个javascript对象继承,代码就是这么简洁。
在这里面,就定义了Animal类,还有派生类Cat和Dog,分别覆盖了父类的sayHello的方法。写完之后,直接使用koala编译一下,马上一段完美的继承代码生成了。
结语:
至此,此片面向对象的文章算是草草结束了,断断续续写了一个星期,就写成了这样子,比较糟糕。大家不妨看看下面的参考文献。
参考文献:
觉得对您有帮助,点个赞。赞赞更健康。
探讨javascript面向对象编程的更多相关文章
- 再谈javascript面向对象编程
前言:虽有陈皓<Javascript 面向对象编程>珠玉在前,但是我还是忍不住再画蛇添足的补上一篇文章,主要是因为javascript这门语言魅力.另外这篇文章是一篇入门文章,我也是才开始 ...
- JavaScript面向对象编程学习笔记
1 Javascript 面向对象编程 所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量.对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例 ...
- 快速学习JavaScript面向对象编程
到处都是属性.方法,代码极其难懂,天哪,我的程序员,你究竟在做什么?仔细看看这篇指南,让我们一起写出优雅的面向对象的JavaScript代码吧! 作为一个开发者,能否写出优雅的代码对于你的职业生涯至关 ...
- 深入理解Javascript面向对象编程
深入理解Javascript面向对象编程 阅读目录 一:理解构造函数原型(prototype)机制 二:理解原型域链的概念 三:理解原型继承机制 四:理解使用类继承(继承的更好的方案) 五:建议使用封 ...
- 【转】Javascript 面向对象编程(一):封装
原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html Javascript ...
- Javascript 面向对象编程(一):封装 by 阮一峰
<Javascript高级程序设计(第二版)>(Professional JavaScript for Web Developers, 2nd Edition) 它们都是非常优秀的Java ...
- 转:javascript面向对象编程
作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学 ...
- JavaScript面向对象编程(一)原型与继承
原型(prototype) JavaScript是通过原型(prototype)进行对象之间的继承.当一个对象A继承自另外一个对象B后,A就拥有了B中定义的属性,而B就成为了A的原型.JavaScri ...
- JavaScript面向对象编程(二)构造函数和类
new关键字和构造函数 在文章JavaScript面向对象编程(一)原型与继承中讨论啦JavaScript中原型的概念,并且提到了new关键字和构造函数.利用new关键字构造对象的实例代码如下: // ...
随机推荐
- 采用Flume实时采集和处理数据
它已成功安装Flume在...的基础上.本文将总结使用Flume实时采集和处理数据,详细过程,如下面: 第一步,在$FLUME_HOME/conf文件夹下,编写Flume的配置文件,命名为flume_ ...
- 新秀翻译(两)——使用Java通用配置模板方法模式
假设你发现你已经非常重码,你可能会考虑使用模板的方法来消除easy重复错误代码.下面是一个示例:以下两类,他完成了几乎相同的功能: 实例化并初始化一个Reader来读取CSV文件. 读取每一行并解析: ...
- hibernate几个纯sql查询
几个hibernate纯SQL询问,查询和表没有映射pojo实体和表有映射关系的实体...... 1.getSession().createSQLQuery(sql).query.addScalar( ...
- 【安德鲁斯】于java代码集drawableLeft给予适当的大小如何,当?
textView.setCompoundDrawables(drawable, null, null, null);如果看不到图片,这是由于需要手动定drawable适当的大小,使用drawable. ...
- 常见的FPGA内串行数据采样的方式
总结下常见的对串行数据采样的三种方式: 1. 全采样存储方式: 采用过采样,用过采样时钟,用移位寄存器移位,把每次采样值都存起来.采用高速的过采样时钟运行. 然后等待触发条件,(就是找到数据的起始点条 ...
- HDU 4123 Bob’s Race 树的直径+单调队列
题意: 给定n个点的带边权树Q个询问. 以下n-1行给出树 以下Q行每行一个数字表示询问. 首先求出dp[N] :dp[i]表示i点距离树上最远点的距离 询问u, 表示求出 dp 数组中最长的连续序列 ...
- Python 基于学习 网络小爬虫
<span style="font-size:18px;"># # 百度贴吧图片网络小爬虫 # import re import urllib def getHtml( ...
- 设计模式之享元模式(Flyweight)摘录
23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于怎样创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...
- python基础课程_学习笔记21:文件和材料
文件和材料 打开文件 open功能是用来打开文件,语法例如,下面的: open([name[,mode[,buffering]]) open函数使用一个文件名称作为唯一的强制參数,然后返回一个文件对象 ...
- this、访问修饰符——Java笔记(五)
this 表示当前对象 谁调用方法谁就是当前对象 用static修饰的代码块里面不能使用this 方法里面有一个和字段同名的局部变量时,不能省略this this还 ...