`
fantaxy025025
  • 浏览: 1247346 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
阅读更多

原来老是轻视js等前台技术,现在发现付出了很惨重的代价。

不得不学习:JavaScript

 

学习方法:

1. 看书《JavaScript高级程序设计》

2. 练习基本

3. 看博文提高认识深度

4. 看源码提高

5. 做,这是程序人的本

6. 学习框架

 

----------------------------------------------------------

学习总结 js知识

----------------------------------------------------------

 

http://blog.csdn.net/liu251/archive/2009/05/04/4150010.aspx

本文里讲述的是关于JavaScriptprototype 问题,至于具体的JavaScript 面向对象的编程教程,请各位看客到其他网站搜索一下,或者到这里看看。

首先开始一个例子,如下:

1 function A() {
2     this.t1 = "ffffff";
3     this.t2 = function (msg) {
4         alert(msg);
5     };
6 };
7
8 A.prototype.p1 = "xxxx";
9
10 A.prototype.f1 = function () {
11      do something.
12 };
其实p1,f1 是对functionprototype 对象的操作,大家要明白,function
也是一个对象,对象也有属性,而prototype 就是function 的属性,该属性
也是一个对象,
不同之处是,function 在做为类定义的时候,创建类实例的
过程(new 的过程)要参照它的prototype 对象,把prototype 对象的所有
属性(也就是Java 里的成员,包括成员变量和成员函数)都复制到新的对象
中去,所以可以看出prototype 就是模板 ,而这个模板是在new 一个对象之
前就已经存在了。

上面的JavaScript 就好像在定义一个Java 类,书写类的时候,除了用不同的声明
ClassFunction )区别,基本没有其他的区别,但在运行时有很大的区别。
首先Java 要求类必须被编译成字节码才能被载入虚拟机,而JavaScript 是在运行
代码的同时,执行了类似Java 的编译载入的过程。并且Java 的类在载入虚拟机
后一般就不能再改变类的定义了,比如把一个方法的行为改变或指向另一个方
法的引用等。而JavaScript 在运行期还可以通过prototype 来改变类及所有该类生成
的对象的行为。例如上面的例子中,在解析完function A 的函数体后,整个类也
就生成了,这时候如果new 的话就能得到类的实例,紧接着的代码又向类动态
添加了新的行为。

而在function A 的函数体内定义的this 成员,可以理解为 绑定成员。
可以这么理解,在new A() 的时候JavaScript 建立了一个临时对象,
A.prototype 的所有成员复制到临时对象中,然后再把函数A
定义的this 成员也绑定到临时对象中,然后把临时对象返回给用户。

下面是模拟JavaScriptnew 关键字的处理伪过程:

// 建立临时对象
var tobj = {};
//
复制prototype
for (var key in A.prototype)
tobj[key] = A.prototype[key];
//
绑定函数体内的this 成员(这个过程是JavaScript 的内部处理,没有办法模拟)
return tobj to user;

之所以存在function 内部定义的this 成员,以及prototype 的成员是
有原因的。由于JavaScript 的类在构造时是可以传递构造参数的,
所以,this 成员的行为可能由于参数的不同而不同。这也就是需要后
绑定的原因了。在看下一个例子:

1 function AA(val1,val2) {
2     this.test1 = function() {
3         alert(val1);
4     };
5
6     this.test2 = val2 ? function () { return this.test1;} : function () { return 456; };
7
8     this.test3 = val1 ? val1 : function () {alert("no val1");};
9 }
这个例子很好的说明了后绑定的实际使用价值,所以后绑定对于成员
函数来说是非常有用的,对于成员变量来说其实没什么实际用处。
唯一不同的是,this 成员在每次new 对象时都要被JavaScript 引擎解析,
原因很简单,根据不同的构造参数,使它们在运行期的行为可能有很大
的不同。而prototype 的成员就不会每次都解析,第一次定义prototype
成员时才解析,以后可以直接引用prototype 成员,并且更改了prototype
成员,所有已经建立的实例对象的相应成员都会被更改。

在运行期可以通过' 对象名. 成员名' 来更改成员,这种方式可以更改this 成员
prototype 成员的默认定义,但是更改只限于自身对象,因为JavaScript
Java 一样,也是传值,对象的引用也是一个地址值,所以new 一个对象后,
prototype
的成员也被复制到那个对象上了,再更改那个对象的成员,只会
影响那个对象自身,其他从同一个类new 出来的对象都不会有任何变化。

不能通过运行期设置'.prototype. 成员名' 来覆盖this 同名成员,这样做没有
任何效果。

通过复制一个对象的所有属性到一个新对象,是不能通过修改prototype 成员
来修改新对象的成员行为,因为新对象不是通过原来对象的类new 出来的。
通常的复制方法如下:

1 var tobj = {};
2 for (var key in otherObj)
3     tobj[key] = otherObj[key];
看似tobjotherObj 的行为是一致的,他们不是一个类new 出来的。
一个很好的办法可以测试,比如otherObjAnew 出来的,
可以通过使用 (tobj instanceof A) 来测试,结果显然是false

最新的测试表明,这种复制方法可以复制所有自定义方法,
但是系统提供的默认方法是不能被复制的,即使你显式的覆盖了
系统默认提供的方法,如toString 方法等。

最后再谈谈prototypeconstructor 成员,该成员是对一个类的构造
函数的引用,在类定义的初期,如果一个类没有从其他别的类那
里继承,该类的prototype.constructor 属性保存的是该类自身的引用,
如果该类从别的类继承,那么它的constructor 属性就保存了父类的
constructor
引用,一般constructor 没有什么用处,但可以通过它来取
得他的类的信息,就像Java 里的对象都有getClass() 方法,constructor
就是干这个用的。有它的好处是,再运行期可以改变所有同类对象
的成员行为,如:

1 someObj.constructor.prototype.somePrototype = function () {
2 other process .
3 }
因此好的习惯是在继承之后把prototypeconstructor 成员设置一下,
否则会把父类的prototype 成员改掉,那样程序的行为就不可预知了。
如:

1 function classA() {
2
3 }
4
5 classB.prototype = new classA();
6 classB.prototype.constructor = classB;
7
我要说的关于JavaScriptprototype 属性就这么多,大家多提意见多交流。

-----------------------------------------------------------------------

http://hi.baidu.com/216syy/blog/item/220183c4f97583ac8226ac2b.html

本文着重解析javascript 类继承机制,让你从底层了解javascript 是怎样实现 继承 这一概念的。

   目前 javascript 的实现继承方式并不是通过 “extend” 关键字来实现的,而是通过 constructor function prototype 属性来实现继承。首先我们创建一个animal

js 代码

  1. var animal = function (){  // 这就是constructor function
  2.    this .name = 'pipi';    
  3.    this .age = 10;      
  4.    this .height = 0;      
  5. }      
  6. // 建立一个动物的实例     
  7. var a1 =  new animal ();   


构造函数与其他普通函数区别在于,1. 构造函数里有 this 关键字,2. 调用构造函数是使用的new 关键字。通过new 运算符调用构造函数animal 后,系统就会返回一个对象,这个对象就相当于

js 代码

  1. var a1 = { name:'pipi' ,age:10,height:0 }  
  2.   
  3. // 或者   
  4. var a1 = new Object();  
  5. a1.name='pipi';  
  6. a1.age = 10;  
  7. a1.height = 0;

等同这样的方式来产生js 对象。

到这里我们知道如何在js 中定义一个类了,接下来我们展示如何写一个cat

js 代码

  1. var cat = function (){    
  2. this .play = function (){     
  3. alert('cat play')    
  4. }    
  5. }    
  6. cat .prototype = new animal (); //lijg prototype 拥有了animal 的所有属性包括prototype 属性和this 属性
  7. //prototype 属性指向一个对象
  8. var c1 = new cat();


到这里,cat 就继承了 animal 对象,类cat 的一个实例对象c1 拥有属性name,age,height, 和方法play 了。
那么prototype 起到了一个什么样的作用呢?
prototype
就好比一个指针,它指向一个object ,这个object 就称为子类对象的原型。当cat 的对象被创建的时候,由于cat 的构造函数拥有prototype 属性,那么cat 的实例就会间接指向这个原型对象了(说成间接的是因为每个object 都有一个constructor 属性指向它的构造函数)。
那么问题来了, 当我们修改对象 c1 name 属性的时候,会不会修改它prototypename 属性值呢? ,答案是否定的。
接下来详细解析:
1.
访问name 属性: 首先当我们第一次访问c1.name 的属性的时候,我们会得到值“pipi” ,这个和我们预料中的一样。但是计算过程你未必知道。
它计算的过程是这样的:

第一步:

检查c1 对象中是否有name 属性, 找到的话就返回值,没有就跳到第二步,显然没有找到,因为cat 的构造函数中没有定义。

第二步:

当第一步没有找时,去间接访问prototype 对象所指向的object ,如果在prototype 对象中找到的name 属性的话,就返回找到的属性值。如果还是没有找到的话,再去递归地寻找prototype 对象的prototype 对象(去找它的爷爷),一直到找到name 属性或者没有prototype 对象为止。如果到最后还是没有找到name 属性的话就返回undefined

2.
设定name 属性:当我们设定c1 对象的name 属性时,及调用 c1.name= ' new name'; 这个过程就简单多了。首先检查是否对象已有该属性,若已存在则修改当前值,若不存在则为该对象新增一个属性并设定当前值。值得一提的是,在设定值的过程中 没有去访问prototype 属性。

为了加深理解,我们再看一个 read-write-read 的过程,第一次read 的时候,由于自己的对象没有name 属性,那么就会返回的原型对象的name 属性的值。第二步,写入name 的值,同样没发现本身 对象有name 属性, 那么就在本身对象上新建一个name 属性,然后赋值。第三步,再次读取name 属性,由于在第二步中已经新建了name 属性,此时就 返回在第二步中设定的值。值得一提的是,在这三步中没有改变原型对象的值。

好了,到此详细分析了 javascript 对象是如果实现继承的,其实和其他的面向对象语言不一样的是,javascript 的继承机制是对象的原型继承而不是类型继承。

呵呵,欢迎看完,有不对的地方欢迎大家讨论!

========================================================================

-----------------------------------------------------------------------

本人简要总结fantaxy

 

1. 一切都是对象

       一切都是对象,方法也是对象,对象的属性也是一个对象,这个对象也可以有属性和方法

 

2. new 的过程

1 new A() 的时候 JavaScript 建立了一个临时对象,这个临时对象就是 this

2 A.prototype 的所有成员复制到临时对象中,

3 然后再把函数 A 中定义的 this 成员也绑定到临时对象中,

4 然后把临时对象返回给用户。

var anObject = new aFunction() 形式创建对象的过程实际上可以分为三步:

第一步是建立一个新对象;

第二步将该对象内置的原型对象设置为构造函数 prototype 引用的那个原型对象;

第三步就是将该对象作为 this 参数调用构造函数,完成成员设置等初始化工作。

对象建立之后,对象上的任何访问和操作都只与对象自身及其原型链上的那串对象 有关,与构造函数再扯不上关系了。换句话说,构造函数只是在创建对象时起到介绍原型对象和初始化对象两个作用。

 

3. 通过 prototype 实现继承

1 js 中继承,是通过 prototype 来实现的, prototye 就像一个继承的管道一样,所有要继承的东西都要通过 prototype 这个管道遗传下去。

2 )顺序上是先继承 prototype 的属性,之后再绑定 this 成员,因此后面绑定的 this 成员可能盖掉 prototype 遗传管道遗传过来的属性值。

3 prototype 遗传过来的属性是通过复制而来的,即传值的。这样的话,如果是成员函数,不会有问题;如果是基本变量不会有问题;但如果是对象 obj ,复制的是对象 obj 的地址,这样所有 new 出来的变量,都指向同一个地址,这样造成的问题是如果一个对象改变了 obj 的值,其他的对象的 obj 的值也改变了。

4 )用 prototype 遗传管道一般只用来遗传成员方法,而不遗传成员变量,原因是( 3

5 )继承具有可覆盖性,这个跟 java 等一样, this 的属性将覆盖掉 prototype 遗传的属性

原理:

JavaScript 中, prototype 不但能让对象共享自己财富,而且 prototype 还有寻根问祖的天性,从而使得先辈们的遗产可以代代相 传。当从一个对象那里读取属性或调用方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的 prototype 对象那里寻找;如果 prototype 没有,又会去 prototype 自己关联的前辈 prototype 那里寻找,直到找到或追溯过程结束为止。

JavaScript 内部,对象的属性和方法追溯机制是通过所谓的 prototype 链来实现的。当用 new 操作符构造对象时,也会同时将构造函数的 prototype 对象指派给新创建的对象,成为该对象内置的原型对象。对象内置的原型对象应该是对外不可见的,尽管有些浏览器 ( Firefox) 可以 让我们访问这个内置原型对象,但并不建议这样做。内置的原型对象本身也是对象,也有自己关联的原型对象,这样就形成了所谓的原型链。

对象可以掩盖原型对象的那些属性和方法,一个构造函数原型对象也可以掩盖上层构造函数原型对象既有的属性和方法。这种掩盖其实只是在对象自己身上创建了新 的属性和方法,只不过这些属性和方法与原型对象的那些同名而已。 JavaScript 就是用这简单的掩盖机制实现了对象的 多态 性,与静态对象语言的虚 函数和重载 (override) 概念不谋而合。

(6) 原型传递给子类的东西究竟有哪些?

1. 给子类 prototype 的东西(复制原理如:( 3 )所述)

2. 给子类非 prototype 的东西,即 this 的东西,给的是完全副本,即使是对象也是给完全副本而非引用地址的副本(见例 2

原型模型需要一个构造函数来定义对象的成员,而方法却依附在该构造函数的原型上。大致写法如下:
//
定义构造函数
function Person(name)
{
this.name = name; //
在构造函数中定义成员
};
//
方法定义到构造函数的 prototype
Person.prototype.SayHello = function()
{
alert("Hello, I'm " + this.name);
};
//
子类构造函数
function Employee(name, salary)
{
Person.call(this, name); //
调用上层构造函数
this.salary = salary; //
扩展的成员
};
//
子类构造函数首先需要用上层构造函数来建立 prototype 对象,实现继承的概念
Employee.prototype = new Person() //
只需要其 prototype 的方法,此对象的成员没有任何意义!

//lijg: 但最终还是给子类了 , 给子类的是完全复制的一个副本,而非引用地址,不论 this.xxx 是基本类型还是对象,还是

属性方法

// 子类方法也定义到构造函数之上
Employee.prototype.ShowMeTheMoney = function()
{
alert(this.name + " $" + this.salary);
};
var BillGates = new Person("Bill Gates");
BillGates.SayHello();
var SteveJobs = new Employee("Steve Jobs", 1234);
SteveJobs.SayHello();
SteveJobs.ShowMeTheMoney();

原型类模型虽然不能模拟真正的私有变量,而且也要分两部分来定义类,显得不怎么 优雅 。不过,对象间的方法是共享的,不会遇到垃圾回收问题,而且性能优于 闭包 模型。正所谓 有失必有得 嘛。

在原型模型中,为了实现类继承,必须首先将子类构造函数的 prototype 设置为一个父类的对象实例。创建这个父类对象实例的目的就是为了构成原型链, 以起到共享上层原型方法作用。但创建这个实例对象时,上层构造函数也会给它设置对象成员,这些对象成员对于继承来说是没有意义的。 虽然,我们也没有给构造 函数传递参数,但确实创建了若干没有用的成员,尽管其值是 undefined ,这也是一种浪费啊。

(见例 2 author lijg

                     function ParentA(){

                            this.a = "a";

                            this.b = "b";

                            this.arr = new Array("xxx", "yyy");

                     }

                     ParentA.prototype.sayHello = function(){

                            alert("a:" + this.a + ", b:" + this.b + ", arr:" + this.arr.toString() + ", arr2:" + this.arr2.toString() );

                     }

                     ParentA.prototype.arr2 = new Array("ooo", "ppp");

                     function ChildA(){

                            //

                     }

                     ChildA.prototype = new ParentA();

                    

                     var p1 = new ParentA();

                     p1.sayHello();//OUT: a:a, b:b, arr:xxx,yyy, arr2:ooo,ppp

                    

                     p1.arr.push("zzz");

                     p1.arr2.push("qqq");

                     p1.sayHello();//OUT: a:a, b:b, arr:xxx,yyy,zzz, arr2:ooo,ppp,qqq

                    

                     var c1 = new ChildA();// 给的是个副本

                     c1.sayHello();//OUT: a:a, b:b, arr:xxx,yyy, arr2:ooo,ppp,qqq

 

4. this 成员、 prototype 成员的区别与后绑定

之所以存在 function 内部定义的 this 成员,以及 prototype 的成员是有原因的。由于 JavaScript 的类在构造时是可以传递构造参数的,所以, this 成员的行为可能由于参数的不同而不同。这也就是需要后绑定的原因了。

5 prototype 的属性就是这个对象的属性,可以直接用,如 obj.functionA(); ,无需这样: obj.prototype.functionA(); 把这些属性放入遗传管道的唯一目的是遗传

 

5. prototype constructor 成员

prototype constructor 成员,该成员是对一个类的构造函数的引用,在类定义的初期,如果一个类没有从其他别的类那里继承,该类的 prototype.constructor 属性保存的是该类自身的引用,如果该类从别的类继承,那么它的 constructor 属性就保存了父类的 constructor 引用,一般 constructor 没有什么用处,但可以通过它来取得他的类的信息,就像 Java 里的对象都有 getClass() 方法, constructor 就是干这个用的。有它的好处是,再运行期可以改变所有同类对象的成员行为,如:

1 someObj.constructor.prototype.somePrototype = function () {
2     other process .
3 }
因此好的习惯是在继承之后把 prototype constructor 成员设置一下,否则会把父类的 prototype 成员改掉,那样程序的行为就不可预知了。
<!-- [if !supportLineBreakNewLine]-->
<!-- [endif]-->

6. 混合构造函数

用构造函数定义所有非函数属性

prototype 定义多有函数属性

 

7. 为什么通过 prototype 链继承时,父类构造函数不能有参数

js 代码

<!-- [if !supportLists]-->9.      <!-- [endif]-->var cat = function (){    

<!-- [if !supportLists]-->10.   <!-- [endif]-->this .play = function (){     

<!-- [if !supportLists]-->11.   <!-- [endif]-->alert('cat play')    

<!-- [if !supportLists]-->12.   <!-- [endif]-->}    

<!-- [if !supportLists]-->13.   <!-- [endif]-->}    

<!-- [if !supportLists]-->14.   <!-- [endif]-->cat .prototype = new animal (); //lijg prototype 拥有了animal 的所有属性包括prototype 属性和this 属性

<!-- [if !supportLists]-->15.   <!-- [endif]-->//prototype 属性指向一个对象

<!-- [if !supportLists]-->16.   <!-- [endif]-->var c1 = new cat();

如果 14 行中的父类 animal 有参数,那么子类继承的时候怎么办呢?没法在实例化之前就指定参数,这些参数是后绑定的。

 

8. 混合继承方式

1 )用对对象冒充继承父类构造函数的属性值

2 )用 prototype 继承父类的属性方法

其中( 1 )用到的冒充机制常用:

function ParentA(pa1, pa2){

       //

}

 

function ChildA(pa1, pa2, c1, c2){

       ParentA.call(this, pa1, pa2);

       this.c1 = c1;

       this.c2 = c2;

}

ChildA.prototype = new ParentA();

 

9. 继承与聚合

在面向对象中,往往继承不如聚合更合理

function ParentA(pa1, pa2){

       //

}

 

function ChildA(pa1, pa2, c1, c2){

       this.base = Parent;//lijg: 相当于给 Parent 起了个别名,注意此处没有 new

                   // 这实际是:把一个对象赋给了 ChildA 的一个属性

                   // 注意区别: this.base = new Parent; 等价于: this.base = new Parent();

       if(pa1 && pa2) this.base(pa1, pa2);

       this.c1 = c1;

       this.c2 = c2;

}

ChildA.prototype = new ParentA();

 

10. 请仔细看下面博文

http://sqcwfiu.iteye.com/blog/270036

http://www.cnblogs.com/leadzen/archive/2008/02/25/1073404.html

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics