《Javascript 高階程式設計(第三版)》筆記0x7 引用型別(2)
目錄
Function 型別
函式實際上是物件。每個函式都是 Function 型別的例項,而且都與其他引用型別一樣具有屬性和方法。由於函式是物件,因此函式名實際上也是一個指向函式物件的指標,不會與某個函式繫結。
function sum (num1, num2) {
return num1 + num2;
}
//這與下面使用函式表示式定義函式的方式幾乎相差無幾。
var sum = function(num1, num2){//在使用函式表示式定義函式時,沒有必要使用函式名——通過變數 sum 即可以引用函式
return num1 + num2;
};
//使用 Function 建構函式
var sum = new Function("num1", "num2", "return num1 + num2"); // 不推薦
由於函式名僅僅是指向函式的指標,因此函式名與包含物件指標的其他變數沒有什麼不同。換句話說,一個函式可能會有多個名字.
function sum(num1, num2){
return num1 + num2;
}
alert(sum(10,10)); //20
var anotherSum = sum;
alert(anotherSum(10,10)); //20
sum = null;
alert(anotherSum(10,10)); //20
//注意即使將 sum 設定為 null,讓它與函式“斷絕關係”,但仍然可以正常呼叫anotherSum()。
沒有過載
//函式名是指標,那後面的函式名自然會覆蓋前面
function addSomeNumber(num){
return num + 100;
}
function addSomeNumber(num) {
return num + 200;
}
var result = addSomeNumber(100); //300
//相當於
var addSomeNumber = function (num){
return num + 100;
};
addSomeNumber = function (num) {
return num + 200;
};
var result = addSomeNumber(100); //300
函式宣告與函式表示式
解析器會率先讀取函式宣告,並使其在執行任何程式碼之前可用(可以訪問);至於函式表示式,則必須等到解析器執行到它所在的程式碼行,才會真正被解釋執行。
作為值的函式
將一個函式作為另一個函式的結果返回
function callSomeFunction(someFunction, someArgument){
return someFunction(someArgument);
}
function add10(num){
return num + 10;
}
var result1 = callSomeFunction(add10, 10);
alert(result1); //20
function getGreeting(name){
return "Hello, " + name;
}
var result2 = callSomeFunction(getGreeting, "Nicholas");
alert(result2); //"Hello, Nicholas"
從一個函式中返回另一個函式
function createComparisonFunction(propertyName) {
return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
};
}
var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];
data.sort(createComparisonFunction("name"));
alert(data[0].name); //Nicholas
data.sort(createComparisonFunction("age"));
alert(data[0].name); //Zachary
函式內部屬性
arguments 主要用途是儲存函式引數;
callee 屬性
該屬性是一個指標,指向擁有這個 arguments 物件的函式。
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * factorial(num-1)
}
}
function factorial(num){
if (num <=1) {
return 1;
} else {
return num * arguments.callee(num-1)
}
}
解除了函式體內的程式碼與函式名的耦合狀態。
this
引用的是函資料以執行的環境物件
//當在網頁的全域性作用域中呼叫函式時,this 物件引用的就是 window
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
sayColor(); //"red"
o.sayColor = sayColor;
o.sayColor(); //"blue"
函式的名字僅僅是一個包含指標的變數而已。因此,即使是在不同的環境中執行,全域性的 sayColor()函式與 o.sayColor()指向的仍然是同一個函式。
caller
儲存著呼叫當前函式的函式的引用,如果是在全域性作用域中呼叫當前函式,它的值為 null。
function outer(){
inner();
}
function inner(){
alert(arguments.callee.caller);
}
outer();
函式屬性和方法
屬性:length 和 prototype
//length表引數個數
function sayName(name){
alert(name);
}
function sum(num1, num2){
return num1 + num2;
}
function sayHi(){
alert("hi");
}
alert(sayName.length); //1
alert(sum.length); //2
alert(sayHi.length); //0
對於ECMAScript 中的引用型別而言, prototype 是儲存它們所有例項方法的真正所在。換句話說,諸如toString()和 valueOf()等方法實際上都儲存在 prototype 名下,只不過是通過各自物件的例項訪問罷了。
方法:apply()和 call()
/*apply()方法接收兩個引數:一個是在其中執行函式的作用域,另一個是引數陣列。
其中,第二個引數可以是 Array 的例項,也可以是arguments 物件。*/
function sum(num1, num2){
return num1 + num2;
}
function callSum1(num1, num2){
return sum.apply(this, arguments); // 傳入 arguments 物件
}
function callSum2(num1, num2){
return sum.apply(this, [num1, num2]); // 傳入陣列
}
alert(callSum1(10,10)); //20
alert(callSum2(10,10)); //20
/*對於 call()方法而言,第一個引數是 this 值沒有變化,變化的是其餘引數都直接傳遞給函式。*/
function sum(num1, num2){
return num1 + num2;
}
function callSum(num1, num2){
return sum.call(this, num1, num2);
}
alert(callSum(10,10)); //20
傳遞引數並非 apply()和 call()真正的用武之地;它們真正強大的地方是能夠擴充函式賴以執行的作用域。使用 call()(或 apply())來擴充作用域的最大好處,就是物件不需要與方法有任何耦合關係。
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
sayColor(); //red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue
bind()
這個方法會建立一個函式的例項,其 this 值會被繫結到傳給 bind()函式的值。
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
基本包裝型別
為了便於操作基本型別值, ECMAScript 還提供了 3 個特殊的引用型別: Boolean、 Number 和String。
var s1 = "some text";
var s2 = s1.substring(2);
//相當於
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;
引用型別與基本包裝型別的主要區別就是物件的生存期。使用 new 操作符建立的引用型別的例項,在執行流離開當前作用域之前都一直儲存在記憶體中。而自動建立的基本包裝型別的物件,則只存在於一行程式碼的執行瞬間,然後立即被銷燬。這意味著我們不能在執行時為基本型別值新增屬性和方法。
Object 建構函式也會像工廠方法一樣,根據傳入值的型別返回相應基本包裝型別的例項。
var obj = new Object("some text");
alert(obj instanceof String); //true
Boolean型別
var booleanObject = new Boolean(true);
var falseObject = new Boolean(false);
var result = falseObject && true;
alert(result); //true
var falseValue = false;
result = falseValue && true;
alert(result); //false
首先, typeof 操作符對基本型別返回"boolean",而對引用型別返回"object"。其次,由於 Boolean 物件是 Boolean 型別的例項,所以使用 instanceof操作符測試 Boolean 物件會返回 true,而測試基本型別的布林值則返回 false。
alert(typeof falseObject); //object
alert(typeof falseValue); //boolean
alert(falseObject instanceof Boolean); //true
alert(falseValue instanceof Boolean); //false
Number型別
var num = 10;
alert(num.toString()); //"10"
alert(num.toString(2)); //"1010"
alert(num.toString(8)); //"12"
alert(num.toString(10)); //"10"
alert(num.toString(16)); //"a"
alert(num.toFixed(2)); //"10.00"
alert(num.toExponential(1)); //"1.0e+1"
var num = 10.005;
alert(num.toFixed(2)); //"10.01"
var num = 99;
alert(num.toPrecision(1)); //"1e+2"
alert(num.toPrecision(2)); //"99"
alert(num.toPrecision(3)); //"99.0"
var numberObject = new Number(10);
var numberValue = 10;
alert(typeof numberObject); //"object"
alert(typeof numberValue); //"number"
alert(numberObject instanceof Number); //true
alert(numberValue instanceof Number); //false
String型別
var stringObject = new String("hello world");
var stringValue = "hello world";
alert(stringValue.length); //"11"
字元方法
var stringValue = "hello world";
alert(stringValue.charAt(1)); //"e"
alert(stringValue.charCodeAt(1)); //輸出"101"
alert(stringValue[1]); //"e"
字串操作方法
var stringValue = "hello ";
var result = stringValue.concat("world");
alert(result); //"hello world"
alert(stringValue); //"hello"
var stringValue = "hello ";
var result = stringValue.concat("world", "!");
alert(result); //"hello world!"
alert(stringValue); //"hello"
var stringValue = "hello world";
alert(stringValue.slice(3)); //"lo world"
alert(stringValue.substring(3)); //"lo world"
alert(stringValue.substr(3)); //"lo world"
alert(stringValue.slice(3, 7)); //"lo w"
alert(stringValue.substring(3,7)); //"lo w"
alert(stringValue.substr(3, 7)); //"lo worl"
var stringValue = "hello world";
alert(stringValue.slice(-3)); //"rld",slice()方法會將傳入的負值與字串的長度相加
alert(stringValue.substring(-3)); //"hello world"
alert(stringValue.substr(-3)); //"rld"
alert(stringValue.slice(3, -4)); //"lo w"
alert(stringValue.substring(3, -4)); //"hel",ubstring()方法會把所有負值引數都轉換為 0。
alert(stringValue.substr(3, -4)); //""(空字串),substr()方法將負的第一個引數加上字串的長度,而將負的第二個引數轉換為 0
字串位置方法
var stringValue = "hello world";
alert(stringValue.indexOf("o")); //4
alert(stringValue.lastIndexOf("o")); //7
var stringValue = "hello world";//第二個引數,表示從字串中的哪個位置開始搜尋。
alert(stringValue.indexOf("o", 6)); //7
alert(stringValue.lastIndexOf("o", 6)); //4
trim()方法
var stringValue = " hello world ";
var trimmedStringValue = stringValue.trim();
alert(stringValue); //" hello world "
alert(trimmedStringValue); //"hello world"
字串大小寫轉換方法
var stringValue = "hello world";
alert(stringValue.toLocaleUpperCase()); //"HELLO WORLD"
alert(stringValue.toUpperCase()); //"HELLO WORLD"
alert(stringValue.toLocaleLowerCase()); //"hello world"
alert(stringValue.toLowerCase()); //"hello world"
字串的模式匹配方法
var text = "cat, bat, sat, fat";
var pattern = /.at/;
//與 pattern.exec(text)相同
var matches = text.match(pattern);
alert(matches.index); //0
alert(matches[0]); //"cat"
alert(pattern.lastIndex); //0
var text = "cat, bat, sat, fat";
var pos = text.search(/at/);
alert(pos); //1
var text = "cat, bat, sat, fat";
var result = text.replace("at", "ond");
alert(result); //"cond, bat, sat, fat"
result = text.replace(/at/g, "ond");
alert(result); //"cond, bond, sond, fond"
var text = "cat, bat, sat, fat";
result = text.replace(/(.at)/g, "word ($1)");
alert(result); //word (cat), word (bat), word (sat), word (fat)
localeCompare()方法
var stringValue = "yellow";
alert(stringValue.localeCompare("brick")); //1
alert(stringValue.localeCompare("yellow")); //0
alert(stringValue.localeCompare("zoo")); //-1
fromCharCode()方法
alert(String.fromCharCode(104, 101, 108, 108, 111)); //"hello"
HTML 方法
單體內建物件
“由 ECMAScript 實現提供的、不依賴於宿主環境的物件,這些物件在 ECMAScript 程式執行之前就已經存在了。”
Global物件
ECMAScript 中的 Global 物件在某種意義上是作為一個終極的“兜底兒物件”來定義的。換句話說,不屬於任何其他物件的屬性和方法,最終都是它的屬性和方法。事實上,沒有全域性變數或全域性函式;所有在全域性作用域中定義的屬性和函式,都是 Global 物件的屬性。
URI 編碼方法
Global 物件的 encodeURI()和 encodeURIComponent()方法可以對 URI(Uniform Resource Identifiers,通用資源識別符號)進行編碼,以便傳送給瀏覽器。有效的 URI 中不能包含某些字元。
encodeURI()主要用於整個 URI(例如, http://www.wrox.com/illegal value.htm),而 encodeURIComponent()主要用於對 URI 中的某一段(例如前面 URI 中的 illegal value.htm)進行編碼。它們的主要區別在於, encodeURI()不會對本身屬於 URI 的特殊字元進行編碼,例如冒號、正斜槓、問號和井字號;而 encodeURIComponent()則會對它發現的任何非標準字元進行編碼。
var uri = "http://www.wrox.com/illegal value.htm#start";
alert(encodeURI(uri));//"http://www.wrox.com/illegal%20value.htm#start"
alert(encodeURIComponent(uri));//"http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"
var uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start";
alert(decodeURI(uri));//http%3A%2F%2Fwww.wrox.com%2Fillegal value.htm%23start
alert(decodeURIComponent(uri));//http://www.wrox.com/illegal value.htm#start
eval()方法
eval()方法就像是一個完整的 ECMAScript 解析器,它只接受一個引數,即要執行的 ECMAScript (或 JavaScript)字串。
var msg = "hello world";
eval("alert(msg)"); //"hello world"
eval("var msg = 'hello world'; ");
alert(msg); //"hello world"
能夠解釋程式碼字串的能力非常強大,但也非常危險。因此在使用 eval()時必須極為謹慎,特別是在用它執行使用者輸入資料的情況下。否則,可能會有惡意使用者輸入威脅你的站點或應用程式安全的程式碼(即所謂的程式碼注入)。
Global 物件的屬性
window 物件
ECMAScript 雖然沒有指出如何直接訪問 Global 物件,但 Web 瀏覽器都是將這個全域性物件作為window 物件的一部分加以實現的。因此,在全域性作用域中宣告的所有變數和函式,就都成為了 window物件的屬性。
var color = "red";
function sayColor(){
alert(window.color);
}
window.sayColor(); //"red",全域性變數是 window 物件的屬性
//另一種取得 Global 物件的方法是使用以下程式碼:
var global = function(){
return this;
}();
Math物件
Math 物件的屬性
min()和 max()方法
var max = Math.max(3, 54, 32, 16);
alert(max); //54
var min = Math.min(3, 54, 32, 16);
alert(min); //3
var values = [1, 2, 3, 4, 5, 6, 7, 8];
var max = Math.max.apply(Math, values);
舍入方法
alert(Math.ceil(25.9)); //26
alert(Math.ceil(25.5)); //26
alert(Math.ceil(25.1)); //26
alert(Math.round(25.9)); //26
alert(Math.round(25.5)); //26
alert(Math.round(25.1)); //25
alert(Math.floor(25.9)); //25
alert(Math.floor(25.5)); //25
alert(Math.floor(25.1)); //25
random()方法
var num = Math.floor(Math.random() * 10 + 1);//選擇一個 1到 10 之間的數值
var num = Math.floor(Math.random() * 9 + 2);//選擇一個介於 2 到 10 之間的值
其他方法