介紹JavaScript面向物件
JavaScript中的引用型別
引用型別通常叫做類(class),也就是遇到引用值或者處理的物件。但是從嚴格意義上講JavaScript並不是面向物件的,而是基於物件(object)的。之所以說是基於面向物件的原因是JavaScript中並沒有類似Java中的多型,抽象,過載等面嚮物件語言中的概念。但是JavaScript中定義了"物件定義",在邏輯上等價於其他面嚮物件語言中的"類"的概念。 例如我們可以使用下面的程式碼建立Object物件的一個例項:
var obj = new Object() ;
JavaScript中的物件
在JavaScript中的Object物件類似於Java中的java.lang.Object物件,所有的物件都是由這個物件繼承而來,也即是說Object中的所有屬性和方法都會出現在其他物件中。
1 Object 物件的屬性和方法
- constructor : 對建立物件的函式的引用
- Prototype : 對該物件的物件原型的引用。對於所有的物件,它預設返回 Object 物件的一個例項。
- ToString() : 返回物件的原始字串表示
- ValueOf() : 返回最適合該物件的原始值。對於許多物件,該方法返回的值都與 {{{ToString?() 的返回值相同
- javascript中定義屬性和方法 在javascript中定義屬性和其他語言類似:如下面的例子:
function person(name){ this.setName= function(newName){name = newName}; this.getName= function(){ return name; } } var p = new person("Lily"); p.setName("Lucy"); p.getName();
注: 除了上面的定義方式之外,在js中有一種比較重要的定義物件屬性方法的常見的寫法就是使用JSON物件。定義一個JSON物件,同時定義它的一些屬性和方法。
2 JavaScript中一切都是物件
當我們瞭解了Object類的時候就可以理解為什麼JavaScript中一切都是物件了。我們來看下面的程式碼
<script type="text/javascript"> function car(){} var c = new car() ; /*證明c就是Object*/ alert(c instanceof car) ; alert(car instanceof Function) ; alert(Function instanceof Object) ; /*證明一切都是Object*/ alert(c instanceof Object) ; alert(car instanceof Object) ; alert(Function instanceof Object) ; </script>
上面alert中的內容都是true,那麼也就是我們宣告出來的c就是一個Object,並且所有的一切都是Object。但是這裡就又存在了一個疑問:JavaScript不是基於物件的麼?從上面的例子可以發現類似java中的繼承的概念:c是Object的子類。那這又是怎麼回事呢?
3 JavaScript中內建物件(瞭解即可,這裡就不舉例說明了)
- Global物件:也即window物件,它沒有construct屬性,所以不能用new進行構造,沒有call屬性,所以也無法像函式一樣進行呼叫
- Object物件:它是所有物件的基礎,任何其它物件都是從object物件原型擴充套件而來。如果Object物件使用原型擴充套件了其它屬性,那麼所有物件將都具有此擴充套件屬性
- Function物件:使用function可以定義一個函式,在系統內部進行呼叫
- Error物件:可以在發生錯誤的時候作為引數傳遞給catch子句,也可以使用new關鍵字構造自定義的error物件
繼承機制的實現
現在我們來說明上面提出的疑問:JavaScript是基於面向物件,但是怎麼存在繼承呢?首先我們知道子類將繼承所有父類的公共的屬性和方法,包括構造和方法的實現。同時子類還可以新增父類中不存在的新的屬性和方法,也可以覆蓋父類中的屬性和方法。
在Java中我們可以使用extends輕鬆的實現繼承,JavaScript並沒有提供。但是我們可以模擬繼承,而且在JavaScript中的繼承並非只有一種形式。
1 call()方法
基本用法
<script type="text/javascript">
function sayColor(sPrefix,sSuffix) {
alert(sPrefix + this.color + sSuffix); // 輸出The color is blue,a very nice color.
};
var obj = new Object();
obj.color = "blue";
sayColor.call(obj, "The color is ", ",a very nice color.");
</script>
說明:
- 1. call()方法中的第一個引數用作this物件,其他的引數都是直接傳遞給函式自身。(this並不一定是執行該函式時的真正的this值,如果this的值是null或者是undefined,那麼this就會自動指向全域性變數,如果是瀏覽器,那麼當然是window了。此時this會指向原始值的自動包裝物件)
- 2. sayColor在物件之外定義,顯然它不屬於任何物件,當時也可以使用關鍵字this。因為一個function也是一個物件。(javascript中函式即為物件)
- 3. call()方法中的第一個引數是obj,也就是在sayColor中的this是obj。所以sayColor中的this.color就是blue。
- 4. 另外的兩個引數就是sayColor中的sPrefix和sSuffix。
使用繼承
0. <script type="text/javascript">
1. function ClassA(sColor) {
2. this.color = sColor;
3. console.log(this) ;
4. this.sayColor = function () {
5. alert(this.color);
6. };
7. }
8. function ClassB(sColor, sName) {
9. ClassA.call(this, sColor);
10. this.name = sName;
11. this.sayName = function () {
alert(this.name);
12. };
13. }
14. var objA = new ClassA("blue");
15. var objB = new ClassB("red", "John");
16. objA.sayColor(); //輸出 "blue"
17. objB.sayColor(); //輸出 "red"
18. objB.sayName(); //輸出 "John"
19. </script>
說明:
- 1. objB本身並沒有sayColor函式,這是因為通過call方式繼承而來。在其中第9行的this是ClassB,第3行的this也是ClassB,所以第2行的this.colo就是ClassB中的 color,即red。這一特點和繼承相符合:子類繼承父類的方法,並擁有父類的所有屬性。
- 2.ClassB同時可以擁有新的屬性和方法。在第10,11行。
- 3.call相當於連線另一個物件的構造方法,類似於java中的super關鍵字的含義,在這裡,相當於是在ClassB作用域下呼叫ClassA函式,很好的體現了繼承。(call還能實現多繼承)
2 prototype
在JavaScript中的繼承是基於原型鏈的。看下面的例子
<script type="text/javascript"> 1 function ClassA() { 2 } 3 4 ClassA.prototype.color = "blue"; 5 ClassA.prototype.sayColor = function () { 6 alert(this.color); 7 }; 8 9 function ClassB() { 10 } 11 12 ClassB.prototype = new ClassA(); 13 ClassB.prototype.name = ""; 14 ClassB.prototype.sayName = function () { 15 alert(this.name); 16 }; 17 var objA = new ClassA(); 18 var objB = new ClassB(); 19 objA.color = "blue"; 20 objB.color = "red"; 21 objB.name = "John"; 22 objA.sayColor(); 23 objB.sayColor(); 24 objB.sayName(); </script>
說明:
- 1.和上面的例子不同的是,第一行ClassA的建構函式中沒有引數,這個是使用原型鏈的標準。此外在函式體中沒有定義屬性和方法,都是在CalssA的建構函式之外通過ClassA.prototye.Xxx的方式定義的。
- 2. 第12行就是繼承的關鍵,我們需要使用ClassA中的全部屬性和方法。當然我們可以通過ClassB.prototye.Xxx的方式逐個定義,使其相等。但是我們可以使用ClassB.prototype = new Xxx()的方式,將ClassA的例項賦予給ClassB,這樣就更好了。第20和23也證明了ClassB繼承了ClassA的屬性和方法。
- 3.我們從第一行中可以發現ClassA是一個Function,但是同時Function也是一個Object,而之前講過,Object物件的屬性:Prototype預設返回Object物件的一個例項。也就是說prototype實際上是Object的屬性。
- 4.從4,5行可以看出我們既可以使用prototype定義屬性也可以定義方法,而且完全取決於你自己。因為prototype返回一個Object例項,自然就可以新增任意你喜歡的屬性和方法了。
- 5.類的例項可以通過"."的方式訪問prototype定義過的屬性方法,第19 - 24行
javaScript物件體系結構
JavaScript中的this
- this是javascript中理解類和繼承的重要基礎。this屬性代表當前物件。如果用在全域性變數中,那麼它代表當前頁面物件window,我們可以通過使用call和apply方法來改變this指標,(注意:this指標是在函式呼叫時改變的,並不是函式定義時)如下面的例子:
function hello(){
alert(this.say);
}
var say = "你好";
hello();
var test = {
say:"歡迎訪問",
hello:hello
}
test.hello();
- 1.開始時執行hello方法是全域性的,相當於window.hello(),輸出的是"你好",在下面呼叫的時候this指向了當前物件test,所以輸出的是"歡迎訪問"。
- 2.在函式定義時,this指向的是window物件,在第一次執行的時候this指標不變,但是在第二次執行的時候this指標變成了test物件。this指標發生了變化。
- this指標可以是全域性物件、當前物件或者任意物件,這個要取決於函式的呼叫方式:在javascript中,函式有幾種不同的呼叫方式:作為物件方法呼叫、作為函式呼叫、作為建構函式呼叫、使用apply和call進行呼叫。以下分別是這幾種呼叫方式下的this指標:
- 1.作為函式物件呼叫
由於函式也是物件,因此函式也可以作為物件的一個屬性,此時函式就是該物件的方法,當使用該物件呼叫這個方法時,this當然指的是該物件 例子:
var hello = { say:"welcome", test:function(name){ this.say = name + " say:" + this.say; } }; hello.test("jack");
此時的this就被繫結到hello物件中
- 2.作為函式呼叫
在函式體內也可以直接呼叫,此時的this指的是全域性物件window。例子:
var say = "welcome"; function hello(say){ this.say = say; }
此時的this指的是全域性物件。
- 3.作為建構函式呼叫
Hello.js function Hello(say){ this.say = say }
this被繫結到新建立的物件上面。
- 4.使用call或者apply呼叫(同上面的call方法中的舉例)
JavaScript匿名函式
1 定義一個函式方式
首先需要說明的是在JavaScript中定義一個函式一般存在如下三種方式:
- 1. 使用關鍵字function
funtion sayHello(){alert("hello"); }
這種方式定義的函式,函式宣告在整個程式執行之前的預處理就完成了。只要同處於一個作用域就可以訪問到。
- 2. 使用Function類
var myFunction = new Function("x","alert(x)") ;
Function類中前面的引數就是在最後一個引數中需要傳遞的引數,也就是最後一個引數是函式的主體。使用Function類定義的函式中的引數必須都是字串。
- 3. 使用匿名物件
var myFunction = function(x){alert(x) ;}
這種方式定義的函式,只能按照程式流程執行到定義的那一行才可以被宣告,所以只能在定義之後才可以呼叫。
2 變數的作用域
變數的作用域無非就是兩種:全域性變數和區域性變數。 在JavaScript中支援在函式的內部直接訪問全域性變數,同時在函式的外部自然就無法訪問到函式內的區域性變量了。 另外需要說明的是在函式的內部宣告變數時候,一定要使用var關鍵字,否則的話,實際上你聲明瞭一個全域性的變數!!
3 示例
<html>
<head>
<title>匿名物件</title>
</head>
<body>
<script type="text/javascript">
// 測試函式作用域
var NUM = 999 ; // 全域性變數
function testNum(){
alert(NUM) ;
var count = 100 // 區域性變數
TEST_NUM = 1 ; // 全域性變數
}
testNum() ; // 999
alert(count) ; // error
alert(TEST_NUM) ; // 1
// 測試匿名函式
var testFunction;
testFunction(); //error
testFunction=function(){
sayHello(); //sayHello works
alert("testFunction works");
return false; // 雖然已經return,說明程式流程並沒有執行,但是sayHello已經在預處理中處理了
function sayHello(){
alert("hello");
}
}
testFunction(); // 先輸出hello , 再輸出testFunction works , 這是因為sayHello程式的執行流程之前被呼叫。
</script>
</body>
</html>
4 匿名函式和this結合
<html>
<head>
<title>匿名物件</title>
</head>
<body>
<script type="text/javascript">
// 不使用this關鍵字
objA={
Calculate : function(num){
return num > 2 ? objA.Calculate(num-1) : num ; // 將objA替換成this即可
}
}
objB={
Calculate : objA.Calculate
}
alert(objB.Calculate(5)) ; // 2
objA = {} ; // 將objA清空
alert(objB.Calculate(5)) ; // error
</script>
</body>
</html>
說明:在上面的程式碼中objA中定義了一個遞迴,直到num的值為2。然後將objA = {}進行了清空,那麼下面的輸出就會出現錯誤了。
這個時候我們的this就可以派上用場了。將遞迴函式中的objA替換成this,這樣的話將objA = {} 清空,但是並不會將objB進行清空。
JavaScript閉包
閉包在js中是一個難點,本人也只是懂得其中的一點基礎,希望以下的介紹能夠對初學者起到入門的作用
1變數的作用域
要理解閉包的概念,首先應該理解一下變數的作用域,它分為兩種:全域性變數和區域性變數,在js中,函式內部可以直接訪問函式外部的變數,例如:
var say = "hello";
function test(){
alert(say);
}
test();
當然外部不能訪問內部的變數,如下的訪問時錯誤的:
function test(){
var say = "hello";
//
}
alert(say);
注意:在函式內部定義變數的時候需要加var,否則預設的宣告的是全域性變數
2.從外部獲取區域性變數
上面說了,在一般情況下是不能訪問的,但是如果改變一下思路,這個問題就會迎刃而解了,就是在函式內部定義函式:
function test1(){ var say = "hello"; function test2(){ alert(say); } return test2; } var test = test1(); test();
以上就是在函式test1的內部定義了函式test2,在test2中訪問區域性變數。這樣就在函式外部訪問到了區域性變數。
3.閉包的概念
閉包,通俗的講,其實就是能夠訪問其他函式內部變數的函式
4.閉包的用途
閉包主要有兩大用途:一個是前面提到的可以訪問函式內部的變數,二是讓這些變數的值始終儲存在記憶體中。
function test1(){
var say = 1;
add = function(){
say += 1;
}
function test2(){
alert(say);
}
return test2;
}
var result=test1();
result();
add();
result();
以上函式中,result實際上就是一個閉包函式,它一共執行了兩次,這說明test1的變數say一直在記憶體中。並沒有在呼叫test1以後自動清除。這裡面有一個add方法,因為在定義它的時候前面沒有var關鍵字,所以它是一個全域性變數,並且它又是一個匿名函式,它實際上也是一個閉包,所以能夠改變區域性變數的值。
5.閉包的執行機制,你理解了嗎?看下面兩個例子:
var name = "Lily";
var test = {
name = "Lucy";
getName:function(){
return function(){
return this.name;
}
}
};
console.log(test.getName()());
輸出 "Lily";
var name = "Lily";
var test = {
name = "Lucy";
getName:function(){
var Dthis = this;
return function(){
return Dthis.name;
}
}
};
console.log(test.getName()());
輸出 "Lucy".
還有幾個閉包的例子,看這裡http://www.cnblogs.com/zhangle/archive/2010/07/02/1770206.html
JavaScript指令碼化Java
1什麼是指令碼化
指令碼化可以使宿主程式具有指令碼所描述的能力,比如JavaScript技術,JavaScript可以讓原本是靜態的HTML程式碼的頁面變活、具有區域性重新整理等更高階的功能。應用程式一般是以二進位制的形式釋出的,使用者很難根據自己的需求對其進行定製。指令碼化是通過使用者自己設計指令碼,然後將其注入到應用中,使得應用的行為得到改變。
2看這裡簡單的例子
http://han2000lei.iteye.com/blog/353253