一、函數
JavaScript中的函數定義分為兩種:聲明式函數和賦值式函數。而且,函數的名稱就是函數的內存地址,和變量一樣,指向函數代碼所在的內存區域。
// 聲明式函數
function fn(name){
var msg = "你好,"+name+",我是一個函數.";
alert(msg);
}
// 賦值式函數
var fn = function(name){
var msg = "你好,"+name+",我是一個函數.";
alert(msg);
}
以上兩種表達式中的fn是一樣的,都是指向一個函數的指針。alert(fn)的運行結果都是:
alert(fn)之所以能夠打印函數的聲明語句,是因為toString()方法:
function fn(){
var msg = "你好,"+name+",我是一個函數.";
alert(msg);
}
alert(fn.toString());
運行結果是一樣的。
那么toString()方法是怎樣來的呢?
對于JavaScript來說,函數其實是Function類的對象。比如,我們可以用Function類直接創建上面的fn函數:
var fn = new Function("name","var msg = \"你好,\"+name+\",我是一個函數.\";\nalert(msg);");
alert(fn);
執行結果如下:
函數的執行結果也是一樣的:
var fn = new Function("name","var msg = \"你好,\"+name+\",我是一個函數.\";\nalert(msg);");
fn("張三");
Function對象有length屬性,可以查看函數的參數,有valueOf()方法和toString()方法,這兩個方法返回的都是函數的源代碼。因此,alert(fn)顯示的就是函數的聲明語句了。
既然函數名是指向函數的變量,那么就可以把函數作為參數傳遞給另一個函數。
function fn(name){
var msg = "你好,"+name+",我是一個函數.";
alert(msg);
}
function call_fn(func,name){
func(name);
}
call_fn(fn,"張三");
JavaScript的函數,使用特殊對象arguments封裝了函數的參數,我們無需明確指出參數名,就能訪問它們。通過屬性 arguments.length可以獲得函數的參數個數 。用arguments對象判斷傳遞給函數的參數個數,即可模擬函數重載。下面是官方的一個例子。
function doAdd() {
if(arguments.length == 1) {
alert(arguments[0] + 5);
} else if(arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); ? ? ? //輸出 "15"
doAdd(40, 20); ? ?//輸出 "60"
JavaScript函數中,變量的作用域,要特別注意的一點是:加var關鍵字的變量是函數內部的局部變量,函數執行完后,變量將銷毀;但沒有加var關鍵字的變量,將成為全局變量,函數外可以訪問。
function fn(){
var x = 10;
y = 20;
alert("函數內部訪問x:"+x+"\n函數內部訪問y:"+y);
}
fn();
alert("函數外部訪問y:"+y);
alert("函數外部訪問x:"+x);
二、對象
JavaScript沒有類的概念,只有對象定義。對象是由 new 運算符加上要實例化的對象的名字創建的。其中,要實例化的對象其實就是函數。那么,函數是怎樣變成對象的呢?
先看下面這段代碼。
function myobj(){
return this;
}
var f = myobj();
var o= new myobj();
alert(f);
alert(o);
我們發現,加了new運算符后,this才指向由myobj創建的對象。
而var f = myobj(),這就不是創建對象,其中的this不是指myobj創建的對象,而是代碼當前上下文環境的當前對象,比如是window。
也就是說,用new運算符調用函數就創建了對象。this代表實例化之后的對象,可以顯示的return,但并不需要這么做。以下代碼效果是一樣的。
function myobj(){
}
var o = new myobj();
alert(o);
JavaScript的Object對象與Java中的Object相似,JavaScript中的所有對象都由這個對象繼承而來,Object對象中的所有屬性和方法都會出現在其他對象中。
Object 對象具有下列屬性:
constructor:創建對象的函數(構造函數)的引用(指針)。
Prototype:對該對象的對象原型的引用。對于所有的對象,它默認返回Object對象的一個實例。
還具有幾個方法:
hasOwnProperty(property) :判斷對象是否有某個特定的屬性。必須用字符串指定該屬性。(例如,o.hasOwnProperty("name"))。
isPrototypeOf(object) :判斷該對象是否為另一個對象的原型。
propertyIsEnumerable :判斷給定的屬性是否可以用 for...in 語句進行枚舉。
toString() :返回對象的原始字符串表示。對于 Object 對象,ECMA-262 沒有定義這個值,所以不同的 ECMAScript 實現具有不同的值。
valueOf() :返回最適合該對象的原始值。對于許多對象,該方法返回的值都與 ToString() 的返回值相同。
我們在瀏覽器的開發者工具的控制臺輸入new object()回車,可以查看上面那些Object對象的屬性和方法。
Object對象也可以使用對象字面量語法來創建:var o = {};
同樣,我們可以在瀏覽器的開發者工具中進行驗證。
javascript支持后綁定,比如這樣:
function obj()
{
}
var o = new obj();
o.fn = function(){
alert("hello");
}
o.fn();
所以,可以通過函數創建對象,這叫工廠方法:
function createCar(color,doors,mpg) {
var car = new Object();
car.color = color;
car.doors = doors;
car.mpg = mpg;
car.showColor = function() {
alert(this.color);
};
return car;
}
var car1 = createCar("red",4,23);
var car2 = createCar("blue",3,25);
car1.showColor();
car2.showColor();
比較正規一點的創建對象的方法,用構造函數法,用this代表當前對象了:
function Car(color,doors,mpg) {
this.color = color;
this.doors = doors;
this.mpg = mpg;
this.showColor = function() {
alert(this.color);
};
}
var car1 = new Car("red",4,23);
var car2 = new Car("blue",3,25);
car1.showColor();
car2.showColor();
構造函數法的問題是,其中的對象方法,比如例子中的showColor方法,每次new的時候都會創建一次,顯然浪費內存。
可以用原型鏈定義對象的方法。這樣,所有對象共享一個對象方法,既保證了對象屬性的唯一性,也節約了內存:
function Car(color,doors,mpg) {
this.color = color;
this.doors = doors;
this.mpg = mpg;
this.drivers = new Array("Mike","John");
}
Car.prototype.showDrivers = function() {
alert(this.drivers);
};
var car1 = new Car("red",4,23);
var car2 = new Car("blue",3,25);
car1.drivers.push("Bill");
car1.showDrivers();? ? ? ? //輸出 "Mike,John,Bill"
car2.showDrivers();? ? ? ? //輸出 "Mike,John"
對象方法,只能是new之后的對象可以訪問:
function obj(){
}
obj.prototype.fn = function(){
alert("hello");
}
var o = new obj();
o.fn();
但是,如果這樣訪問obj.fn()就會報錯:
function obj(){
}
obj.prototype.fn = function(){
alert("hello");
}
obj.fn();
用函數名字直接訪問的方法,我們叫函數方法,或者靜態方法。
function obj(){
}
obj.fn = function(){
alert("hello");
}
obj.fn();
但javascript的靜態方法,對象并不能訪問,如果這樣就會報錯:
function obj(){
}
obj.fn = function(){
alert("hello");
}
var o = new obj();
o.fn();
還有很重要的一點,原型屬性是所有對象共享,如果屬性是引用類型,那么就會出現,一個對象修改了數值,其他對象相應的屬性數值都會改變的尷尬局面。
function obj(){
}
obj.prototype.names = ["張三","李四"];
var o1 = new obj();
var o2 = new obj();
o1.names.push("o1添加的新的名字");
alert("o1.names:"+o1.names+"\no2.names:"+o2.names);
其實,javascript并沒有真正的靜態方法,只是利用javascript靈活的特性模擬實現的。
本文出自 “老惠” 博客,轉載已經過作者同意。