第1章 原始類型和引用類型
1.1 對象的兩種類型:
JavaScript使用一個變量對象追蹤變量的生存期。原始類型保存為簡單的值,引用類型則保存為對象,其本質(zhì)是指向內(nèi)存位置的引用。
1.2 原始類型
1..2.1 五種原始類型:
Boolean
Number
String
Null
Undefined
1.2.2 鑒別原始類型
使用typeof 操作符
console.log(typeof 10); //'number'
console.log(typeof “123”); //“string”
console.log(typeof true); //'boolean'
console.log(typeof undefined); //'undefined'
//null為特例,可通過和null值進(jìn)行比較判斷
console.log(typeof null); //'object'
console.log(value===null); //true or false
1.3 引用類型:
1.3.1創(chuàng)建對象(實例化對象)
使用new操作符
var object = new Object();
該代碼實例化了一個通用對象,并將它的引用保存在object中。object變量實際上并不保存對象的實例,而是一個指向內(nèi)存中實際對象所在位置的指針(或者說引用)。
1.3.2 引用對象解除
解除引用的最佳手段是將對象變量置為null。在不使用對象時將其引用解除,會讓垃圾收集器對那塊內(nèi)存進(jìn)行釋放。
var object1 = new Object();
//doing something
object = null;
1.3.3 六種內(nèi)建類型:
Object
Array
Function
Date
RegExp
Error
內(nèi)建類型實例化
使用new操作符來實例化每一個內(nèi)建引用類型:
var object = new Object();
var items = new Array();
var func = new Function('console.log('hi');'); //稱為構(gòu)造函數(shù)
var now = new Date();
var re = new RegExp('\\d+');
var error = new Error('something bad happened.');
字面形式,字面形式允許不使用new操作符和構(gòu)造函數(shù)顯示創(chuàng)建對象的情況下生成引用值。
//對象字面形式
var person = {
name:'liang',
sayName:function(){
return this.name;
}
};
person.year = 1992; //添加對象的屬性
var items = ['item1','item2','item3'];
//函數(shù)字面形式,函數(shù)聲明
function func(value){
return value;
}
//函數(shù)字面形式,函數(shù)表達(dá)式(匿名函數(shù))
var func = function(){
statement;
};
//正則表達(dá)式字面形式
var numbers = /\d+/g;
1.3.4 訪問屬性
var array = [];
array.push(123); //使用點號
array['push'](456); //使用中括號
//中括號允許使用動態(tài)訪問方法
var method = 'push';
array[method](789);
點號更易讀,但使用中括號可允許你在屬性名字上使用特殊字符。
1.3.5 鑒別引用類型
對于函數(shù),typeof 操作符返回“function”;
其他非函數(shù)的引用類型,typeof 操作符都返回“object”。因此,使用instanceof 操作符來區(qū)分其他引用類型。
instanceof 操作符以一個對象和一個構(gòu)造函數(shù)為參數(shù)。如果對象是構(gòu)造函數(shù)所指定的類型的一個實例,instanceof 返回true;否則返回false。
var items = [];
var object = {};
function reflect(){
return value;
}
console.log(typeof reflect); //'function'
console.log(items instanceof Array); //true
console.log(object instanceof Object); //true
console.log(reflect instanceof Function); //true
//這些引用類型也都是Object的實例,instanceof 操作符可鑒別繼承類型。
console.log(items instanceof Object); //true
console.log(reflect instanceof Object); //true
1.3.6 鑒別數(shù)組
instanceof 可以鑒別數(shù)組,但有一個例外,當(dāng)你把一個數(shù)組從一個框架傳到另一個框架時,instanceof 就無法識別,因為這個數(shù)組是來自不同框架的Array的實例。
使用Array.isArray()鑒別數(shù)組,IE8及更早版本不支持。
var items = [];
console.log(Aray.isArray(items)); //true
1.4 原始封裝類型
原始封裝類型共有3種(String, Number 和 Boolean)。
當(dāng)讀取字符串、數(shù)字或布爾值時,原始封裝類型將被自動創(chuàng)建。這種特殊引用類型的存在使得原始類型用起來和對象一樣方便。
//第二行代碼把name當(dāng)成一個對象,調(diào)用了charAt方法
var name = 'liang';
var firstChar = name.charAt(0);
console.log(firstChar); //'l'
/*
背后的工作原理:創(chuàng)建了一個臨時對象,隨后被銷毀
var name = 'liang';
var temp = new String(name);
var firstChar = temp.charAt(0);
temp = null;
console.log(firstChar); //'l'
*/
//臨時對象僅在值被讀取時創(chuàng)建,instanceof并沒有真的讀取任何東西,因此為false
console.log(typeof name); //string
console.log(name instanceof String); //false
第2章 函數(shù)
函數(shù)其實就是對象。使函數(shù)不同于其他對象的決定性特點是函數(shù)存在一個被稱為[[call]]的內(nèi)部屬性。
內(nèi)部屬性無法通過代碼訪問,它定義了代碼執(zhí)行時的行為。
[[call]]是函數(shù)獨有的,表明該對象可以被執(zhí)行。
2.1 聲明還是表達(dá)式
函數(shù)有兩種字面形式。第一種以function關(guān)鍵字開頭,后面跟著函數(shù)的名字。第二種是函數(shù)表達(dá)式,function后面不需要跟著函數(shù)名,這種函數(shù)被稱為匿名函數(shù)。
//函數(shù)聲明
function add(num1,num2){
return num1 + num2;
}
//函數(shù)表達(dá)式
var push = function(num1,num2){
return num1 + num2;
};
兩者中最重要的區(qū)別是,函數(shù)聲明會被提升至上下文的頂部。意味著可以先使用函數(shù),后聲明。
而函數(shù)表達(dá)式是通過變量引用,因此無法提升。
var sum = add(3,5);
function add(num1,num2){
return num1 + num2;
}
2.2 函數(shù)就是值
記住函數(shù)就是對象,可以將函數(shù)當(dāng)成參數(shù)傳遞給其他的函數(shù)。
比如數(shù)組的sort()方法,接受一個比較函數(shù)作為可選參數(shù)。
在默認(rèn)情況下,sort()將數(shù)組中每個對象轉(zhuǎn)換成字符串然后進(jìn)行比較。
var numbers = [1,6,3,7,2,10];
numbers.sort(function(num1,num2){
return num1 - num2;
});
console.log(numbers); //[1, 2, 3, 6, 7, 10]
numbers.sort();
console.log(numbers); //[1, 10, 2, 3, 6, 7]
2.3 參數(shù)
函數(shù)參數(shù)實際上被保存在一個被稱為arguments類似于數(shù)組的對象中。
var reflect = function(){
return arguments[1];
};
console.log(reflect('first','second')); //second
console.log(reflect.length); //'0'
應(yīng)盡量避免使用argument。不過,在某些情況下使用arguments比名稱參數(shù)有效。例如,創(chuàng)建一個函數(shù),可以接受任意數(shù)量的參數(shù),并返回它們的和。
function sum(){
var i = 0,
result = 0,
len = arguments.length;
while (i < len){
result += arguments[i];
i++;
}
return result;
}
console.log(sum(3,5,1)); //9
console.log(sum(1,2,3,4)); //10
console.log(sum()); //0
//由于result的初始值為0,改函數(shù)就算沒有參數(shù)也能正常工作
2.4 重載
大多數(shù)面向?qū)ο笳Z言支持函數(shù)重載,它能讓一個函數(shù)具有多個簽名。
函數(shù)簽名由函數(shù)的名字、參數(shù)的個數(shù)及其類型組成。
JavaScript并沒有簽名,但可以模仿函數(shù)重載。用arguments對象獲取傳入的參數(shù)個數(shù)并決定怎么處理。
function sayMessage(message){
if (arguments.length === 0){
message = 'Default message';
}
console.log(message);
}
sayMessage('Hello'); //Hello
sayMessage(); //Default message
2.5 對象方法
對象的屬性的值是函數(shù),則該屬性被稱為方法。
2.5.1 this對象
JavaScript所有函數(shù)作用域內(nèi)都有一個this對象代表調(diào)用該函數(shù)的對象。在全局作用域中,代表全局對象。
function sayNameForAll(){
console.log(this.name);
}
var person1 = {
name: 'liang',
sayName: sayNameForAll
};
var person2= {
name: 'zhu',
sayName: sayNameForAll
};
person1.sayName(); //liang
person2.sayName(); //zhu
2.5.2 改變this
call() 方法
call() 的第一個參數(shù)指定了函數(shù)執(zhí)行時this的值,其后的所有參數(shù)(可選)都是需要被傳入函數(shù)的參數(shù)。
function sayNameForAll(){
console.log(this.name);
}
function sayName(a){
console.log(a + ': '+this.name);
}
var person1= {
name: 'liang'
};
var person2= {
name: 'zhu'
}
sayNameForAll.call(person1); //liang
sayName.call(person1,'name'); //name: liang
apply() 方法
apply() 方法的工作方式和call()完全一樣,但它只接受兩個參數(shù):this的值、一個數(shù)組(或者類似數(shù)組的對象,內(nèi)含需要被傳入函數(shù)的參數(shù))。
function sayNameForAll(a){
console.log(a + ': ' + this.name);
}
var person1 = {
name: 'liang'
};
var person2 = {
name: 'zhu'
};
sayNameForAll.apply(person1,['person']); //person: liang
var array = [1,2,3,4];
sayNameForAll.apply(person2,array); //1: zhu
sayNameForAll.apply(person2,array[2]); //error
bind() 方法
bind() 的第一個參數(shù)是要傳給新函數(shù)的this的值。其他所有參數(shù)代表需要被永久設(shè)置在新函數(shù)中的命名參數(shù)??梢栽谥罄^續(xù)設(shè)置任何非永久參數(shù)。
function sayName(a){
console.log(a + ': ' + this.name);
}
var person1 = {
name: 'liang'
};
var person2= {
name: 'zhu'
};
//綁定this,并傳入?yún)?shù)
var sayPerson1 = sayName.bind(person1,'person');
sayPerson1(); //person: liang
//僅綁定this
var sayPerson2 = sayName.bind(person2);
sayPerson2(); //undefined: zhu
sayPerson2('person'); //person: zhu