标签归档:JavaScript

JavaScript面向对象基础

传统的Web开发模式中,JavaScript一直被当作过程化的语言使用,比如表单验证之类。其实,JavaScript提供了完善的机制来实现面向对象的开发思想,这在Ajax技术上,表现得淋漓尽致。

总结下JavaScript面向对象的基础:(结合了《Web 2.0 开发技术详解》这本书,希望对大家有帮助)

 

1 定义类

用定义函数的方式(即用“function”关键字定义):

function class01 () { //……. }

此处class01是一个函数,也是一个类。作为函数,可以理解为类的构造函数(初始化)。在JavaScript中,函数和类就是一个概念。

 

BTW:函数声明的方法:

(1)function fun1(…)  {…}

(2)var fun1 = function(…) {…};     // 注意无名函数在调用之前,必需先定义

(3)var fun1 = function fun2(…) {…};

(4)var fun1 = new Function(p1, p2, …, pN, body);

 

2 定义对象

1)使用new操作符。– 适用内部类(如Date类,Array类,String类,RegExp,Math,Error,Object)和用户自定义类。

如:

function class01() { // 类成员的定义 }

var obj = new class01();  // 即所有函数都可以用new来操作。

 

e.g:

var obj = new Object();

obj.name = "ljlwill";               // 定义name属性

obj.hello = function(…) {….}    // 定义obj的hello方法

 

有个小技巧,以下大家发现没有

var namespace = new Object();

var namespace.class1 = function() {…..}

var obj1 = new namespace.class1();

>> 对象名起到一个命名空间的作用。先用new出一个namespace对象,把namespace对象的方法定义为类的形式,再new出一个新的obj1

 

2)使用{}大括号创建无类型对象

传统的面向对象语言中,每个对象都会对应到一个类,而JavaScript中的对象,其实就是属性(方法)的一个集合,无严格意义的类的概念。故可用{}的语法创建一个对象。

如:

var user = { name: "ljwill",        // 定义了name属性,初始化为“ljlwill

hobby: ['basketball', 'football', 'ping-pong'],  // 定义了爱好,类型为数组

// 定义hello方法

hello: function() { alert("Hello, " + this.name); },

…… }

可看到形式,其中属性名和其定义之间用:(冒号)隔开,以,(逗号)结尾。很是紧凑,清晰,减少代码体积。

 

3 对象的属性和方法的引用

1) 对象名.属性名(方法名) — 即用.符号引用

2) 对象名["属性(方法)名"]  — 即用[]符号引用

如:

var arr = new Array(); // 为数组添加一个元素a

arr["push"]("a"); arr.push("a");

// 计算数组长度

var len = arr["length"];

var len = arr.length;

用方括号[]的引用对象属性(方法),类似于数组,体现了一个JavaScript对象就是一组属性(方法)的集合这个性质。适用于不确定具体要引用哪个属性(方法)的场合。 在document的集合对象中,也有类似[]的用法,如果引用某一个“myForm"的表单对象:document.forms["myForm"],当然,也可以写成document.forms.myForm。(注意,这里的forms对象是一个内部对象)

 

4 对象的属性和方法的操作

如何为一个对象添加,修改或删除其属性和方法呢?

在一些语言中,要修改一个已生成的对象的属性或方法,必须在对应的类修改,重新实例化,再重新编译。JavaScript却可以灵活的动态添加,修改或删除其属性和方法。

如:先创建一个空对象user:var user = new Object();

1)添加属性。

user.name = "jinlie";   // 为其添加name属性

user.age   = 25;       // 为其添加age属性

user["name"] = "jinle"   // 使用[]

user["age"]   =  "25"

// 可否发现[]方式有个而外特点, 可以使用非标识符字符串作为属性名称,如数字开头或出现,user["007 name"] = "jinlie",如果user.007 name就错误了。

// 这一属性可以很容易实现一个简单的哈希表。在此不详述。 输出试试:alert(user.name);

 

2)添加方法

user.getName = function() { 

     // 可添加参数 return this.name;

} // alert(user.getName());

 

3)修改属性

即用新的属性替换旧的属性

user.name = "hello"; //  测试:alert(user.getName());

 

4)删除属性和方法

将其置为undefined即可。

user.name = undefined;

user.getName = undefined;

 

到此,我们可以感受JavaScript的强大的灵活性。

 

5 prototype原型对象

在JavaScript中,每个函数(function)其实也是一个对象,他们对应的类是“Function”,而每个函数对象都具有一个子对象prototype。所以,prototype表示了该函数的原型,也即是表示一个类的成员的集合。 prototype是一个对象,也可以对其方法进行动态修改:

如:

function class01 { // ….. }

// 对类的prototype对象增加方法

hello class01.prototype.method = function() { alert("Hello Word!"); }

var obj = new class01();

obj.hello();   // 调用hello()方法

 

看个有趣的例子:

// 为所有的Function函数对象添加method1方法

Function.prototype.method1 = function() {

     alert("This is a function.");

}

function func1() { alert("this is func1"); }

func1.method1();                        // 执行了alert("This is a function")

func1.method1.method1();      // 执行了alert("This is a function")

func1.method1.method1()是个递归定义,因为method1本身也是一个函数,便具有了函数对象的属性和方法,所以它调用了method1这个函数对象的method1方法。结论:所有对Function类型的方法扩充都具有这样的递归性质。

 

6 类成员的访问机制

1)公有成员,私有成员

在JavaScript中,并没有特殊的机制(比如用像一些语言中有关键字private,public等)来访问其成员,但可以通过变量的作用域性质来实现这些功能。– 在一函数内部定义的变量称为局部变量,它不可以被函数外边的程序所使用,却可以被其内部定义的嵌套函数所使用。

有思路了吧?如:

function class1() {

var name = 'ljlwill';      // 私有属性

 

// 私有方法

function privateMethod(…) {

   ….

}

 

// 公有方法

this.pubMethod = function(…) {

    ….

}

}

 

// 建以对象obj

var obj = new class1();

obj.pubMethod();

注意,prototype定义的类成员却不可以访问其构造体中定义的局部变量(私有成员)

 

2)静态成员

它可以通过“class.staticMemberName(类名.静态成员名)”访问。

实现:

function class1() {

     ….

}

calss1.staticName = "ljlwil";

class1.staticMethod = function(…) { …. }

 

如果想给所有的对象添加静态成员(比如静态方法):

Function.prototype.staticMethod = function(…) { … }

 

7 类的继承

继承是OOP中很重要的IDEA。很抱歉,JavaScript没有专门的机制(extends)来实现,但还是可以使用以下方式实现继续

1)拷贝一个类的prototype到另外一个类来实现继承。

如:

function class1() {

   …

}

function class2() {

  ..

}

class2.prototype = class1.prototype;    // 这样class2有了其公有类成员的属性或方法

 

下边的语句是成立的:

var obj = new  class2();

obj instanceof class1;     // intanceof 操作符判断一个对象是否是某一类的实例。

obj instanceof class2;

注意:在JavaScript中,除了基本数据类型(数字,字符串,布尔等),所有的赋值或函数传参都是引用传递,所以class2的prototype引用了class2的prototype,如果改变class2的prototype,class2的prototype也随之改变。所以,注意要不允许类成员的重新定义,用prototype实现继承,还是蛮好用的。

 

2)使用发射机制实现正确继承

发射机制指的是程序在运行时能够获取自身的信息。

如:

// 为Object类添加静态方法extend

Object.extend = function(destination, source) {

for(p in source) {

destination[p] = source[p];

}

return destination;

}

 

// 通过Object类为所有对象添加extend方法

Object.prototype.extend = function(object) {

return Object.extend.apply(this, [this, object]);

}

 

// 定义class1

function class1() {…)

 

class1.prototype = {

method1: function(…) {…},

method2: function(…) {….}

}

 

// 定义class2

function class2() {….}

 

// 继承

class2.prototype = (new class1()).extend({         // 不要把new class1()换成class1,这样和prototype实现继承一样的错误哦!

// 重新定义method1

method1: function() {

    ….

}

}

);

 

// 定义对象

var obj1 = new class1();

var obj2 = new class2();

// 试试吧

obj1.method1();

obj1.method2();

obj2.method1();

obj2.method2();

 

8 抽象类

JavaScript的抽象类也是没任何机制支持的。但却还是可以实现。

传统的面向对象语言中,抽象类的概念是,具有虚函数的类。而虚函数指的是,只做了一个声明而未实现的方法。在JavaScript中,虚函数可以看作该类中没有定义的方法,但已经通过this指针使用了(在其他语言中,虚函数必须先声明)。

如:

Object.extend = function(destination, source) {

for(p in source) {

destination[p] = source[p];

}

return destination;

}

 

// 定义一个抽象基类base,无构造函数
function base() {…}

base.prototype = {

initialize: function() {

this.oninit();     // 调用了一个虚方法

}

 

// 如果要在基类中添加虚方法的一个定义,也可以的:

// oninit: function() {}   // 虚方法是一个空方法,由派生类实现

}

 

function class1() {….}

class1.prototype = (new base()).extend({

// 实现抽象类中的oninit虚方法

oninit: function() {

// 实现

}

});

 

好,今天就谈到这,JavaScript一个非常灵活的设计语言。学好基础,看看那些类的设计模式,和一些出名的框架,不禁要;)一下!