Javascript 編程全解(筆記一)

函數(shù)JavaScript 的函數(shù)是一種對象。

對象

Javascript 中沒有這樣的語言結(jié)構(gòu), Javascript 中的對象是一個(gè) 名稱配對的集合晶丘。這樣一對兒名稱和值的配對被稱為屬性。例如一個(gè)人的屬性有:

  • 身高: 178cm
  • 體重 65kg
  • 年齡 28

所以, Javascript 對象可以定義為屬性 的集合捶码。Javascript 的對象字面量

// 對象字面量表達(dá)式的語法
{ 屬性名 : 屬性值,  屬性名 : 屬性值, ...... }

屬性名可以是標(biāo)識(shí)符汹押。字符串和數(shù)值:

// 對象字面量表達(dá)式的例子

{ x: 2, y:1 }        // 屬性名是標(biāo)識(shí)符
{ "x":2, "y":1 }    // 屬性名是字符串值
{ 'x':2, 'y':1 }      // 屬性名是字符串值
{ 1:2, 2:1 }        // 屬性名是數(shù)值
{ x:2, y:1, enable:true, color:{ r:255, g:255, b:255 } } // 各種類型的屬性值

對對象字面量表達(dá)式求值所得到的結(jié)果缘回,是所生成對象的一個(gè)引用剂公。

// 對象字面量表達(dá)式與賦值表達(dá)式
js> var obj = { x:3, y:4 };  // 所生成對象的引用將被賦值給變量 obj
js> typeof obj;  // 通過 typeof 運(yùn)算符來判別 obj 的類型希俩,得到的結(jié)果是 object
object

屬性訪問

通過點(diǎn)語法和方括號(hào)訪問屬性:

js> var obj = {x:3, y:4}
js> typeof(obj)
"object"
js> print(obj.x)
3
js> print(obj['x'])
3

方法

可以把任意類型的值、對象或者函數(shù)賦值給對象的屬性诬留。正如前節(jié)所講斜纪,對匿名函數(shù)表達(dá)式求值所
得到的結(jié)果是函數(shù)對象的引用贫母,所以文兑,也可以像下面這樣來書寫。

js> obj.fn = function (a, b) {return Number(a) + Number(b); };      // 將函數(shù)賦值給對象 obj 的屬性 fn

可以像下面這樣腺劣,對被賦值給屬性的函數(shù)進(jìn)行調(diào)用绿贞。

js> obj.fn(3, 4); // 調(diào)用函數(shù)
7

回顧一下之前章節(jié)的說明可以發(fā)現(xiàn),在代碼清單 2.2 之后還可以像下面這樣書寫橘原。

js> obj.fn2 = sum;  // sum 是在代碼清單 2.2 中定義的函數(shù)
js> obj.fn2(3, 4); // 調(diào)用函數(shù)

7

數(shù)組

Javascript 中數(shù)組中的元素可以是不同的類型:

var arr = [1, "foo", "bar", 5]
print(arr[1])     ///  foo

數(shù)據(jù)類型

像 Java 這樣籍铁,變量具有數(shù)據(jù)類型的語言,被稱為靜態(tài)數(shù)據(jù)類型語言趾断;而像 JavaScript 這樣拒名,變量沒有類型的語言,則被稱為動(dòng)態(tài)數(shù)據(jù)類型語言芋酌。
在 JavaScript 中增显,字符串值會(huì)被隱式地轉(zhuǎn)換為字符串對象類型

在 JavaScript 中書寫 '012'.lenght 的話,(屬于內(nèi)建類型的)字符串值會(huì)先被隱式地轉(zhuǎn)換為
字符串對象 脐帝,然后再讀取字符串對象的 length 屬性同云。隱式類型轉(zhuǎn)換也能反向進(jìn)行糖权。

var sobj = new String('abc'); // 生成字符串對象
var s = sobj + 'def';               // 將字符串對象隱式轉(zhuǎn)換為了字符串值
print(s);
// abcdef

字符串值和字符串對象之間可以進(jìn)行隱式類型轉(zhuǎn)換。因此炸站,一般來說并不需要在意值和對象之間的
區(qū)別星澳。不過正因看起來非常相似,所以會(huì)存在一些陷阱旱易。例如禁偎,在判定兩者是否相等上是有差異的。對 象的相等運(yùn)算咒唆,判斷的是兩者是否引用了同一個(gè)對象(而非兩者的內(nèi)容是否相同)届垫。

js> var sobj1 = new String('abc');
js> var sobj2 = new String('abc');
js> sobj1 == sobj2;  // 雖然字符串的內(nèi)容相同,但是并非引用了同一個(gè)對象全释,所以結(jié)果是 false
false
js> sobj1 === sobj2; // 雖然字符串的內(nèi)容相同装处,但是并非引用了同一個(gè)對象,所以結(jié)果是 false
false

js> sobj3 = sobj2
(new String("abc"))
js> sobj3 == sobj2
true
js> sobj3 === sobj2
true

上面的兩個(gè)字符串對象浸船,在通過 + 與空字符串值連接之
后妄迁,就會(huì)進(jìn)行隱式數(shù)據(jù)類型轉(zhuǎn)換而變?yōu)樽址担瑥亩Y(jié)果也將發(fā)生變化李命。(比較的是兩者的內(nèi)容是否相同)

// 繼續(xù)之前的代碼(以下只是用于說明的代碼登淘,實(shí)際中并不推薦這樣使用)
js> sobj1 + '' == sobj2 + '';
true
js> sobj1 + '' === sobj2 + '';
true

對于字符串值和字符串對象的等值判斷,如果使用的是會(huì)進(jìn)行隱式數(shù)據(jù)類型轉(zhuǎn)換的 == 運(yùn)算封字,則只會(huì)判定其內(nèi)容是否相同黔州,如果內(nèi)容相同則結(jié)果為真尿招。

js> var sobj = new String('abc');
js> var s = 'abc';
js> sobj == s;  // 進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換的等值運(yùn)算的結(jié)果為 true
true;
js> sobj === s;  // 不進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換的等值運(yùn)算的結(jié)果為 false
false

要盡量避免顯式地使用 new Stirng 生成字符串對象捶惜。盡情享受隱式轉(zhuǎn)換就好了湿诊。

js> var s = 'abc';  // 返回字符串值下標(biāo)為 1 的字符
js> s.charAt(1);
b
js> 'abc'.charAt(1); // 對于字符串字面量也能像這樣進(jìn)行方法調(diào)用
b

調(diào)用 String 函數(shù)進(jìn)行顯式數(shù)據(jù)類型轉(zhuǎn)換:

js> var s = String('abc');
js> typeof s; // 變量 s 的值是字符串型
string
js> var s = String(47);  // 由數(shù)值類型向字符串值類型的顯式數(shù)據(jù)類型變換
js> print(s);
47
js> typeof s; // 變量 s 的值是字符串型
string

String 類的函數(shù)以及構(gòu)造函數(shù)調(diào)用

函數(shù)或是構(gòu)造函數(shù)
說明

String([value])
將參數(shù) value 轉(zhuǎn)換為字符串值類型

new String([value])
生成 String 類的實(shí)例

String類的屬性

屬性名
說明

fromCharCode([char0[,char1,...]])
將參數(shù) value 轉(zhuǎn)換為字符串值類型

length
值為1

prototype
原型鏈

String.prototype 對象所具有的屬性

屬性名
說明

charAt(pos)
返回下標(biāo) pos 位置字符長度為 1 的字符串值严里。下標(biāo)從 0 開始弓坞。如果下標(biāo)超界則返回空字符串值

charCodeAt(pos)
返回下標(biāo) pos 位置處字符的字符編碼叫搁。如果超過了下標(biāo)的范圍, 則返回 NaN

concat([string0, string1,...])
和參數(shù)字符串相連接后返回新的字符串值

constructor
引用一個(gè) String 類對象

indexOf(searchString[, pos])
返回在字符串中第一個(gè)遇到的字符串值 searchString 的下標(biāo)值纺蛆∷憷可以通過第二個(gè)可選參數(shù)指定搜索的起始位置在辆。如果沒有找到符合條件的結(jié)果, 則返回 -1

localeCompare(that)
比較和本地運(yùn)行環(huán)境相關(guān)的字符串证薇。根據(jù)比較的結(jié)果分別返回正數(shù)、0 或者負(fù)數(shù)

match(regexp)
返回匹配正則表達(dá)式 regexp 的結(jié)果

quote()
Javascript 自定義的增強(qiáng)功能匆篓。在字符串外加上雙引號(hào)之后返回這一新的字符串值

replace(searchValue, replaceValue)
將 searchValue (正則表達(dá)式活字符串值) 替換為 replaceValue (字符串或函數(shù)) 后返回經(jīng)過替換后的字符串

search(regexp)
返回匹配正則表達(dá)式 regexp 的位置的下標(biāo)

slice(start, end)
將參數(shù) start 開始至 end 結(jié)束的字符串部分作為新的字符串返回浑度。 如果 start 和 end 是負(fù)數(shù), 則返回從末尾逆向起數(shù)的下標(biāo)值

split(separator, limit)
根據(jù)字符串或正則表達(dá)式形式的參數(shù) separator 將字符串分割, 返回相應(yīng)的字符串值數(shù)組

substring(start, end)
將參數(shù) start 開始至 end 結(jié)束的字符串部分作為新的字符串返回。其作用和 slice 相同, 但是不支持以負(fù)數(shù)作為參數(shù)

toLocaleLowerCase()
將字符串中所有字符轉(zhuǎn)換為和本地環(huán)境相應(yīng)的小寫字符

toLocaleUpperCase()
將字符串中所有字符轉(zhuǎn)換為和本地環(huán)境相應(yīng)的大寫字符

toLowerCase()
將字符串中所有字符轉(zhuǎn)換為小寫字符

toSource()
Javascript 自定義的增強(qiáng)功能鸦概。返回用于生成 String 實(shí)例的字符串(即源代碼)

toString()
將 Stirng 實(shí)例轉(zhuǎn)換為字符串值(并返回)

toUpperCase()
將字符串中的所有字符轉(zhuǎn)換為大寫字符

trim()
去除字符串前后的空白符

trimLeft()
Javascript 自定義的增強(qiáng)功能箩张。去除字符串左側(cè)(頭部) 的空白符

trimRight()
Javascript 自定義的增強(qiáng)功能。去除字符串右側(cè)(尾部) 的空白符

valueOf()
將 String 實(shí)例轉(zhuǎn)換為字符串值并返回

還可以像下面這樣,通過數(shù)值屬性獲取指定下標(biāo)的字符(不過這是 JavaScript 自定義的增強(qiáng)功能)伏钠。其返回值是一個(gè) String 對象横漏。

js> var s = new String('abc');
js> print(s[1]); // 下標(biāo)為 1 的字符
b
js> print('abc'[2]); // 由于有隱式數(shù)據(jù)類型轉(zhuǎn)換,所以對字符串值也能進(jìn)行這樣的操作
c

數(shù)值

Javascript 中熟掂, 大部分情況下浮點(diǎn)數(shù)只能表達(dá)數(shù)值的近似值缎浇。

js> 0.1 + 0.2;  // 0.1 與 0.2 的和并不是 0.3。
0.30000000000000004
js> (0.1 + 0.2) == 0.3  // 兩者不一致赴肚。
false
js> (0.1 + 0.2) === 0.3  // 兩者不一致素跺。
false
js> 1/3 // 1 除以 3 之后的近似結(jié)果。
0.333333333333333
js> 10/3 – 3; // 這同樣是近似值誉券。
0.333333333333333
js> (10/3 – 3) == (1/3);  // 這兩個(gè)近似值是不一致的指厌。
false
js> (10/3 – 3) === (1/3);
false

而 Perl 6 就不會(huì)出現(xiàn)這種情況。數(shù)值也存在數(shù)值對象:

js> var nobj = new Number(1);
js> var nobj1 = new Number(1);
js> nobj == nobj1;  // 雖然值是相同的踊跟,但是所引用的對象不同踩验,因而結(jié)果為 false
false
js> nobj === nobj1;  // 雖然值是相同的,但是所引用的對象不同商玫,因而結(jié)果為 false
false
js> nobj == 1;  // 會(huì)進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換的等值運(yùn)算結(jié)果為 true
true
js> nobj === 1;  // 不會(huì)進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換的等值運(yùn)算結(jié)果為 false
false

調(diào)用 Number 函數(shù):

js> var n1 = Number(1);
js> typeof n1;  // 變量 n1 的值為數(shù)值
number
js> n1 == 1;
true
js> n1 === 1;
true
js> var n = Number('1');  // 從字符串值至數(shù)值型的顯式數(shù)據(jù)類型轉(zhuǎn)換

第四章

Javascript 標(biāo)識(shí)符區(qū)分大小寫箕憾。JavaScript(準(zhǔn)確地說是 ECMAScript)的代碼塊中的變量并不存在塊級作用域這樣
的概念。

// 變量聲明的例子
var foo;
var foo, bar; // 同時(shí)聲明多個(gè)變量
var foo = 'FOO', bar = 'BAR'; // 在聲明變量的同時(shí)進(jìn)行初始化

Javascript 中的 switch/case

var x = 0;
switch (x) {
case 0:
    print("0");
case 1:
    print("1");
case 2:
    print("2");
default:
    print("default");
    break;
}

使用 switch 語句時(shí)拳昌,等值比較表達(dá)式可以被隱藏起來袭异,所以與使用了等值比較的 if-else 語句相比表達(dá)
上更為簡潔。需要注意的是炬藤,switch 語句所隱藏的等值比較運(yùn)算是不會(huì)對數(shù)據(jù)類型進(jìn)行轉(zhuǎn)換的 === 運(yùn)算御铃。
如果原來的 if-else 語句中的表達(dá)式使用的是 == 運(yùn)算的話,就可能會(huì)在執(zhí)行上有一些細(xì)微的差別

var s = 'foo';
switch (s) { // 可以在 switch 表達(dá)式中使用字符串值沈矿。
// 可以在 case 表達(dá)式中使用和 switch 表達(dá)式類型不同的值上真。
// s === 0 的值為假,所以將繼續(xù)進(jìn)行比較细睡。
case 0:
    print('not here');
    break;
// 可以在 case 表達(dá)式中使用含有變量的表達(dá)式谷羞。
// s === s.length 的值為假帝火,所以將繼續(xù)進(jìn)行比較溜徙。
case s.length:
    print('not here');
    break;
// 可以在 case 表達(dá)式中使用方法調(diào)用表達(dá)式。
// s === (0).toString() 的值為假犀填,所以將繼續(xù)進(jìn)行比較蠢壹。
case (0).toString();
    print('not here');
    break;
// 還可以在 case 表達(dá)式中書寫這樣的表達(dá)式。
// s === 'f' + 'o' + 'o' 為真九巡,所以將執(zhí)行以下的代碼图贸。
case 'f' + 'o' + 'o':
    print('here');
    break;
// 如果所有的 case 表達(dá)式在等值運(yùn)算(===)后得到的結(jié)果都為假,則執(zhí)行以下的代碼。
default:
    print('not here');
    break;
}

標(biāo)簽:

// 使用標(biāo)簽來同時(shí)跳出嵌套的循環(huán)
outer_loop:
while (true) {
    print("outer loop");
    while (true) {
        print("inner loop");
        break outer_loop;
    }
}

外層循環(huán)被標(biāo)以 outer_loop 的標(biāo)簽(此前提到過疏日,請?jiān)倩叵胍幌鲁ソ啵瑆hile 循環(huán)以及相應(yīng)的代碼塊共同組成了一句語句)。

異常:

// try-catch-finally 結(jié)構(gòu)的語法
try {
    語句
    語句
    ……
} catch ( 變量名 ) { // 該變量是一個(gè)引用了所捕捉到的異常對象的局部變量
    語句
    語句
    ……
} finally {
    語句
    語句
    ……
}

在 try 語句之外沟优,或者沒有 catch 子句的 try 語句涕滋,都是無法捕捉異常的。這時(shí)函數(shù)會(huì)中斷并返回至調(diào)用該函數(shù)之處挠阁。

finally 子句必定會(huì)在跳出 try 語句之時(shí)被執(zhí)行宾肺。即使沒有產(chǎn)生異常,finally 子句也會(huì)被執(zhí)行侵俗。也就是說锨用,如果沒有產(chǎn)生異常的話,在執(zhí)行完 try 子句之后會(huì)繼續(xù)執(zhí)行 finally 子句的代碼隘谣;如果產(chǎn)生了異常增拥,則會(huì)在執(zhí)行 finally 子句之前首先執(zhí)行 catch 子句。對于沒有 catch 子句的 try 語句來說寻歧,異常將會(huì)被直接傳
遞至上一層跪者,但 finally 子句仍然會(huì)被執(zhí)行。

代碼清單 4.9?try 語句的執(zhí)行示例

try {
    print('1');
    null.x; // 在此處強(qiáng)制產(chǎn)生一個(gè) TypeError 異常
    print('not here');  // 這條語句不會(huì)被執(zhí)行
} catch (e) { // 對象 e 是 TypeError 對象的一個(gè)引用
    print('2');
} finally {
    print('3');
}
// 代碼清單 4.9 的運(yùn)行結(jié)果
1
2
3

with 表達(dá)式:

with 語句用于臨時(shí)改變名稱(變量名或是函數(shù)名)的查找范圍熄求。with 語句中使用的表達(dá)式是 Object
類型的渣玲。如果使用了其他類型的值,則會(huì)被轉(zhuǎn)換為 Object 類型弟晚。在 with 語句內(nèi)對變量名進(jìn)行查找時(shí)忘衍,將
會(huì)從所指定對象的屬性開始尋找。

// with 語句的例子
js> var x = 1;  // 全局變量
js> var obj = { x:7, y:8 };
js> with (obj) {
    print(x);  // 如果要查找變量 x卿城,則會(huì)在查找全局變量 x 之前先查找到 obj.x
}
7

注釋:

// 單行注釋
/* 注釋 */

運(yùn)算符和操作數(shù)在英語中分別稱為 operator 和 operand枚钓。

// 賦值表達(dá)式的結(jié)合律為右結(jié)合
x = y = z = 0;
將以
x = (y = (z = 0);
的方式被求值

在 JavaScript 所有算術(shù)運(yùn)算中的數(shù)值都是浮點(diǎn)小數(shù)。

ECMAScript 中瑟押,=== 被稱為 Strict Equals 運(yùn)算符搀捷,而 == 則被稱為 Equals 運(yùn)算符。
將 Strict Equals 運(yùn)算符(===)稱為全等運(yùn)算符多望,而將 Equals 運(yùn)算符(==)稱為相等運(yùn)算符嫩舟。兩者的區(qū)別在于,是否會(huì)在進(jìn)行相等判定時(shí)進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換怀偷。
全等運(yùn)算不會(huì)進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換家厌,因此數(shù)據(jù)類型是否一致也是判斷是否相等的內(nèi)容之一。而相等運(yùn)算 (==)會(huì)先進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換椎工,在數(shù)據(jù)類型相同后再進(jìn)行相等判斷饭于。兩種運(yùn)算符的運(yùn)算結(jié)果都是布爾值蜀踏。

下面總結(jié)了全等運(yùn)算的一些特性。

  • 1.?x 與 y 如果數(shù)據(jù)類型不相符掰吕,則結(jié)果為假果覆。
  • 2.?兩者都是 undefined 值或兩者都是 null 值的情況,結(jié)果為真殖熟。
  • 3.??兩者都是數(shù)值随静,但有一方為 NaN,或者兩者都是 NaN 的情況吗讶,結(jié)果為假燎猛。否則,如果數(shù)值相等則結(jié)果為真照皆,不相等則為假重绷。
  • 4.?兩者都是字符串的情況下,如果內(nèi)容一致則結(jié)果為真膜毁,否則結(jié)果為假昭卓。
  • 5.?兩者都是布爾值的情況下,如果值一致則結(jié)果為真瘟滨,否則結(jié)果為假候醒。
  • 6.?兩者都是對象引用的情況下,如果引用的是同一個(gè)對象則結(jié)果為真杂瘸,否則結(jié)果為假倒淫。

相等運(yùn)算 == 由于會(huì)進(jìn)行隱式數(shù)據(jù)類型轉(zhuǎn)換,所以其執(zhí)行方式更為復(fù)雜败玉。下面是對其運(yùn)算規(guī)則的總結(jié)敌土。

● x 與 y 的數(shù)據(jù)類型相同時(shí),與全等運(yùn)算的結(jié)果相同运翼。
? ● x 與 y 的數(shù)據(jù)類型不同時(shí)返干,判定規(guī)則如下。
 ?(1)一方為 null 值血淌,另一方為 undefined 值的情況矩欠,結(jié)果為真。
 ?(2)一方為數(shù)值悠夯,另一方為字符串值的情況癌淮,將字符串值轉(zhuǎn)換為數(shù)值之后對數(shù)值進(jìn)行比較。
 ?(3)一方為布爾值疗疟,另一方為數(shù)值的情況该默,將布爾值轉(zhuǎn)換為數(shù)值之后對數(shù)值進(jìn)行比較瞳氓。
 ?(4)一方為布爾值策彤,另一方為字符串值的情況栓袖,將兩者都轉(zhuǎn)換為數(shù)值后對數(shù)值進(jìn)行比較。
 ?(5)一方為數(shù)值店诗,另一方為對象引用的情況裹刮,將對象引用轉(zhuǎn)換為數(shù)值后對數(shù)值進(jìn)行比較。
 ?(6)一方為字符串值庞瘸,另一方為對象引用的情況捧弃,將對象引用轉(zhuǎn)換為字符串值后對字符串的內(nèi)容進(jìn)行比較。
 ?(7)以上 6 種情況之外的運(yùn)算結(jié)果都為假

void 運(yùn)算符:

無論向其傳遞什么操作數(shù)擦囊,其運(yùn)算結(jié)果都會(huì)是 undefined 值违霞。下面是一個(gè)具體的例子。

js> print(void 0);  // 操作數(shù)為數(shù)值
undefined
js> print(void 'x'); // 操作數(shù)為字符串值
undefined
js> var x = 0;
js> void x++; // 由于會(huì)先對操作數(shù)進(jìn)行求值瞬场,所以 x 將自增
js> print(x);
1
js> void(x); // 常常會(huì)把操作數(shù)通過括號(hào)包圍起來

在客戶端 JavaScript 中有不少相關(guān)的習(xí)慣用法买鸽。下面是一個(gè)在 HTML 中點(diǎn)擊了標(biāo)簽 a 之后發(fā)送表單內(nèi)容的 JavaScript 代碼的例子。

<a href="javascript:void(document.form.submit())"> 發(fā)送 HTML 表單數(shù)據(jù)但不跳轉(zhuǎn)頁面 </a>

hred 屬性中所寫的表達(dá)式如果具有值的話贯被,則會(huì)被標(biāo)簽 a 認(rèn)為是 URL 并跳轉(zhuǎn)至該頁面眼五。為了阻止標(biāo)簽 a 的這一行為,需要將 href 屬性中表達(dá)式的值強(qiáng)制設(shè)為 undefined 值彤灶。對此最為簡單的慣用方法就是通過 void 運(yùn)算來實(shí)現(xiàn)看幼。

逗號(hào)運(yùn)算符(,)是一個(gè)雙目運(yùn)算符,其作用為依次對其左操作數(shù)與右操作數(shù)求值幌陕。逗號(hào)運(yùn)算符的運(yùn)
算結(jié)果是其右操作數(shù)的值诵姜,也就是說其結(jié)果的類型取決于所使用的操作數(shù)。下面是一個(gè)具體的例子搏熄。

js> print((x = 1, y = 2)); // 請注意茅诱,如果不在真?zhèn)€參數(shù)外加括號(hào)的話,其含義就會(huì)變?yōu)閰?shù)的數(shù)量是兩個(gè)
2
js> print((x = 1, ++x, ++x)); // 由于是左結(jié)合搬卒,相當(dāng)于 ((x = 1, ++x), ++x)
3

字符 .(點(diǎn))稱為點(diǎn)運(yùn)算符瑟俭,中括號(hào) [] 稱為中括號(hào)運(yùn)算符,它們都是用于訪問屬性的運(yùn)算符契邀。雖然這
兩個(gè)運(yùn)算符不太顯眼摆寄,卻有著很重要的作用。
其左操作數(shù)為對象引用坯门,右操作數(shù)為屬性名微饥。如果左操作數(shù)不是對象引用的話,則會(huì)被轉(zhuǎn)換為
Object 類型古戴。點(diǎn)運(yùn)算符的右操作數(shù)是一個(gè)用于表示屬性名的標(biāo)識(shí)符欠橘,而中括號(hào)運(yùn)算符的右操作數(shù)為字符
串型或是可以被轉(zhuǎn)換為字符串型的值。

第五章 變量與對象

var a = a || 7;  // 一種習(xí)慣用法现恼。如果變量 a 已經(jīng)具有某個(gè)值(嚴(yán)格來說是具有某個(gè)可以被轉(zhuǎn)換為 true 的值)就直接使用肃续,否則就把 7 賦值給 a

準(zhǔn)確地說黍檩,對象的賦值其實(shí)是將對象的引用進(jìn)行賦值。變量有值類型和引用類型始锚。將基本類型的值賦值給變量的話刽酱,變量將把這個(gè)值本身保存起來。這時(shí)瞧捌,可以將變量簡單地理解為一個(gè)裝了該值的箱子棵里。變量本身裝有所賦的這個(gè)值,所以能夠?qū)⒃撝祻淖兞恐腥〕觥?/p>

如果將一個(gè)對象賦值給變量姐呐,其實(shí)是把這個(gè)對象的引用賦值給了該變量殿怜。對象本身是無法賦值給一個(gè)變量的。如果在右側(cè)寫上了這樣的變量曙砂,該變量所表示的引用將被復(fù)制給賦值目標(biāo)處(左側(cè))的變量稳捆。對象本身并不會(huì)被復(fù)制。 var a = {x:2, y:3} “變量 a 所引用的對象".

在上下文不會(huì)發(fā)生誤會(huì)的情況下麦轰,可以用“對象”這一術(shù)語來指代“對象的引用”乔夯。對象是一個(gè)實(shí)體,而引用是用于指示這一實(shí)體的位置信息款侵,兩者本應(yīng)是不同的末荐。不過根據(jù)上下文可以知
道,“將對象賦值給變量 a”的說法很顯然是指將對象的引用賦值新锈,所以方便起見可以直接這么說甲脏。

變量和屬性

很多讀者都會(huì)覺得對象的屬性和變量非常相似吧。兩者都可以通過其名字(變量名或?qū)傩悦﹣慝@取其值妹笆,也都可以作為賦值對象块请,而寫在賦值表達(dá)式的左側(cè)。其實(shí)拳缠,在 JavaScript 中變量就是屬性墩新,兩者何止是相似,本身就是同一個(gè)概念窟坐。全局變量和局部變量兩者的本質(zhì)都是屬性海渊。全局變量(以及全局函數(shù)名)是全局對象的屬性。全局對象是從程序運(yùn)行一開始就存在的對象哲鸳。下面的代碼證明臣疑,全局變量即為全局對象的屬性。

js> var x = 'foo';  // 對全局變量 x 進(jìn)行賦值
js> print(this.x);  // 可以通過 this.x 進(jìn)行訪問
foo
js> function fn() {return "functon"}; // 全局函數(shù)徙菠。
js> 'fn' in this; // 全局對象的屬性 fn
true

js>this.fn() // "function"

最外層代碼中的 this 引用是對全局對象的引用讯沈。因此上面代碼中的 this.x,指的就是全局對象的屬性 x婿奔,這也就是全局變量 x缺狠。

像下面這樣问慎,在最外層代碼中將 this 引用的值賦值給全局變量 global 的話,這個(gè)變量就不但是全局對象的屬性儒老,同時(shí)也是一個(gè)對全局對象的引用蝴乔,從而形成了一種自己引用自己的關(guān)系.

js> var global = this;  // 將 this 引用賦值給全局變量 global
js> 'global' in this; // 全局對象的屬性 global
true

在最外層代碼中對變量名進(jìn)行查找记餐,就是查找全局對象的屬性驮樊。這其實(shí)只是換了一種說法,在最外層代碼中能夠使用的變量與函數(shù)片酝,只有全局變量與全局函數(shù)而已囚衔。

至于對函數(shù)內(nèi)的變量名的查找,前一節(jié)中已經(jīng)介紹過雕沿,是按照先查找 Call 對象的屬性练湿,再查找全局對象的屬性來進(jìn)行的。這相當(dāng)于在函數(shù)內(nèi)可以同時(shí)使用局部變量(以及參數(shù)變量)與全局變量审轮。對于
嵌套函數(shù)的情況肥哎,則會(huì)由內(nèi)向外依次查找函數(shù)的 Call 對象的屬性,并在最后查找全局對象的屬性疾渣。

對變量是否存在的檢驗(yàn)

var a = a || 7;  // 一種習(xí)慣用法篡诽。如果變量 a 已經(jīng)具有某值,則使用變量 a 的值
// 如果變量 a 已經(jīng)具有某值榴捡,則使用變量 a 的值杈女。代碼示例(1)
var a;
var b = a || 7;

// 如果變量 a 已經(jīng)具有某值,則使用變量 a 的值吊圾。代碼示例(2)
var a;
var b = a !== undefined ? a : 7;

// 如果變量 a 已經(jīng)具有某值达椰,則使用變量 a 的值。代碼示例(3)
// (不使用 var a 的版本)
if (typeof a !== 'undefined') {
    var b = a;
} else {
    var b = 7;
}
// 從這里開始可以使用變量 b, 因?yàn)?Javascript 中沒有塊級作用域项乒。

可以在最外層代碼中啰劲,像下面這樣來判斷在全局對象中是否存在屬性 a,也就是說檀何,可以用來檢測
全局變量 a 是否存在呈枉。

// 用于判斷變量 a 是否已經(jīng)被聲明的代碼
if ('a' in this) {
    var b = a;
} else {
    var b = 7;
}
// 從這里開始可以使用變量 b

對屬性是否存在的檢驗(yàn)

變量與屬性實(shí)質(zhì)上是一樣的。不過埃碱,如果變量或?qū)傩员旧聿淮嬖诓瑁幚矸绞絼t會(huì)有所不同。請看下面的例子:

js> print(x); // 訪問未聲明的變量會(huì)導(dǎo)致 ReferenceError 異常
ReferenceError: x is not defined
js> print(this.x);  // 訪問不存在的屬性并不會(huì)引起錯(cuò)誤
undefined
js> var obj = {};
js> print(obj.x); // 讀取不存在的屬性僅會(huì)返回 undefined 值砚殿,并不會(huì)引起錯(cuò)誤
undefined

讀取不存在的屬性僅會(huì)返回 undefined 值啃憎,而不會(huì)引起錯(cuò)誤。但是如果對 undefined 值進(jìn)行屬性訪問的話似炎,則會(huì)像下面這樣產(chǎn)生 TpyeError 異常辛萍。

js> print(obj.x.y);
TypeError: obj.x is undefined

為了避免產(chǎn)生 TypeError 異常悯姊,一般會(huì)使用下面的方法。

obj.x && obj.x.y

但如果是為了檢測對象內(nèi)是否存在某一屬性贩毕,還請使用 in 運(yùn)算符悯许。

構(gòu)造函數(shù)與 new 表達(dá)式

構(gòu)造函數(shù)是用于生成對象的函數(shù)』越祝可以直觀地將代碼清單 5.8 理解為 MyClass 類的類定義先壕。在調(diào)用時(shí)通過 new 來生成一個(gè)對象實(shí)例。

// 構(gòu)造函數(shù)(類的定義)
function MyClass(x, y) {
    this.x = x;
    this.y = y;
}

// 對代碼清單 5.8 的構(gòu)造函數(shù)的調(diào)用
js> var obj = new MyClass(3, 2);
js> print(obj.x, obj.y);
3 2

從形式上來看谆甜,構(gòu)造函數(shù)的調(diào)用方式如下垃僚。
? ● 構(gòu)造函數(shù)本身和普通的函數(shù)聲明形式相同。
? ● 構(gòu)造函數(shù)通過 new 表達(dá)式來調(diào)用规辱。
? ● 調(diào)用構(gòu)造函數(shù)的 new 表達(dá)式的值是(被新生成的)對象的引用谆棺。
? ● 通過 new 表達(dá)式調(diào)用的構(gòu)造函數(shù)內(nèi)的 this 引用引用了(被新生成的)對象

  • new 表達(dá)式的操作

在此說明一下 new 表達(dá)式在求值時(shí)的操作。首先生成一個(gè)不具有特別的操作對象罕袋。之后通過 new 表達(dá)式調(diào)用指定的函數(shù)(即構(gòu)造函數(shù))改淑。構(gòu)造函數(shù)內(nèi)的 this 引用引用了新生成的對象。執(zhí)行完構(gòu)造函數(shù)后浴讯,它將返回對象的引用作為 new 表達(dá)式的值朵夏。new 表達(dá)式的操作就是以上這些。實(shí)際上其中還含有一個(gè)和原型鏈有關(guān)的問題兰珍,將會(huì)在之后進(jìn)行說明侍郭。

img

構(gòu)造函數(shù)總是由 new 表達(dá)式調(diào)用。為了和普通的函數(shù)調(diào)用區(qū)別開掠河, 將使用 new 表達(dá)式的調(diào)用稱為構(gòu)造函數(shù)的調(diào)用亮元。構(gòu)造函數(shù)的名稱一般以大寫字母開始。(例如 MyClass)唠摹。
構(gòu)造函數(shù)在最后會(huì)隱式地執(zhí)行 return this 操作爆捞。所以構(gòu)造函數(shù)最終會(huì)返回新生成的這個(gè)對象。

構(gòu)造函數(shù)與類的定義

// 模擬類定義(尚有改進(jìn)的余地)

// 相當(dāng)于類的定義
function MyClass(x, y) {
    // 相當(dāng)于域
    this.x = x;
    this.y = y;
    // 相當(dāng)于方法
    this.show = function() {
        print(this.x, this.y);
    }
}

// 對代碼清單 5.9 中的構(gòu)造函數(shù)的調(diào)用(實(shí)例生成)
js> var obj = new MyClass(3, 2);
js> obj.show();
3 2

這段代碼簡單地實(shí)現(xiàn)了Javascript 的定義勾拉, 但是有兩個(gè)問題:

● 由于所有的實(shí)例都是復(fù)制了同一個(gè)方法所定義的實(shí)體煮甥,所以效率(內(nèi)存效率與執(zhí)行效率)低下。
● 無法對屬性值進(jìn)行訪問控制(private 或 public 等)藕赞。

前者可以通過原型繼承來解決成肘,后者可以通過閉包來解決。

屬性的訪問

通過點(diǎn)運(yùn)算符和方括號(hào)運(yùn)算符來訪問對象的屬性斧蜕。在點(diǎn)運(yùn)算符之后書寫的屬性名會(huì)被認(rèn)為是標(biāo)識(shí)符双霍,而中括號(hào)運(yùn)算符內(nèi)的則是被轉(zhuǎn)為字符串值的表達(dá)式。

js> var obj = { x:3, y:4 };
js> print(obj.x); // 屬性 x
3
js> print(obj['x']); // 屬性 x
3
js> var key = 'x';
js> print(obj[key]); // 屬性 x(而非屬性 key)
3

屬性訪問的運(yùn)算對象并不是變量,而是對象的引用

js> ({x:3, y:4}).x;  // 屬性 x
3

js> ({x:3, y:4})['x'];  // 屬性 x
3

現(xiàn)實(shí)中幾乎不會(huì)對對象字面量進(jìn)行運(yùn)算洒闸。不過當(dāng)這種運(yùn)算對象不是一個(gè)變量時(shí)染坯,倒是常常會(huì)以方法鏈之類的形式出現(xiàn)。

點(diǎn)運(yùn)算符與中括號(hào)運(yùn)算符在使用上的區(qū)別

只能使用中括號(hào)運(yùn)算符的情況分為以下幾種丘逸。
? ● 使用了不能作為標(biāo)識(shí)符的屬性名的情況单鹿。
? ● 將變量的值作為屬性名使用的情況。
? ● 將表達(dá)式的求值結(jié)果作為屬性名使用的情況深纲。

// 含有橫杠的屬性名
js> obj = { 'foo-bar':5 };
js> obj.foo-bar; // 將解釋為 obj.foo 減去 bar仲锄,從而造成錯(cuò)誤
ReferenceError: bar is not defined

無法作為標(biāo)識(shí)符被使用的字符串,仍可以在中括號(hào)運(yùn)算符中使用囤萤。

js> obj['foo-bar'];  // 使用 [] 運(yùn)算以字符串值指定了一個(gè)屬性名昼窗∈桥浚可以正常執(zhí)行
5

屬性的枚舉

可以通過 for in 語句對屬性名進(jìn)行枚舉(代碼清單 5.10)涛舍。通過在 for in 語句中使用中括號(hào)運(yùn)算符,可以間接地實(shí)現(xiàn)對屬性值的枚舉唆途。使用 for each in 語句可以直接枚舉屬性值富雅。

var obj = { x:3, y:4, z:5 };
for (var key in obj) {
    print('key = ', key); // 屬性名的枚舉
    print('val = ', obj[key]); // 屬性值的枚舉
}

// 代碼清單 5.10 的運(yùn)行結(jié)果
key = x
val = 3
key = y
val = 4
key = z
val = 5

屬性可以分為直接屬性以及繼承于原型的屬性。for in 語句和 for each in 語句都會(huì)枚舉繼承于原型的屬性肛搬。

作為關(guān)聯(lián)數(shù)組的對象

在 JavaScript 中没佑,必須通過對象來實(shí)現(xiàn)關(guān)聯(lián)數(shù)組(字典、散列)

簡單說來温赔,原型繼承指的是一種對象繼承其他對象的屬性并將其作為自身的屬性一樣來使用的做法蛤奢。如下所示,從形式上來說陶贼,對象 obj 的屬性并不是其直接屬性啤贩,而是通過原型繼承而得到的屬性。

js> function MyClass() {}
js> MyClass.prototype.z = 5;  // 在原型鏈上設(shè)定屬性 z
js> var obj = new MyClass();  // 屬性 z 繼承了原型
js> print(obj.z);
5

for in 語句將枚舉通過原型繼承而得到的屬性拜秧。

// 接之前的代碼
js> for (var key in obj) { print(key); }  // for in 語句也會(huì)枚舉通過原型繼承得到的屬性
z

請注意痹屹,通過原型繼承而得到的屬性無法被 delete。繼續(xù)接之前的代碼枉氮。

// 接之前的代碼
js> delete obj.z; // 盡管沒有被 delete志衍,但還是會(huì)返回 true……

true
js> print(obj.z); // 無法 delete 通過原型繼承而得到的屬性
5

即使通過使用空的對象字面量創(chuàng)建一個(gè)沒有元素的空的關(guān)聯(lián)數(shù)組, 也仍然會(huì)從 Object 類中繼承原型的屬性聊替。 可以通過 in 運(yùn)算對此進(jìn)行檢驗(yàn)楼肪。

js> var map = { };         // 通過空的對象字面量生成關(guān)聯(lián)數(shù)組
js> 'toString' in map;    // map 所引用的對象從 Object 類中繼承了屬性 toString
true

但是,通過 for in 語句對元素進(jìn)行枚舉不會(huì)有任何效果惹悄。這是由于 enumerable 屬性的緣故春叫,將在之后的小節(jié)中說明。

// 接之前的代碼
js> for (var key in map) {
   print(key);
}
// 沒有元素會(huì)被枚舉

通過 in 運(yùn)算符檢測關(guān)聯(lián)數(shù)組的鍵是否存在,就會(huì)發(fā)生與原型繼承而來的屬性相關(guān)的問題象缀。因此蔬将,像下面這樣通過 hasOwnProperty 來對其進(jìn)行檢測,是一種更安全的做法央星。

js> var map = {};
js> map.hasOwnProperty('toString');      // 由于 toString 不是直接屬性霞怀,因此結(jié)果為 false
false
js> map['toString'] = 1;
js> map.hasOwnProperty('toString');
true
js> delete map['toString'];
js> map.hasOwnProperty('toString');
false

屬性的屬性

在標(biāo)準(zhǔn)的對象中有一部分屬性的 enumerable 屬性為假而無法通過 for in 語句枚舉。其中一個(gè)很容易理解的例子是數(shù)列的 length 屬性莉给。

屬性的屬性名
含義

writable
可以改寫屬性值

enumerable
可以通過 for in 語句枚舉

configurable
可以改變屬性的屬性咆贬。可以刪除屬性

get
可以指定屬性值的 getter 函數(shù)

set
可以指定屬性值的 setter 函數(shù)

垃圾回收

不再使用的對象的內(nèi)存將會(huì)自動(dòng)回收凌盯,這種功能稱作垃圾回收粮宛。所謂不再使用的對象,指的是沒有被任何一個(gè)屬性(變量)引用的對象叁幢。

循環(huán)引用會(huì)造成內(nèi)存泄漏滤灯。所謂循環(huán)引用,指的是對象通過屬性相互引用而導(dǎo)致它們不會(huì)被判定為不再使用的狀態(tài)曼玩。

不可變對象

所謂不可變對象鳞骤,指的是在被生成之后狀態(tài)不能再被改變的對象。由于對象的狀態(tài)是由其各個(gè)屬性的值所決定的黍判,因此從形式上來說也是指無法改變屬性的值的對象

JavaScript 中的一種典型的不可變對象就是字符串對象豫尽。

在 JavaScript 中可以通過以下方式實(shí)現(xiàn)對象的不可變。

● 將屬性(狀態(tài))隱藏顷帖,不提供變更操作美旧。
? ● 靈活運(yùn)用 ECMAScript 第 5 版中提供的函數(shù)。
? ● 靈活運(yùn)用 writable 屬性贬墩、configurable 屬性以及 setter 和 getter榴嗅。

為了將屬性隱藏,可以使用一種被稱為閉包的方法震糖。

在 ECMAScript 第 5 版中有一些用于支持對象的不可變化的函數(shù)(表 5.2)录肯。seal 可以向下兼容 preventExtensions,freeze 可以向下兼容 seal吊说。這里的向下兼容论咏,指的是比后者有更為嚴(yán)格的限制。

ECMAScript 第 5 版中用于支持對象的不可變化的函數(shù)

方法名
屬性新增
屬性刪除
屬性值變更
確認(rèn)方法

preventExtensions
X
O
O
Object.isExtensible

seal
X
X
O
Object.isSealed

freeze
X
X
X
Object.isFrozen

Object.preventExtensions 的例子

js> var obj = { x:2, y:3 };
js> Object.preventExtensions(obj);
// 無法新增屬性
js> obj.z = 4;
js> Object.keys(obj);
["x", "y"]
// 可以刪除屬性
js> delete obj.y;
js> Object.keys(obj);
["x"]
// 可以更改屬性值
js> obj.x = 20;
js> print(obj.x);
20

Object.seal 的例子

js> var obj = { x:2, y:3 };
js> Object.seal(obj);
// 無法刪除屬性
js> delete obj.y; // 將返回 false
js> Object.keys(obj);
["x", "y"]
// 可以更改屬性值
js> obj.x = 20;
js> print(obj.x);
20

Object.freeze 的例子

js> var obj = { x:2, y:3 };
js> Object.freeze(obj);
// 無法更改屬性值
js> obj.x = 20;
js> print(obj.x);
2

● 一旦更改就無法還原颁井。
● 如果想讓原型繼承中的被繼承方也不可變化厅贪,需要對其進(jìn)行顯式的操作。

方法

我們將作為對象屬性的函數(shù)稱為方法雅宾。那些使用了 this 引用來調(diào)用并訪問了對象的屬性的函數(shù)养涮,被稱為方法。

this 引用

this 引用有著會(huì)根據(jù)代碼的上下文語境自動(dòng)改變其引用對象的特性。

在此贯吓,總結(jié)一下 this 引用的規(guī)則。

● 在最外層代碼中悄谐,this 引用引用的是全局對象。
● 在函數(shù)內(nèi)爬舰,this 引用根據(jù)函數(shù)調(diào)用方式的不同而有所不同(參見表 5.3)。

對于函數(shù)內(nèi)部的情況情屹,this 引用的引用對象并不是根據(jù)函數(shù)的內(nèi)容或聲明方式而改變的,而是根據(jù)其調(diào)用方式而改變椅文。也就是說,即使是同一個(gè)函數(shù)雾袱,如果調(diào)用方式不同官还,this 引用的引用對象也會(huì)有所不同。

函數(shù)內(nèi)部的 this 引用

函數(shù)的調(diào)用方式
this 引用的引用對象

構(gòu)造函數(shù)調(diào)用
所生成的對象

方法調(diào)用
接收方對象

apply 或是 call 調(diào)用
由 apply 或 call 的參數(shù)指定的對象

其它方式的調(diào)用
全局對象

對于構(gòu)造函數(shù)調(diào)用的情況毒坛,this 引用的引用對象是所生成的對象望伦。 上表中的方法調(diào)用的說明中的接收方對象是這樣一種對象:?● 通過點(diǎn)運(yùn)算符或中括號(hào)運(yùn)算符調(diào)用對象的方法時(shí),在運(yùn)算符左側(cè)所指定的對象煎殷。

方法是對象的屬性所引用的函數(shù)屯伞。下面是一個(gè)關(guān)于方法和接收方對象的具體例子。

// 對象定義
js> var obj = {
    x:3,
    doit: function() { print('method is called.' + this.x ); }
};
js> obj.doit();  // 對象 obj 是接收方對象豪直。doit 是方法劣摇。
method is called. 3
js> obj['doit']();  // 對象 obj 是接收方對象。doit 是方法弓乙。
method is called. 3

現(xiàn)在說明上面的例子末融。首先是將對象的引用賦值給了變量 obj。這個(gè)對象有兩個(gè)屬性暇韧。屬性 x 的值為數(shù)值 3勾习,屬性 doit 的值是一個(gè)函數(shù)。將該函數(shù)稱為方法 doit懈玻∏缮簦可以通過點(diǎn)運(yùn)算符或中括號(hào)運(yùn)算符對 obj 調(diào)用方法 doit。這時(shí),方法調(diào)用的目標(biāo)對象被稱為接收方對象(也就是說艺栈,obj 所引用的對象是一個(gè)接收方對象)英岭。被調(diào)用的方法內(nèi)的 this 引用引用了該接收方對象。

this 引用注意點(diǎn)

在 Java 中, this 所引用的接收方對象始終是該類的實(shí)例, 而在 Javascript 中卻不一定總是如此湿右。Javascript 的 this 引用的引用對象會(huì)隨著方法調(diào)用方式的不同而改變巴席。

var obj = { 
    x : 3;
    doit: function() { print('method is called.' + this.x ); }
}

var fn = obj.doit;       // 將 ojb.doit 引用的 Function 對象賦值給全局變量
fn();                          // 函數(shù)內(nèi)的 this 引用引用了全局對象, 現(xiàn)在全局變量中還沒有定義變量 x, 所以下面會(huì)打印 undefined
method is called. undefined
var x = 5;                 // 確認(rèn) this 引用確實(shí)引用了全局對象
fn();
method is called. 5
var obj2 = { x:4, doit2:fn };  //  將obj的方法(Function對象的引用)賦值給了另一個(gè)對象obj2的屬性
obj2.doit2(); // 方法內(nèi)的 this 引用引用了對象 obj2
method is called. 4

在方法內(nèi)部調(diào)用方法的情況

// 從 doit 方法內(nèi)調(diào)用 doit2 方法時(shí),必須通過 this 引用诅需,以 this.doit2() 的方式實(shí)現(xiàn)
js> var obj = {
x:3,
doit: function() { print('doit is called.' + this.x ); this.doit2(); },
doit2: function() { print('doit2 is called.' + this.x); }
};
js> obj.doit();
doit is called. 3
doit2 is called. 3

apply 與 call

在 Function 對象中包含 apply 與 call 這兩種方法漾唉,通過它們調(diào)用的函數(shù)的 this 引用,可以指向任意特定的對象堰塌。也就是說,可以理解為它們能夠顯式地指定接收方對象般此。

js> function f() { print(this.x); }
js> var obj = { x:4 };
js> f.apply(obj); // 通過 apply 調(diào)用函數(shù) f铐懊。函數(shù)內(nèi)的 this 引用引用了對象 obj
4
js> f.call(obj); // 通過 call 調(diào)用函數(shù) f瞎疼。函數(shù)內(nèi)的 this 引用引用了對象 obj
4
// 將接收方對象指定為另一個(gè)對象并進(jìn)行方法調(diào)用
js> var obj = {
    x:3,
    doit: function() { print('method is called.' + this.x ); }
};
js> var obj2 = { x:4 };
js> obj.doit.apply(obj2);  // 通過 apply 調(diào)用 obj.doit 方法贼急。方法內(nèi)的 this 引用引用了對象 obj2

method is called. 4

apply 與 call 之間的不同之處在于兩者對其他參數(shù)的傳遞方式太抓。對于 apply 來說走敌,剩余的參數(shù)將通過數(shù)組來傳遞掉丽,而 call 是直接按原樣傳遞形參。

js> function f(a, b) { print('this.x = ' + this.x + ', a = ' + a + ', b = ' + b); }
js> f.apply({x:4}, [1, 2]);  // 作為第 2 個(gè)參數(shù)的數(shù)列中的元素都是函數(shù) f 的參數(shù)
this.x = 4, a = 1, b = 2
js> f.call({x:4}, 1, 2);  // 從第 2 個(gè)參數(shù)起的參數(shù)都是函數(shù) f 的參數(shù)
this.x = 4, a =1 , b = 2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市残邀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌耻台,老刑警劉巖盆耽,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摄杂,死亡現(xiàn)場離奇詭異析恢,居然都是意外死亡秧饮,警方通過查閱死者的電腦和手機(jī)盗尸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門泼各,熙熙樓的掌柜王于貴愁眉苦臉地迎上來历恐,“玉大人弱贼,你說我怎么就攤上這事吮旅”硬” “怎么了责嚷?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵罕拂,是天一觀的道長。 經(jīng)常有香客問我衷掷,道長戚嗅,這世上最難降的妖魔是什么懦胞? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任医瘫,我火速辦了婚禮醇份,結(jié)果婚禮上僚纷,老公的妹妹穿的比我還像新娘怖竭。我一直安慰自己痊臭,他們只是感情好登夫,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布鸦致。 她就那樣靜靜地躺著分唾,像睡著了一般绽乔。 火紅的嫁衣襯著肌膚如雪碳褒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天鹃觉,我揣著相機(jī)與錄音盗扇,去河邊找鬼疗隶。 笑死斑鼻,一個(gè)胖子當(dāng)著我的面吹牛猎荠,可吹牛的內(nèi)容都是我干的关摇。 我是一名探鬼主播输虱,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼愁茁,長吁一口氣:“原來是場噩夢啊……” “哼鹅很!你這毒婦竟也來了命贴?” 一聲冷哼從身側(cè)響起胸蛛,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤葬项,失蹤者是張志新(化名)和其女友劉穎民珍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陋桂,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嗜历,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年梨州,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了暴匠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片每窖。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡窒典,死狀恐怖崇败,靈堂內(nèi)的尸體忽然破棺而出后室,到底是詐尸還是另有隱情岸霹,我是刑警寧澤将饺,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布刮吧,位于F島的核電站杀捻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏致讥。R本人自食惡果不足惜垢袱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一请契、第九天 我趴在偏房一處隱蔽的房頂上張望姚糊。 院中可真熱鬧救恨,春花似錦肠槽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孝冒。三九已至庄涡,卻和暖如春搬设,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泣洞。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工斜棚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弟蚀,地道東北人义钉。 一個(gè)月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像拖刃,于是被迫代替她去往敵國和親兑牡。 傳聞我的和親對象是個(gè)殘疾皇子均函,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容