如何理解Javascript中类和对象这两个概念

JavaScript027

如何理解Javascript中类和对象这两个概念,第1张

在说这个话题之前,我想先说几句题外话:最近偶然碰到有朋友问我“hoisting”的问题。即在js里所有变量的声明都是置顶的,而赋值则是在之后发生的。可以看看这个例子:

var a = 'global'

(function () {

alert(a)

var a = 'local'

})()

大家第一眼看到这个例子觉得输出结果是什么?‘global’?还是‘local’?其实都不是,输出的是undefined,不用迷惑,我的题外话就是为了讲这个东西的。

其实很简单,看一看JavaScript运行机制就会明白。我们可以把这种现象看做“预声明”。但是如果稍微深究一下,会明白得更透彻。

这里其实涉及到对象属性绑定机制。因为所有JavaScript函数都是一个对象。在函数里声明的变量可以看做这个对象的“类似属性”。对象属性的绑定在语言里是有分“早绑定”和“晚绑定”之分的。

【早绑定】

是指在实例化对象之前定义其属性和方法。解析程序时可以提前转换为机器代码。通常的强类型语言如C++,java等,都是早绑定机制的。而JavaScript不是强类型语言。它使用的是“晚绑定”机制。

【晚绑定】

是指在程序运行前,无需检查对象类型,只要检查对象是否支持特性和方法即可。可以在绑定前对对象执行大量操作而不受任何惩罚。

上面代码出现的“预声明”现象,我们大可用“晚绑定”机制来解释。在函数的作用域中,所有变量都是“晚绑定”的。 即声明是顶级的。所以上面的代码和下面的一致:

var a = 'global'

(function () {

var a

alert(a)

a = 'local'

})()

在alert(a)之前只对a作了声明而没有赋值。所以结果可想而知。

<!-- 题外话到此结束 -->

RT:本文要说的是,在JavaScript里,我所知道的几种定义类和对象的方式:<! -- 声明:以下内容大部分来自《JavaScript高级程序设计》,只是个人叙述方式不同而已 -- >

【直接量方式】

使用直接量构建对象是最基础的方式,但也有很多弊端。

var Obj = new Object

Obj.name = 'sun'

Obj.showName = function() {

alert('this.name')

}

我们构建了一个对象Obj,它有一个属性name,一个方法showName。但是如果我们要再构建一个类似的对象呢?难道还要再重复一遍?

NO!,我们可以用一个返回特定类型对象的工厂函数来实现。就像工厂一样,流水线的输出我们要的特定类型结果。

【工厂方式】

function createObj(name) {

var tempObj = new Object

tempObj.name = name

tempObj.showName = function () {

alert(this.name)

}

return tempObj

}

var obj1 = createObj('obj_one')

var obj2 = createObj('obj_two')

这种工厂函数很多人是不把他当做构建对象的一种形式的。一部分原因是语义:即它并不像使用了运算符new来构建的那么正规。还有一个更大的原因,是因为这个工厂每次产出一个对象都会创建一个新函数showName(),即每个对象拥有不同的版本,但实际上他们共享的是同一个函数。

有些人把showName在工厂函数外定义,然后通过属性指向该方法,可以避开这个问题:

代码

可惜的是,这种方式让showName()这个函数看起来不像对象的一个方法。

【构造函数方式】

这种方式是为了解决上面工厂函数的第一个问题,即没有new运算符的问题。可是第二个问题它依然不能解决。我们来看看。

function Obj(name) {

this.name = name

this.showName = function () {

alert(this.name)

}

}

var obj1 = new Obj('obj_one')

var obj2 = new Obj('obj_two')

它的好处是不用在构造函数内新建一个对象了,因为new运算符执行的时候会自动创建一个对象,并且只有通过this才能访问这个对象。所以我们可以直接通过this来对这个对象进行赋值。而且不用再return,因为this指向默认为构造函数的返回值。

同时,用了new关键字来创建我们想要的对象是不是感觉更“正式”了。

可惜,它仍然不能解决会重复生成方法函数的问题,这个情况和工厂函数一样。

【原型方式】

这种方式对比以上方式,有个很大的优势,就是它解决了方法函数会被生成多次的问题。它利用了对象的prototype属性。我们依赖原型可以重写对象实例。

var Obj = function () {}

Obj.prototype.name = 'me'

Obj.prototype.showName = function () {

alert(this.name)

}

var obj1 = new Obj()

var obj2 = new Obj()

我们依赖原型对构造函数进行重写,无论是属性还是方法都是通过原型引用的方式给新建的对象,因此都只会被创建一次。可惜的是,这种方式存在两个致命的问题:

1。没办法在构建对象的时候就写入想要的属性,因为原型在构造函数作用域外边,没办法通过传递参数的方式在对象创建的时候就写入属性值。只能在对象创建完毕后对值进行重写。

2。致命问题在于当属性指向对象时,这个对象会被多个实例所共享。考虑下面的代码:

var Obj = function () {}

Obj.prototype.name = 'me'

Obj.prototype.flag = new Array('A', 'B')

Obj.prototype.showName = function () {

alert(this.name)

}

var obj1 = new Obj()

var obj2 = new Obj()

obj1.flag.push('C')

alert(obj1.flag)// A,B,C

alert(obj2.flag)//A,B,C

是的,当flag属性指向对象时,那么实例obj1和obj2都共享它,哪怕我们仅仅改变了obj1的flag属性,但是它的改变在实例obj2中任然可见。

面对这个问题,让我们不得不想是否应该把【构造函数方式】和【原型方式】结合起来,让他们互补。。。

【构造函数和原型混合方式】

我们让属性用构造函数方式创建,方法用原型方式创建即可:

var Obj = function (name) {

this.name = name

this.flag = new Array('A', 'B')

}

Obj.prototype = {

showName : function () {

alert(this.name)

}

}

var obj1 = new Obj()

var obj2 = new Obj()

obj1.flag.push('C')

alert(obj1.flag)// A,B,C

alert(obj2.flag)//A,B

这种方式有效地结合了原型和构造函数的优势,是目前用的最多,也是副作用最少的方式。

不过,有些追求完美的家伙还不满足,因为在视觉上还没达到他们的要求,因为通过原型来创建方法的过程在视觉上还是会让人觉得它不太像实例的方法(尤其对于传统OOP语言的开发者来说。)

所以,我们可以让原型活动起来,让他也加入到构造函数里面去,好让这个构造函数在视觉上更为统一。而这一系列的过程只需用一个判断即可完成。

var Obj = function (name) {

this.name = name

this.flag = new Array('A', 'B')

if (typeof Obj._init == 'undefined') {

Obj.prototype = {

showName : function () {

alert(this.name)

}

}

Obj._init = true

}

}

如上,用_init作为一个标志来判断是否已经给原型创建了方法。如果是那么就不再执行。这样其实在本质上是没有任何变化的,方法仍是通过原型创建,唯一的区别在于这个构造函数看起来“江山统一”了。

但是这种动态原型的方式是有问题的,《JavaScript高级程序设计》里并没有深究。创建第一个对象的时候会因为prototype在对象实例化之前没来的及建起来,是根本无法访问的。所以第一个对象是无法访问原型方法的。同时这种方式在子类继承中也会有问题。

关于解决方案,我会在下一文中说明。

其实就使用方便来说的话,个人觉得是没必要做这个判断的。。。呵呵 ^_^

javascript是弱类型语言,没有java那么成熟

javascript是基于对象,而java是面向对象

所有面向对象编程语言都支持三个概念:封装、多态性和继承

java的特点就是

1面向对象

2可移植性

3安全性

4并发机制

5支持可视化图形界面

JavaScript语言和Java语言是相关的,但它们之间的联系并不像想象中的那样紧密。

二者的区别体现在:

首先,它们是两个公司开发的不同的两个产品,Java是SUN公司推出的新一代面向对象的程序设计语言,特别适合于Internet应用程序开发;而JavaScript是Netscape公司的产品,其目的是为了扩展Netscape Navigator功能,而开发的一种可以嵌入Web页面中的基于对象和事件驱动的解释性语言。

其次,JavaScript是基于对象的,而Java是面向对象的,即Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象。JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。它是一种基于对象和事件驱动的编程语言。因而它本身提供了非常丰富的内部对象供设计人员使用。

第三,两种语言在其浏览器中所执行的方式不一样。Java的源代码在传递到客户端执行之前,必须经过编译,因而客户端上必须具有相应平台上的仿真器或解释器,它可以通过编译器或解释器实现独立于某个特定的平台编译代码的束缚。JavaScript是一种解释性编程语言,其源代码在发往客户端执行之前不需经过编译,而是将文本格式的字符代码发送给客户,由浏览器解释执行。

第四,两种语言所采取的变量是不一样的。Java采用强类型变量检查,即所有变量在编译之前必须作声明。JavaScript中变量声明,采用其弱类型。即变量在使用前不需作声明,而是解释器在运行时检查其数据类型。

第五,代码格式不一样。Java是一种与HTML无关的格式,必须通过像HTML中引用外媒体那么进行装载,其代码以字节代码的形式保存在独立的文档中。JavaScript的代码是一种文本字符格式,可以直接嵌入HTML文档中,并且可动态装载。编写HTML文档就像编辑文本文件一样方便。

第六,嵌入方式不一样。在HTML文档中,两种编程语言的标识不同,JavaScript使用 <script>...</script>来标识,而Java使用<applet>... </applet>来标识。

第七,静态绑定和动态绑定。Java采用静态联编,即Java的对象引用必须在编译时的进行,以使编译器能够实现强类型检查。JavaScript采用动态联编,即JavaScript的对象引用在运行时进行检查,如不经编译则就无法实现对象引用的检查。

首先你没理解好javascript,Javascript的一个重要功能就是基于对象的功能,通过基于对象的程序设计,可以用更直观、模块化和可重复使用的方式进行程序开发。开发目的是为了可以嵌入Web页面中的基于对象和事件驱动的解释性语言, 并非面向对象。

因为javascript是弱类型语言,所以没有那些成熟的语言那么拘谨,约束不多,反而让它强大,为什么有很多非常聪明的编程人员喜欢研究、开发javascript架包的原因。

因为javascript是弱类型语言.不像c++,C#,java这类型语言!他不支持函数方法重载.你之前写一个方法.后面再写一个相同名字的方法他默认会把上一个方法覆盖掉!这种情况和PHP中相同!

他不像是高等语言支持函数重载.根据不同的参数.返回值调用不同的方法!

他也可以写成类,方法,属性.但是和其它的语言稍有不同!比如

var cls={

my:{a:0},

init:function()

{

alert(this.my.a)

}

}

window.onload=function()

{

cls.init()

}

调用cls.init()

这就是他的类,但是缺少了好多面向对象的一些特性

当然要做到继承还是有可能,那就是通过原型,但是费尽心思去实现了继承,可是还不能说它是面向对象,而面向对象可以很容易做到封装、多态性和继承