天天看點

JavaScript語言精粹【文法、對象、函數】

版權聲明:本文為部落客原創文章,遵循 CC 4.0 by-sa 版權協定,轉載請附上原文出處連結和本聲明。

本文連結:https://ligang.blog.csdn.net/article/details/44701817

JavaScript是Web浏覽器語言,浏覽器的API和文檔對象模型(DOM)相當糟糕,使得JavaScript遭到不公平的指責。

函數就是數值!

一、文法

1. 注釋

JavaScript提供了【/*塊注釋*/】、【//行注釋】兩種方式,建議大家使用行注釋,不要使用塊注釋。

/* 
  var rm_a = /a*/.match(s);
 */           

複制

配合正則使用,會發生錯誤!

2. 數字

JavaScript隻有一個數字類型。它在内部被表示為64位的浮點數,和Java的double數字類型一樣。進而避免了短整型的溢出問題。

NaN 是一個數值,isNaN(number)可判斷是否為數字
Infinity 表示大于1.79769313JavaScript中有一個Math對象,包含了一套用于數字的方法。例如:Math.floor(number); //把數字轉化為整數486...e+308的值
Math JavaScript中有一個Math對象,包含了一套用于數字的方法。例如:Math.floor(number); //把數字轉化為整數

PS:毒瘤

(1). 0.1+0.2不等于0.3

推薦:

(0.1*10 + 0.2*10)/10 = 0.3

(2). typeof NaN === 'number'; //true

NaN === NaN; //false

NaN !== NaN; //false

可辨識數字:isNaN(number)

判斷是否可用做數字:isFinite(""); 其會篩選NaN和Infinity,但會試圖把它的運算符串轉為數字

例:isFinite("123"); //true isFinite("123A"); //false isFinite(Infinity); //false

isNaN("123") //false isNaN("123A"); //true isNaN(Infinity); //false

推薦:

var isNumber = function isNumber(value){
	return typeof value === 'number' && isFinite(value);
}              

複制

例:isNumber(123); //true isNumber("123"); //false

3. 字元串

JavaScript沒有字元類型。要表示一個字元,隻需建立僅包含一個字元的字元串即可。JavaScript在被建立的時候,Unicode是一個16為的字元集,是以JavaScript中的所有字元都是16位的。

字元串擁有一個特性,一旦被建立,永無法改變;但可通過"+"建立一個新的字元串。

var s = "hello";
s.toUpperCase();
console.log(s); // HELLO,此處的s同聲明時var s不是一個對象!           

複制

4. 語句

在web浏覽器中,每個<script>标簽提供一個被編譯且立即執行的編譯單元;因為缺少連結器,JavaScript把它們一起抛到一個公共的全局命名空間中。

switch、while、for和do語句允許有一個可選的前置标簽(label),它配合break語句來使用。

5. 表達式

typeof運算符産生的值有:'number'、'string'、'boolean'、'undefined'、'function'、'object',其中數組和null也會傳回object。

二、對象

JavaScript的簡單資料類型包括數字、字元串、布爾值、null和undefined;其他所有的都是對象。

1. 對象字面量:包圍在一對花括号中的零或多個“名/值”對

var a = {};
var b = {"first-name":"lee",
		 "last-name":"gang"};           

複制

其中,屬性名不強制要求用引号包覆

2. 檢索

JavaScript中有兩種檢索方式:[]和.

小技巧;

(1). 使用"||"運算符來填充預設值

var status = flight['status'] || "unkown";           

複制

對于上述flight['status'],不存在成員屬性值傳回undefined

(2). 嘗試從undefined的成員屬性取值,會導緻TypeError異常,可通過"&&"運算符避免錯誤:

if(flight && flight.status){
	var status = flight['status'] || "unkown";
}           

複制

3. 引用

對象通過引用來傳遞。它們永遠不會被複制;

var x = stooge;
x.nickname = 'leegang';
var nick = stooge.nickname; //因為x和stooge是指向同一個對象的引用,所有nick為'leegang'           

複制

4. 原型

每個對象都連接配接到一個原型對象,并且它可以從中繼承屬性。所有通過對象字面量建立的對象都連接配接到Object.prototype,它是JavaScript中的标配對象。

當建立一個對象時,可以選擇某個對象作為它的原型。

對某對象做出改變時,不會觸及對象的原型,隻有在檢索值的時候才被用到【委托】。

屬性值自身找不到 --> 原型 --> ... --> Object.prototype

原型關系是一種動态關系,添加一個新屬性到原型中立即對所有基于該原型建立的對象可見。

5. for-in

可枚舉出所有的屬性,包括函數和原型中的屬性。

過濾非值:typeof props['name'] !== 'function'

過濾非自身:hasOwnProperty()

var obj = {a:'123',b:'456',c:function(){return 1}};
/* 獲得對象的屬性個數*/
function count(obj){
	var length = 0;
	var type = typeof obj;
	if(type === "string"){
		length = obj.length;
	}else{
		for(var o in obj){
			length++;
		}
	}
	return length;
}           

複制

6. 減少全局變量污染

隻建立一個唯一全局變量,其他變量和對象都作為該變量的屬性。

var myApp = {};
myApp.stooge = {};
myApp.flight = {a:'123',b:'456'};           

複制

三、 函數

函數 --> Function.prototype --> Object.prototype

1. 函數字面量

var add = function(a,b){
	return a+b;	
};           

複制

函數字面量可以出現在任何允許表達式出現的地方。函數也可以被定義在其他函數中。一個内部函數除了可以通路自己的參數和變量,同時它也能自有通路把它嵌套在其中的父函數的參數與變量。通過函數字面量建立的函數對象包含一個連到外部上下文的連接配接。這被稱為閉包。

2. 函數調用

調用一個函數會暫停目前函數的執行,傳遞控制權和參數給新函數。除了聲明時定義的形式參數,每個函數還接收兩個附件的參數:this和arguments。

(1). 方法調用模式

當一個函數被儲存為對象的一個屬性時,其被稱為方法。當一個方法被調用時,this被綁定到該對象。

var myObject = {
	value:0,
	increment:function(inc){
		this.value += typeof inc === 'number' ? inc : 1;
	}
};           

複制

調用:對象.方法

myObject.increment();

myObject.value; // 1

myObject.increment(2);

myObject.value; // 3

(2). 函數調用模式

當一個函數并非一個對象的屬性時,那麼它就是被當做一個函數來調用的:

var sum = add(1,2);

此模式調用函數時,this被綁定到全局對象。

導緻問題:

方法不能利用内部函數來幫助它工作,因為内部函數的this被綁定到了錯誤的值,是以不能共享該方法對對象的通路權。

解決方案:

如果該方法定義一個變量并給它指派為this,那麼内部函數就可以通過那個變量通路到this。

myObject.double = function(){	// 給myObject增加一個double方法
	var that = this; // 解決方案,this為myObject
	var helper = function(){
		/* helper方法中,this指向全局, that指向myObject*/
		that.value = add(that.value,that.value); 
	};
	helper();	// 以函數形式調用helper
};
myObject.double(); // 以方法形式調用double           

複制

總結如下:

obj.method = function(){	//方法
	// 方法中,this被綁定到目前obj對象
	that = this;
	var fun = function(){	//函數
		// 函數中,this被綁定到全局對象
		// this.value 不可以;this.add 全局方法可以
		// 将外部方法中的this另存到that中,避免被函數中this覆寫!
	};
};           

複制

(3). 構造器調用模式

在一個函數前面帶上new來調用,那麼背地裡将會建立一個連接配接到該函數的prototype成員的新對象,同時this會被綁定到那個對象上。

/* 建立一個名為Quo,帶有status屬性的構造器函數*/
var Quo = function(str){
	this.status = str;
};
/* 給Quo的所有執行個體提供一個名為get_status的公共方法*/
Qu0.prototype.get_status = function(){
	return this.status;
};
var myQuo = new Que("confused");           

複制

(4). Apply調用模式

apply方法構造一個參數數組傳遞給調用函數。其接收兩個參數,第1個是要綁定給this的值,第2個是參數數組。

// 執行個體一:構造一個包含兩個數字的數組,并将它們相加
var arr = [3,4];
var sum = add.apply(null,arr);
// 執行個體二:構造一個包含status成員的對象,并調用Quo上的get_status方法[非繼承方式]
var statusObject = {status:'A-OK'};
var status = Quo.prototype.get_status.apply(statusObject);            

複制

3. 函數傳回

一個函數總會傳回一個值。如果沒有指定傳回值,則傳回undefined。

4. 異常

var add = function(a,b){
	if(typeof a !== 'number' || typeof b !== 'number'){
		throw{
			name:'TypeError',
			message:'add needs numbers'
		};
	}
	return a+b;
}
/* throw語句中斷函數的執行,它會抛出一個exception對象,該對象包含的屬性可自定義*/
var try_it = function(){
	try{
		add("seven");
	}catch(e){
		document.writeln(e.name+":"+e.message);
	}
}
try_it();           

複制

5. 擴充類型的功能

JavaScript允許給語言的基本類型擴充功能。

Function.prototype.method = function(name,func){
	this.prototype[name] = func;
	return this;
};           

複制

在Function原型上添加method,其所有方法上都可用method

/* 取整*/
Number.method('integer',function(){
	return Math[this<0?'ceil':'floor'](this);
});
/* 移除字元串首尾空白*/
String.method('trim',function(){
	return this.replace(/^\s+|\s+$/g,'');
});           

複制

6. 閉包

内部函數擁有比它的外部函數更長的生命周期!!!

函數可以通路它被建立時所處的上下文環境!!!

内部函數能通路外部函數的實際變量,而無需複制!

常用解決方案:

(1)給對應的li添加一個屬性記錄是第幾個如 id=0,1,2,3

(2)将函數外移,避免函數套函數

7. 回調

request=prepare_the_request();

response=send_request_synchronously(request);

display(response);

這種方式的問題在于網絡上的同步請将會導緻用戶端進入假死狀态。如果網絡傳輸或伺服器很慢,響應性的降低将是不可接受的。

更好的方式是發起異步的請求,提供一個當伺服器的響應到達時将被調用的回調函數。這樣用戶端不會被阻塞。

request=prepare_the_request();

send_request_asynchronously(request,function(response){

display(response);

});

8. 子產品

子產品通常結合單例模式使用。JavaScript單例就是用對象字面量表示法建立的對象,對象的屬性值可以是數值或函數,并且屬性值在該對象的生命周期中不會發生變化。

var serial_maker = function(){
	var prefix = '';
	var seq = 0;
	return{
		set_prefix:function(p){
			prefix = String(p);
		},
		set_seq:function(s){
			seq = s;
		},
		gensym:function(){
			var result = prefix + seq;
			seq +=1;
			return result;
		}
	};
};
var seqer = serial_maker();
seqer.set_prefix('Q');
seqer.set_seq(1000);
var unique = seqer.gensym(); // 'Q1000'           

複制

子產品的一般形式:一個定義了私有變量和函數的函數;利用閉包建立可以通路私有變量和函數的特權函數;最後傳回這個特權函數,或者把它們儲存到一個可通路到的地方。