ECMAScript可以识别两种类型的对象,一种叫做Native Object属于语言范畴;一种叫做Host Object,由运行环境提供例如document对象, Dom Node等 Native objects是一种松散的结构并且可以动态的增加属性(property),所有的属性都有一个名字和一个值,这个值可以是另一个对象的引用 或者是内建的数据类型(String, Number, Boolean, Null 或者 Undefined) 下面的这个简单的例子描述了一个javascript对象是如何设置一个属性的值和如何读取属性的值的。
赋值操作 一个对象的属性的创建非常简单,直接通过赋值操作就可以完成属性的创建。
代码 var objectRef = new Object(); //create a generic javascript object.
一个名为testNumber的属性可以这样创建。
代码 objectRef.testNumber = 5; /* - or:- */ objectRef["testNumber"] = 5;
如果复制的属性名称已经存在那么不会再次创建这个属性,赋值操作仅仅是重新设置属性的值
代码 objectRef.testNumber = 8; /* - or:- */ objectRef["testNumber"] = 8;
js对象的原型(prototype)自己本身也可以是对象,也可以有属性(property),对于js对象的(prototype)的赋值操作跟普通对象属性的创建 没什么不同。
取值操作 在取值操作中property和prototype就不一样了,先看最简单的property取值操作。
代码 /*为一个对象的属性赋值,如果这个对象没有这个属性,那么在赋值操作后,这个对象就有这个属性了 */ objectRef.testNumber = 8; /* 读出这个属性的值 */ var val = objectRef.testNumber; /* 现在val 就得到了刚才赋予objectRef的值8了*/
prototype揭密
但是所有的对象都可以有prototypes, prototypes自己也是对象,那么他也可以有prototypes,这样循环下去就形成了一个prototype链, 这个链当他遇到链中队形的prototype是null时中止。(Object的默认的prototype是null)
代码 var objectRef = new Object(); //create a generic javascript object.
创建一个新的js对象,这时这个对象的prototype是Null,所以objectRef的prototype链只包含一个对象Object.prototype 我们在看下面的代码
代码 /* 构建MyObject1这个类型的构造函数 MyObject1 - type. */ function MyObject1(formalParameter){ /* 为者对象创建一个属性名字叫testNumber */ this.testNumber = formalParameter; } /* 构建MyObject2这个类型的构造函数 MyObject2 - type:- */ function MyObject2(formalParameter){ /* 为者对象创建一个属性名字叫testString*/ this.testString = formalParameter; } /* 下一步的操作会用MyObject1对象替换掉MyObject2默认的prototype属性*/ MyObject2.prototype = new MyObject1( 8 ); /* 最后我们创建MyObject2类型的一个对象*/ var objectRef = new MyObject2( "String_Value" );
objectRef这个MyObject2类型的对象有一个prototype的链,链中的第一个对象是MyObject1对象,MyObject1对象也有prototype, 这个prototype是Object默认的prototype,Object.prototype的prototype是null,至此这条prototype链结束。 当一个取值操作发生时,objectRef 的整个prototype链就开始工作
代码 var val = objectRef.testString;
objectRef这个对象的有一个属性叫做testString,那么这句代码会把testString的值赋给val
代码 var val = objectRef.testNumber;
在objectRef这个对象里并没有testNumber这个属性,但是val却的到了值8,而不是undefine,这是因为解释器在没有在当前对象找到要找 的属性后,就会去检查这个对象的prototype,objectRef的prototype是MyObject1对象,这个对象有testNumber这个属性,所以val得到8这个值。
代码 var val = objectRef.toString;
现在val是个function的引用,这个function是Object.prototype的property,由于MyObject1和MyObject2都没有定义toString这个property 所以Object.prototype返回。
代码 var val = objectRef.madeUpProperty;
最后val是undefined,因为MyObject1和MyObject2,还有Object都没有定义madeUpProperty这个property,所以得到的是undefine. 读操作会读取在obj自己和prototype 链上发现的第一个同名属性值 写操作会为obj对象本身创建一个同名属性(如果这个属性名不存在 这就意味着objectRef.testNumber = 3会在objectRef对象上创建一个property,名字是testNumber,当下一次在要读取testNumber时 propertype链就不会工作,仅仅会得到objectRef的property 3,而MyObject1的testNumber属性并不会被修改。下面的代码可以验证
代码 /* 构建MyObject1这个类型的构造函数 MyObject1 - type. */ function MyObject1(formalParameter){ /* 为者对象创建一个属性名字叫testNumber */ this.testNumber = formalParameter; } /* 构建MyObject2这个类型的构造函数 MyObject2 - type:- */ function MyObject2(formalParameter){ /* 为者对象创建一个属性名字叫testString*/ this.testString = formalParameter; } /* 下一步的操作会用MyObject1对象替换掉MyObject2默认的prototype属性*/ var obj1 = new MyObject1( 8 ); MyObject2.prototype = obj1; /* 最后我们创建MyObject2类型的一个对象*/ var objectRef = new MyObject2( "String_Value" ); alert(objectRef.testNumber); objectRef.testNumber = 5; alert(objectRef.testNumber); alert(obj1.testNumber);
URL:http://
Class - 类创建 Class类实现了在JavaScript中声明一个新的类, 并通过构造函数实例化这个类的机制。通过使用Class.create()方法, 你实际上声明了一个新的类, 并定义了一个initialize()方法作为构造函数, 一旦你在这个声明的类的prototype中实现了改该方法, 你就可以使用new操作符来创建并实例化一个类。
Knowledge Prepare - 知识准备 在JavaScript中, 当你定义了一个新的函数, 你实际上声明了一个新的类, 而这个函数本身就相当于类的构造函数。 下面的代码向你展示了两种不同的方式来创建一个新的Person类, 而Person.prototype的定义也紧跟在函数定义之后。
var Person = function(name) { // 一个匿名函数, 并将这个函数赋值给一个Person变量, 此时Person成为一个类 this.name = name;}function Person(name) { // 直接定义一个叫做Person的函数表示Person类 this.name = name;}Person.prototype = { // 定义Person的prototype域 printName: function() { // 定义一个print函数 alert(this.name); }}
当你通过函数的方式声明了一个类之后, 你就可以通过new操作符来实例化这个类。这样, 你就可以调用类的成员函数来完成你的逻辑。
var person = new Person("Joe Smith"); // 使用new操作符来新建一个Person的实例, 并赋给变量personperson.printName(); // person就可以看作是一个实例的引用(reference), 所以可以通过这个引用来调用Person类中的成员函数
我们来总结一下创建一个新的类的实例的整个流程和步骤:
1. 通过定义一个函数的方式(匿名或者实名)来声明一个新的类. 2. 如果有必要, 定义这个新的类的prototype域. 3. 使用new操作符紧跟你所定义的函数来创建一个新的类的实例. 一旦JavaScript编译器碰到了new操作符, 它实际上创建了一个空的类实例变量. 4. 将所有这个类的prototype域中的属性与方法复制到这个新的实例中, 并将其成员函数中所有的this指针指向这个新创建的实例. 5. 接下来, 执行紧跟在new操作符后面的那个函数. 6. 当你执行这个函数时, 如果你试图对一个不存在的属性进行赋值, JavaScript编译器将自动为你在这个实例范围内新创建这个属性. 7. 函数执行完毕后, 将这个初始化完成的实例返回.
在Prototype中, 使用Class对象, 你可以以一个比较简单的方式来声明一个新的对象。通过使用Class.create(), prototype为你创建了一个默认的构造函数initialize(), 一旦你实现这一函数, 就可以以一个类似Java中构造函数的方式来创建一个新的类的实例。
Source View - 源码解析 var Class = { // 全局静态类, 用于声明一个新的类并提供构造函数支持 create: function() { return function() { // 返回一个函数, 代表着这个新声明的类的构造函数 // 一个命名为initialize的函数将被这个类实现作为类的构造函数 this.initialize.apply(this, arguments);// initialize函数将在你实例化一个变量的时候被调用执行(即上面7个步骤中的第5步) } }}
Field & Function Reference - 属性方法一览 Class ( 静态 ) Method / Property Kind Arguments Description create() 静态方法 / 用于声明一个新的类并提供了一个名为initialize构造函数支持
Analysis & Usage - 分析与使用 通过Class类, 你可以很容易地使用构造函数的方式创建一个新的类, 这对于Java程序员来说或许更加容易被接受。下面我们列出了Java和JavaScript各自声明和创建一个新的类的代码对比, 我们可以看到, 他们是如此相似:
var Person = Class.create(); // 类的声明 |public class Person { // 类的声明Person.prototype = { | private String name; initialize: function(name) { // 构造函数 | public Person(String name){ // 构造函数 this.name = name; | this.name = name; } | } printName: function() { // 成员函数 | public void printName(){ // 成员函数 alert(this.name); | System.out.println(name); } | }} |}var person = new Person("Joe Smith");// 创建实例 |Person person = new Person("Joe Smith");// 创建实例person.printName(); // 函数调用 |person.printName(); // 函数调用
URL:http://bencode.javaeye.com/blog/57760
从 prototype.js 深入学习 javascript 的面向对象特性
js是一门很强大的语言,灵活,方便。 目前我接触到的语言当中,从语法角度上讲,只有 Ruby 比它更爽。
不过我接触的动态语言只有: js ruby python flash的as 简单的几门, 应该算是井底之蛙之见。
js 语法成分简单,没有 ruby 语言复杂。所以有时候我觉得她更干净(Ruby Fans 不要攻击我哦,我也是很爱很爱很爱Ruby的)!
prototype.js 无疑是 js的漂亮之作,从它身上应该可以学到一些东西。
如果你用 js 在页面仅仅能写出 if, alert等简单的验证代码,或者想多了解一下Js, 那么此文可能对你有帮助。
好了,开始吧。
现在我突然想起了 Thinking in java 中的 "一切皆是对像", 其实我觉得这句话 有点不适合 java 反倒是更适合 js
1.怎样构造(初始化)对象?
js 代码 var Prototype = { Version: '1.5.0_rc1', ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', emptyFunction: function() {}, K: function(x) {return x} } 就这样,初始化了一个对象(名字就叫 Prototype),以及对象的四个成员: Version, ScriptFragment, emptyFunction, K
我们也来试试:
js 代码 var bbs = { name: 'JavaEye', version: '2.0', describe: "做最棒的软件开发交流区", sayHello: function() { alert("hello, i'm javaeye! ") } } 于是你可以这样使用: bbs.name 或 bbs.sayHello()
看到吗? sayHello 是一个方法哦,不要惊慌,"一切都是对象",所以它和 name 是一样的,只不过初始化,或定义的语法不一样。想起 js 中的正则表达式中的那两个杆杆了吗? 可爱吧!
方法是对象,所以它可以被当作参数传递,或者作为方法的返回值。
所以 Prototype 中有一个 Version 属性,还有一个匹配 script 的正则式字符串, 一个空方法emptyFunction,还有一个方法 K, 它仅仅返回参数。
没问题吧,继续!
2. 构造函数?
先让我们写段代码吧(中学时,我语文极差(大学没语文了),我想写代码让你们明白我心里真实的想法):
js 代码 var Person = function(name) { // 这里 Person 是一个方法
this.name = name; } var bencode = new Persion("bencode"); // 这里像Java吧!
alert(bencode.name); 先看结果: 从 alert(bencode.name); 可以知道,bencode是对象, 而 name 就是 bencode 的属性, 它被正确地初始化为 "bencode"
所以 var bencode = new Persion("bencode"); 就是构造了一个新的对象,Person() 相当于构造函数
所以 new 这个关键字, 就是构造一个新的对象,并且在这个对象上调用相应的方法,并将这个对象返回。
按上面说: 方法 如果用在 在 new 后面,就相当于成了构造函数了。
话又说回来了, 如果 var bencode = new Persion("bencode") 是 构造了一个对象,像Java, 那么 Person 是不是类呢? 可是 Person 不是方法吗? 可是方法不也是对象吗? 类也是对象?
一切皆对象?
本来无一物!
好了,看 prototype.js吧
js 代码 var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } 初始化一个 Class 对象, 它有一个成员,是一个方法, 这个方法返因另一个方法(方法是对象,所以可以作为参数或者返回值)
所以如果我们这么做:
js 代码 var A = Class.create(); // 此时 A 是一个方法,方法体,下面解释
var a = new A(...); // 对方法使用 new 操作符,就是构造一个新的对象,然后在这个对象上调用这个方法( 现在是 A)
上面分析说? A相当于类, 哈哈 Class.create(); // 终于名副其实
var a = new A(...); // 也是相当地直观, 就是构造一个新的对象,类型 是A
new 操作符构造了对象,并调用了 方法, 这个方法到底做了什么呢? 也就是上面没有分析的东东,看看先:
js 代码 var Class = { create: function() { return function() { // 见[1]
this.initialize.apply(this, arguments); // 见[2]
} } } [1]. new 操作符,就会在新产生的对象上调用这个方法 [2]. 哦? 这里就是调用 this 对象上的 initialize方法, 并传递 arguments 换句话说,就是把构造的任务委托给 initialize 方法 initialize? 哪里来? 见下面,类的扩展(继承) 3. prototype?
看段老代码:
js 代码 var Person = function(name) { this.name = name; } var bencode = new Person("bencode"); bencode不是一个自闭的人,他应该可以向javaeye介绍一下自己。 像这样:
js 代码 bencode.sayHello();
假如不能实现以上功能的话, 上面的 new,上面所有的东东都等于垃圾。
所以。需要给 Person 类加"实例方法"
题外话: 静态方法如何添加? 看上面的 Class.create, 仅仅是一个对象的成员而已
好, 再来一段 (为了完整性,上面的几句话,再抄一次)
js 代码 var Person = function(name) { this.name = name; } Person.prototype = { // protype 是啥?
sayHello: function() { alert("hi, javaeye, I'm " + this.name); } } var bencode = new Person("bencode"); bencode.sayHello(); 运行代码,通过!
prototype是啥? 请暂时忘记 Prototype(prototype.js) 这个库,名字一样而已!
让我们再从结果上去分析(第一次我们用这种方法分析而得出了 new 的作用),
我们在思考: 要想 bencode.sayHello() 正常运行 bencode 是一个对象, 这是我们已经知道的 sayHello() 应该是 bencode 这个对象的方法才可以 可是bencode 这个对象是 new 操作符产生的, 而 new 此时作用于 Person 这个 "类" 那么, 哦? 那么有两种可能: 1. new 产生的那个新对象是不是就是 Person.prototype 2. Person.prototype 中的成员 将会被 new 操作符添加到 新产生的对象中
再看:
js 代码 Person.prototype = { sayHello: function() { alert("hi, javaeye, I'm " + this.name); // 这里有this
} } this.name, 这里的 this 指什么?所以第一个可能讲不通呀
回忆起这段:
js 代码 var Person = function(name) { this.name = name; } 如果这里的 this 代表着新产生的对象的话。 那么第二种情况就讲得通了, new 将会把 Person.prototype 这个对象的成员放到 这个新对象中。 与当前行为相符。
所以: Person 的 prototype 对象中的 成员, 将会被添加到 新产生的对象 中(我是这样理解的) (不知道 Js解释器是不是开源的, 有空我得去看看,怎么实现的。)
嘿,默认的 prototype 就是 Object 哦!
4. 扩展?继承?
什么是扩展?啥是继承? ! 我从爸爸那得到了什么? 想不通!
还是实际点:
有一个类A, 它有一个 sayHello方法
js 代码 var A = function() { } A.prototype = { sayHello: function() { alert("sayHello A") } } 我想构造一个 B 类,让他继承 A 对象, 这句话太抽象。
其实我们可能想这样:
js 代码 var b = new B(); b.sayHello(); // 调用 A 的 sayHello
这应该是继承的第一层含义(重用)
怎么办到呢?
var B = function() { // 这里是有一个B类了
}
怎么样添加"实例方法"? 快点想起
B.prototype = A.prototype
这样行了吗? 恭喜, 运行通过!
让我们整合一次
js 代码 var A = function() { } A.prototype = { sayHello: function() { alert("sayHello A"); } } var B = function() { } B.prototype = A.prototype; var b = new B(); b.sayHello(); 可是如果 B 是这样呢?
js 代码 var B = function() { } B.prototype = { sayHi: function() { alert("sayHi B"); } } 我们是不是应该将 A.prototype 中的内容添加到 B.prototype 对象中,而不是代替它呢? 当然。
这样才能"扩展"
题外话?多态在哪里? 嘿嘿
好了,足够多了, 那prototype.js 是怎么样"扩展"的呢?
js 代码 Object.extend = function(destination, source) { for (var property in source) { destination[property] = source[property]; } return destination; } 这个只是简单地把 source 的成员, 添加到 destination 对象中嘛, 哪里看得出扩展?
如果我这样呢?
js 代码 var A = function() { } A.prototype = { sayHello: function() { alert("sayHello A") } } var B = function() { } Object.extend(B.prototype, A.prototype); // 先添加父类(A)成员
Object.extend(B.prototype, { // 再添加B类成员, 如果是同名,则覆盖,行为符合 "多态"
sayHi: function() { alert("sayHi B"); } }); 回忆刚才的 Class.create():
js 代码 var Person = Class.create(); var bencode = new Person("bencode"); 刚才说过, 调用 new 时, 将会创建一个新对象,并且调用 Person 方法, Person 方法会委托给 "新产生对象"的 initialize方法
怎么样给新产生对象添加 initialize 方法? 哈哈,轻松
js 代码 Object.extend(Person.prototype, { initialize: function() { this.name = name; } //,
// 下面可以添加其他实例方法。
});
所以, 我们使用 prototype 创建类一般格式是这样的:
js 代码 var ClassName = Class.create(); Object.extend(ClassName.prototype, { initialize: function(...) { // 这就相当于构造函数
} //...
}); 如果我们要继承一个类,只要:
js 代码 var ClassName = Class.create(); Object.extend(ClassName.prototype, SuperClassName.prototype); Object.extend(ClassName.prototype, { initialize: function(...) { } //...
}); 面向对象部分基本上就这样。
本来想再接着写 prototype.js 的源码解读,但一来是因为时间,第二是发现也没有这个必要。
|