相等操作符
最早的ECMAScript中的相等和不相等操作符會在執(zhí)行比較之前,先將對象轉換成相似的類型室谚。后來毡鉴,有人提出了這種轉換到底是否合理的質疑。最后ECMAScript的解決方案就是提供兩組操作符:相等和不相等-先轉換再比較秒赤,全等和不全等-僅比較而不轉換猪瞬。
在轉換不同的數據類型時,相等和不相等操作符遵循下列基本規(guī)則:
1.如果有一個操作數是布爾值倒脓,則在比較相等性之前現將其轉換為數值-false
轉換為0撑螺,true
轉換為1。
2.如果一個操作數是字符串崎弃,另一個操作數是數值甘晤,在比較相等性之前先將字符串轉換為數值。
3.如果一個操作數是數值饲做,另一個操作數不是线婚,則調用對象的valueOf
方法,用得到的基本類型值按照前面的規(guī)則進行比較盆均;
基于第三點比較規(guī)則來說話塞弊,這兩個操作符在進行比較時則要遵循下列規(guī)則:
a:null
和undefined
是相等的
b:要比較相等性之前,不能將null
和undefined
轉換成其他任何值
c:如果有一個操作數是NaN
泪姨,則相等操作符也返回false
,而不相等操作符返回true
游沿。重要提示:即使兩個操作數都是NaN,相等操作符也返回false肮砾,因為按照規(guī)則诀黍,NaN不等于NaN
d:如果兩個操作數都是對象,則比較它們是不是同一個對象仗处。如果兩個操作數都指向同一個對象眯勾,則相等操作符返回true
枣宫,否則,返回false
break/continue/ return語句
break
用于完全結束一個循環(huán)吃环,跳出循環(huán)體也颤。不管是哪種循環(huán),一旦在循環(huán)體中遇到break郁轻,系統將完全結束循環(huán)翅娶,開始執(zhí)行循環(huán)之后的代碼。break
不僅可以結束其所在的循環(huán)好唯,還可結束其外層循環(huán)故觅。
continue
語句會立即退出當前循環(huán),然后繼續(xù)執(zhí)行后面的循環(huán)渠啊,直到循環(huán)結束输吏。而break
則是完全中止循環(huán)。
return
關鍵字并不是專門用于跳出循環(huán)的替蛉,return
的功能是結束一個方法贯溅。 一旦在循環(huán)體內執(zhí)行到一個return語句,return
語句將會結束該方法躲查,循環(huán)自然也隨之結束它浅。與continue
和break
不同的是,return
直接結束整個方法镣煮,不管這個return
處于多少層循環(huán)之內姐霍。
以下是三段代碼來表示三者的區(qū)別:
//break
var num = 0;
for(var = 1 ; i < 10 ; i++){
if(i%5 == 0){
break;
}
num++;
}
alert(num); //4
//continue
var num = 0;
for(var = 1 ; i < 10 ; i++){
if(i%5 == 0){
continue;
}
num++;
}
alert(num); //8
//return
function test(i){
if(i == 3){
return
}
console.log(i)
}
for (var i = 0; i < 10 ; i++ ){
test(i)
} // 0 1 2 4 5 6 7 8 9
width語句
width
語句在開發(fā)中很少會用到,本來不想寫它典唇,后來想了想镊折,其特殊的語法形式,也有必要寫下來介衔。
width
語句的作用是將代碼的作用域設置到一個特定的環(huán)境中恨胚。定義width
語句的目的主要為了簡化多次編寫同一個對象的工作。如下:
var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;
上面代碼塊多次用到location
這個對象炎咖,如果使用width
語句可以寫成如下所示:
width(location){
var qs = serarch.substring(1);
var hostName = hostname;
var url = href;
}
使用width
語句赃泡,從寫法上來說變的復雜了,將簡單的取值賦值語句包在了函數寫法中乘盼。再看一下以下的寫法:
width(window){
var qs = window.location.serarch.substring(1);
var hostName = window.location.hostname;
var url = window.location.href;
}
這樣升熊,就好理解width
語句真正的作用。
從運行環(huán)境上來說绸栅,width
語句的代碼塊內部级野,每個變量首先被認為是一個局部變量,而如果在局部環(huán)境中找不到該變量的蒂尼阴幌,就會查詢location
對象中是否有同名屬性勺阐。如果發(fā)現了同名屬性,則以location
對象屬性的值作為變量的值矛双。
大量使用width
語句會導致性能下降渊抽,也會讓調試代碼變得困難,而且在嚴格模式下不允許使用width
語句议忽,否則將會視為語法錯誤懒闷。
理解函數的參數
在給一個函數傳遞參數時,我們可以顯式的傳參栈幸,也在不傳參的情況下愤估,用arguments
這個對象來表示傳入到函數中的參數。
函數傳參有這么一條潛規(guī)則:你可以多傳參數速址,函數體內部可以不用玩焰,但是你不可以少傳參數,那函數體內部就會報錯芍锚。
從函數接受參數的情況來看昔园,函數接收到的參數在函數內部始終會用arguments
這個對象來表示。arguments
是一個類數組的對象并炮,但它并不是Array
的實例默刚。你可以用數組的方法訪問arguments
對象中的每一項,arguments[0],arguments[1]......
逃魄。所以arguments
的長度是由傳入的參數個數決定的荤西,沒有傳入參數就會自動被賦予undefined
值。
function test(a,b){
console.log(typeof arguments)
}
test(1,2) //'object'
另外還有一點伍俘,arguments
的類型是object
邪锌,這一點別忘了。
最后還有一點癌瘾,arguments
對象內部每一項的值都會與傳入的參數一一對應秃流,注意:是每一項的值。也就是說柳弄,傳入的參數值與arguments
中對應的值會保持同步舶胀,不過,由于arguments
這個對象始終存在并作用于函數體內部碧注,并且讀取傳入的參數值和讀取對應arguments
對象內部的值并不是訪問相同的內存空間嚣伐,他們的內存空間是獨立的。
函數重載
首先理解什么是函數重載萍丐?
函數重載是函數的一種特殊情況轩端,允許在同一范圍中聲明幾個功能類似的同名函數,但是這些同名函數的[形式參數](指參數的個數逝变、類型或者順序)必須不同基茵,也就是說用同一運算符完成不同的運算功能奋构。這就是重載函數。重載函數常用來實現功能類似而所處理的數據類型不同的問題拱层。不能只有函數返回值類型不同弥臼。
但是在js中,函數是無法重載的根灯,例如:
function test(num){
return num+100
}
function test(num){
return num+200
}
var result = test(100); //300
不過径缅,由于函數中有arguments
這個對象,我們可以根據它的長度烙肺,類型或者順序來實現函數重載纳猪。
這里說一個非常典型的案例:
我們現在有這樣的一個需求,有一個people對象桃笙,里面存著一些人名氏堤,如下:
var people = {
values: ["Dean Edwards", "Sam Stephenson", "Alex Russell", "Dean Tom"]
};
我們希望people對象擁有一個find方法,當不傳任何參數時搏明,就會把people.values里面的所有元素返回來丽猬;當傳一個參數時,就把first-name跟這個參數匹配的元素返回來;當傳兩個參數時熏瞄,則把first-name和last-name都匹配的才返回來脚祟。因為find方法是根據參數的個數不同而執(zhí)行不同的操作的,所以强饮,我們希望有一個addMethod方法由桌,能夠如下的為people添加find的重載:
addMethod(people, "find", function() {}); /*不傳參*/
addMethod(people, "find", function(a) {}); /*傳一個*/
addMethod(people, "find", function(a, b) {}); /*傳兩個*/
還有一個問題,就是這個全局的addMethod方法該怎么實現呢邮丰?如下所示
function addMethod(object, name, fn) {
var old = object[name]; //把前一次添加的方法存在一個臨時變量old里面
object[name] = function() { // 重寫了object[name]的方法
// 如果調用object[name]方法時行您,傳入的參數個數跟預期的一致,則直接調用
if(fn.length === arguments.length) {
return fn.apply(this, arguments);
// 否則剪廉,判斷old是否是函數娃循,如果是,就調用old
} else if(typeof old === "function") {
return old.apply(this, arguments);
}
}
}
現在斗蒋,我們一起來分析一個這個addMethod函數捌斧,它接收3個參數,第一個為要綁定方法的對象泉沾,第二個為綁定的方法名稱捞蚂,第三個為需要綁定的方法(一個匿名函數)。函數體的的分析已經在注釋里面了跷究。
OK姓迅,現在這個addMethod方法已經實現了,我們接下來就實現people.find的重載啦!全部代碼如下:
//addMethod
function addMethod(object, name, fn) {
var old = object[name];
object[name] = function() {
if(fn.length === arguments.length) {
return fn.apply(this, arguments);
} else if(typeof old === "function") {
return old.apply(this, arguments);
}
}
}
var people = {
values: ["Dean Edwards", "Alex Russell", "Dean Tom"]
};
/* 下面開始通過addMethod來實現對people.find方法的重載 */
// 不傳參數時肩杈,返回peopld.values里面的所有元素
addMethod(people, "find", function() {
return this.values;
});
// 傳一個參數時解寝,按first-name的匹配進行返回
addMethod(people, "find", function(firstName) {
var ret = [];
for(var i = 0; i < this.values.length; i++) {
if(this.values[i].indexOf(firstName) === 0) {
ret.push(this.values[i]);
}
}
return ret;
});
// 傳兩個參數時,返回first-name和last-name都匹配的元素
addMethod(people, "find", function(firstName, lastName) {
var ret = [];
for(var i = 0; i < this.values.length; i++) {
if(this.values[i] === (firstName + " " + lastName)) {
ret.push(this.values[i]);
}
}
return ret;
});
// 測試:
console.log(people.find()); //["Dean Edwards", "Alex Russell", "Dean Tom"]
console.log(people.find("Dean")); //["Dean Edwards", "Dean Tom"]
console.log(people.find("Dean Edwards")); //["Dean Edwards"]