JavaScript極簡入門教學(二):物件與函數_javascript技巧
閱讀本文需有其他語言的程式設計經驗。
JavaScript 中的簡單型別包括:
1.數字
2.字串
3.布爾(true 和 false)
4.null
5.undefined
此外的其他類型皆是物件(我們不要被 typeof 運算子的回傳值所迷惑),例如:
1.函數
2.數組
3.正規表示式
4.對象(對象自然也是對象)
物件基礎
在 JavaScript 中,物件是屬性的集合(物件為關聯陣列),每個屬性都包括:
1.屬性名,必須為字串
2.屬性值,可以為除了 undefined 之外的任何值
透過物件 literal 建立物件:
// 透過物件 literal {} 建立空物件
var empty_object = {};
物件的屬性名稱和屬性值:
var stooge = {
// "first-name" 為屬性名,"Jerome" 為屬性值
"first-name": "Jerome",
// "last-name" 為屬性名,"Howard" 為屬性值
"last-name": "Howard"
};
如果屬性名稱是合法的標識符,那麼可以省略引號:
var flight = {
airline: "Oceanic",
number: 815,
departure: {
IATA: "SYD",
time: "2004-09-22 14:55",
city: "Sydney"
},
arrival: {
IATA: "LAX",
time: "2004-09-23 10:42",
city: "Los Angeles"
}
};
我們來看屬性存取的範例:
var owner = { name: "Name5566" };
owner.name; // "Name5566"
owner["name"]; // "Name5566"
owner.job; // undefined
owner.job = "coder"; // 或 owner["job"] = "coder";
如果屬性名不是合法標識符,那麼就需要用引號包裹。不存在的屬性值為 undefined。物件是透過引用而非按值傳遞:
var x = {};
var owner = x;
owner.name = "Name5566";
x.name; // x.name === "Name5566"
這裡 x 和 owner 引用同一個物件。
物件的屬性可以使用 delete 運算子刪除:
delete obj.x; // 刪除物件 obj 的 x 屬性
物件的原型(prototype)
每一個物件都被連結了一個原型物件(prototype object),物件能夠從原型物件繼承屬性。我們透過物件 literal 建立一個對象,它的原型物件為 Object.prototype 物件(Object.prototype 物件本身沒有原型物件)。我們在創建物件的時候,可以設定物件的原型物件(之後再討論具體的設定方法)。在嘗試取得(而非修改)物件的某個屬性時,如果該物件不存在此屬性,那麼JavaScript 會嘗試從此物件的原型物件中取得此屬性,如果原型物件中沒有該屬性,那麼再從此原型對象的原型物件中查找,以此類推,直到Object.prototype 原型物件。相較於獲取屬性而言,我們修改物件的某個屬性時,不會影響原型物件。
函數基礎
在 JavaScript 中函數也是對象,其連結到 Function.prototype 原型對象(Function.prototype 連結到 Object.prototype)。函數存在一個名為 prototype 的屬性,其值的類型為對象,此物件存在一個屬性 constructor,constructor 的值為此函數:
var f = function() {}
typeof f.prototype; // 'object'
typeof f.prototype.constructor; // 'function'
f === f.prototype.constructor; // true
函數是對象,你可以像使用對像一樣使用函數,也就是說,函數可以保存在變數、陣列中,可以作為參數傳遞給函數,函數內部可以定義函數。附帶提及一下,函數有兩個被隱藏的屬性:
1.函數的上下文
2.函數的程式碼
函數的建立如下:
var f = function add(a, b) {
return a b;
}
console.log(f); // 輸出 [Function: 加]
關鍵字 function 後的函數名稱是可選的,我們制定函數名稱主要出於幾個目的:
1.為了遞歸呼叫
2.被調試器、開發工具等用來識別函數
很多時候我們並不需要函數名,沒有函數名的函數被叫做匿名函數。有括號包裹的為參數清單。 JavaScript 不要求實參和形參匹配,例如:
var add = function(a, b) {
return a b;
}
add(1, 2, 3); // 實參和形參不符
如果實參過多,那麼多餘的實參會被忽略,如果實參過少,那麼未被賦值的形參的值為 undefined。函數一定有一個回傳值,如果沒有透過 return 語句指定回傳值,那麼函數傳回值為 undefined。
一個函數和其存取的外部變數組成一個閉包。這就是 JavaScript 的關鍵魅力。
函數呼叫
每個函數被呼叫時,會接收到兩個額外的參數:
1.this
2.arguments
this 的值和具體呼叫的模式有關,在 JavaScript 中有四種呼叫模式:
1.方法呼叫模式。物件的屬性如果是函數,則稱為方法。如果一個方法透過 o.m(args) 被調用,this 為物件 o(由此可見,在調用時,this 和 o 才進行綁定),例如:
var obj = {
value: 0,
increment: function(v) {
this.value = (typeof v === 'number' ? v : 1);
}
};
obj.increment(); // this === obj
2.函數呼叫模式。如果一個函數不是一個物件的屬性,那麼它將作為一個函數被調用,這時候 this 被綁定到全域物件上,例如:
message = 'Hello World';
var p = function() {
console.log(this.message);
}
p(); // 輸出 'Hello World'
這種行為有時候讓人疑惑,看一個例子:
obj = {
value: 0,
increment: function() {
var helper = function() {
// 對全域物件中的 value 加上 1
this.value = 1;
}
// helper 被當作一個函數來呼叫
// 因此 this 為全域物件
helper();
}
};
obj.increment(); // obj.value === 0
我們預期的結果應該是:
obj = {
value: 0,
increment: function() {
var that = this;
var helper = function() {
that.value = 1;
}
helper();
}
};
obj.increment(); // obj.value === 1
3.建構函式呼叫模式。意圖使用 new 前綴的函數稱為建構函數,例如:
// Test 被叫做建構子
var Test = function(string) {
this.message = string;
}
var myTest = new Test("Hello World");
一個函數前面可以加上 new 來呼叫(這樣的函數通常大寫開頭),加上 new 之後將建立一個連結到此函數的 prototype 屬性的對象,且建構函式中 this 為此對象。
4.apply 呼叫模式。函數的 apply 方法被用來呼叫函數,其有兩個參數,第一個為 this,第二個為參數數組,例如:
var add = function(a, b) {
return a b;
}
var ret = add.apply(null, [3, 4]); // ret === 7
函數呼叫時,我們能夠存取一個名為 arguments 的類別數組(非真正的 JavaScript 數組),其包含了所有的實參,這樣我們就能實現變長參數:
var add = function() {
var sum = 0;
for (var i=0; i
}
return sum;
}
add(1, 2, 3, 4);
異常
現在來說說 JavaScript 的異常處理機制。我們使用 throw 語句來拋出異常,try-cache 語句來捕捉並處理異常:
var add = function (a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
// 拋出異常
throw {
name: '類型Error',
message: 'add needs numbers'
};
}
return a b;
}
// 捕捉並處理異常
try {
add("seven");
// e 為拋出的異常物件
} catch (e) {
console.log(e.name ': ' e.message);
}
為JavaScript 類型新增屬性
JavaScript 中大多數型別存在建構子:
1.物件的建構子為 Object
2.數組的建構子為 Array
3.函數的建構子為 Function
4.字串的建構子為 String
5.數字的建構子為 Number
6.布林的建構子為 Boolean
7.正規表示式的建構子為 RegExp
我們可以為建構函式的 prototype 新增屬性(常加法),使得此屬性對相關變數可用:
Number.prototype.integer = function() {
return Math[this }
(1.1).integer(); // 1
作用域
JavaScript 需要透過函數來建構作用域:
function() {
// ...
}();
這裡建立並執行了一個匿名函數。透過作用域能夠隱藏不希望暴露的變數:
var obj = function() {
// 隱藏 value,外部無法存取
var value = 0;
return {
// 僅此方法可以修改 value
increment: function() {
value = 1;
},
// 僅此方法可讀取 value
getValue: function() {
return value;
}
};
}();
obj.increment();
obj.getValue() === 1;
繼承
JavaScript 實作繼承的方式很多。
在創建對象時,我們可以設定對象關聯的原型對象,我們這樣做:
// 建立一個物件 o,其原型物件為 {x:1, y:2}
var o = Object.create({x:1, y:2});
Object.create 方法被定義在 ECMAScript 5 中,如果你使用 ECMAScript 3 時可以自己實作一個 create 方法:
// 如果未定義 Object.create 方法
if (typeof Object.create !== 'function') {
// 建立 Object.create 方法
Object.create = function (o) {
var F = function () {};
F.prototype = o;
// 建立一個新對象,此對象的原型對象為 o
return new F();
};
}
透過 Object.create 方法我們進行基於原型繼承:一個新物件直接繼承一個舊物件的屬性(相對於基於類別的繼承,這裡無需類別的存在,物件直接繼承物件)。範例:
var myMammal = {
name: 'Herb the Mammal',
get_name: function() {
return this.name;
},
says: function() {
return this.saying || '';
}
};
// 繼承 myMammal
var myCat = Object.create(myMammal);
myCat.name = 'Henrietta';
myCat.saying = 'meow';
myCat.purr = function(n) {
var i, s = '';
for (i = 0; i if (s) {
s = '-';
}
s = 'r';
}
return s;
};
myCat.get_name = function() {
return this.says() ' ' this.name ' ' this.says();
};
上面的程式碼很簡單,但沒辦法保護私有成員。我們可以使用模組模式。在模組模式中,某一類物件由一個函數產生,並利用函數作用域保護私有成員不被外部存取:
// mammal 函數,用於建構 mammal 物件
var mammal = function(spec) {
// that 為構造的物件
var that = {};
// 公有方法 get_name 可外部存取
that.get_name = function() {
// spec.name 外在無法直接存取
return spec.name;
};
// 公有方法 says 外部存取
that.says = function() {
// spec.saying 外在無法直接存取
return spec.saying || '';
};
return that;
};
// 建立 mammal 物件
var myMammal = mammal({name: 'Herb'});
// cat 函數,用於建構 cat 物件
var cat = function(spec) {
spec.saying = spec.saying || 'meow';
// cat 繼承自 mammal,因此先建構出 mammal 物件
var that = mammal(spec);
// 加入公有方法 purr
that.purr = function(n) {
var i, s = '';
for (i = 0; i if (s) {
s = '-';
}
s = 'r';
}
return s;
};
// 修改公有方法 get_name
that.get_name = function() {
return that.says() ' ' spec.name
' ' that.says();
return that;
};
};
// 建立 cat 物件
var myCat = cat({name: 'Henrietta'});
在模組模式中,繼承是透過呼叫建構子來實現的。另外,我們也可以在子類別中存取父類別的方法:
Object.prototype.superior = 函數(名稱) {
var that = this, method = that[名稱];
回傳函數() {
return method.apply(that,arguments);
};
};
var Coolcat = 函數(規格){
// 取得子類別的 get_name 方法
var that = cat(spec), super_get_name = that.superior('get_name');
that.get_name = function(n) {
return 'like ' super_get_name() 'baby';
};
返回;
};

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

Go語言提供了兩種動態函數創建技術:closures和反射。 closures允許存取閉包作用域內的變量,而反射可使用FuncOf函數建立新函數。這些技術在自訂HTTP路由器、實現高度可自訂的系統和建置可插拔的元件方面非常有用。

在C++函數命名中,考慮參數順序至關重要,可提高可讀性、減少錯誤並促進重構。常見的參數順序約定包括:動作-物件、物件-動作、語意意義和遵循標準函式庫。最佳順序取決於函數目的、參數類型、潛在混淆和語言慣例。

將MySQL查詢結果陣列轉換為物件的方法如下:建立一個空物件陣列。循環結果數組並為每一行建立一個新的物件。使用foreach迴圈將每一行的鍵值對賦給新物件的對應屬性。將新物件加入到物件數組中。關閉資料庫連線。

1. SUM函數,用於對一列或一組單元格中的數字進行求和,例如:=SUM(A1:J10)。 2、AVERAGE函數,用於計算一列或一組儲存格中的數字的平均值,例如:=AVERAGE(A1:A10)。 3.COUNT函數,用於計算一列或一組單元格中的數字或文字的數量,例如:=COUNT(A1:A10)4、IF函數,用於根據指定的條件進行邏輯判斷,並返回相應的結果。

C++函數中預設參數的優點包括簡化呼叫、增強可讀性、避免錯誤。缺點是限制靈活性、命名限制。可變參數的優點包括無限彈性、動態綁定。缺點包括複雜性更高、隱式型別轉換、除錯困難。

PHP中,數組是有序序列,以索引存取元素;物件是具有屬性和方法的實體,透過new關鍵字建立。數組存取透過索引,物件存取通過屬性/方法。數組值傳遞,物件參考傳遞。

自訂PHP函數與預定義函數的差異在於:作用域:自訂函數僅限於其定義範圍,而預定義函數可在整個腳本中存取。定義方式:自訂函數使用function關鍵字定義,而預先定義函數則由PHP核心定義。參數傳遞:自訂函數接收參數,而預先定義函數可能不需要參數。擴充性:自訂函數可以根據需要創建,而預定義函數是內建的且無法修改。
