前言
- 現(xiàn)在Android開發(fā)需求越來越少了,快過年也沒什么事,公司叫我學(xué)學(xué)前端,也罷了,技多不壓身.
變量的聲明:
- js中使用var關(guān)鍵字聲明變量,同時(shí)變量名是大小寫敏感的,即A與a是兩個(gè)不同的變量.如果只是聲明了變量而沒有賦值
var a ;
那么a的值就是undefined
,這是js中的一個(gè)關(guān)鍵字,表示未定義.js是一門動(dòng)態(tài)類型語言,這意味著你可以var a = 1; a = "hello"
,賦值不同類型.
變量提升
- 在js中,js引擎會(huì)將所有代碼的聲明全部先解析,然后再一行行執(zhí)行語句,這就意味著所有變量會(huì)被提到頭部執(zhí)行,例如
console.log(a);var a = 1
等價(jià)于var a ; console.log(a);a=1;
,所以良好的編程習(xí)慣還是得先聲明變量再使用.
區(qū)塊
-
{}
以一對(duì)花括號(hào)表示,對(duì)于var
來說,區(qū)塊不構(gòu)成單獨(dú)作用域,也就是說
{
var a = 1;
}
console.log(a);
在控制臺(tái)上會(huì)輸出a=1;這里說一下js的局部變量只在函數(shù)內(nèi)部才能聲明,區(qū)塊中無效.可以理解為var任然是全局變量.
標(biāo)簽
- 作用與kotlin中的標(biāo)簽一樣,主要用來跳出循環(huán)等操作,聲明格式:
label:語句
,下面是一個(gè)例子
top:
for(var i=0;i<10;i++){
for(var j=0;j<10;j++){
if(i===j===1){
return top;
}
}
}
數(shù)據(jù)類型轉(zhuǎn)換
- js是一種動(dòng)態(tài)類型語言,變量類型可以隨意賦值,但是使用運(yùn)算符時(shí),如果變量類型不符合預(yù)期類型則會(huì)自動(dòng)轉(zhuǎn)型,舉個(gè)栗子:
"4"-"1"
,這里使用了-
運(yùn)算符,要求元素類型為數(shù)值,所以js會(huì)自動(dòng)將字符串轉(zhuǎn)為數(shù)值.運(yùn)行結(jié)果為3
,使用typeof
輸出結(jié)果為number
類型,說明結(jié)果被自動(dòng)轉(zhuǎn)型了. - js也提供了幾個(gè)可以強(qiáng)制轉(zhuǎn)型的方法
Number()
,Boolean()
,String()
,下面分開細(xì)說這幾個(gè)方法
Number()
- 分為參數(shù)為原始類型與對(duì)象類型,原始類型包括數(shù)值,字符串,布爾,下面貼上一段測(cè)試代碼
//純數(shù)字字符串
console.log(Number('321'));
//字符串
console.log(Number('321abc'));
//true
console.log(Number(true));
//false
console.log(Number(false));
//對(duì)象 null
console.log(Number(null));
//對(duì)象 undefined
console.log(Number(undefined));
接下來我們來看看輸出的結(jié)果情況:
可以看到當(dāng)參數(shù)是無法解析的字符串時(shí)例如包含
abc
輸出結(jié)果為NaN(not a number)
,接下來我們來看看參數(shù)傳對(duì)象試試,
console.log(Number({name:"xiaoming"}));
,這個(gè)時(shí)候輸出了NaN
.這里說一下
Number()
的轉(zhuǎn)換過程
- 首先調(diào)用自身的
valueof
方法,如果返回原始類型,則調(diào)用Number()
方法,否則進(jìn)行下一步. - 如果
valueof
方法返回的是對(duì)象,則調(diào)用toString()
方法,如果toString()
返回原始類型則調(diào)用Number()
方法 - 如果
toString
還是返回對(duì)象,則返回NaN
String()
- 該方法可以將任意類型轉(zhuǎn)為字符串,
console.log(String({name:"xiaoming"}));//[object object]
console.log(String(true));//'true'
console.log(String(false));'false'
console.log(String(null));'null'
console.log(String(undefined));'undefined'
Boolean()
- 除以下五個(gè)值為false,其余皆轉(zhuǎn)換為true
undefined,null,+0/-0,NaN,''(空字符串)
值得一提的是,所有對(duì)象的轉(zhuǎn)化結(jié)果都是true,甚至new Boolean(false)
也是true
錯(cuò)誤機(jī)制
- JS通過Error對(duì)象來構(gòu)造一個(gè)錯(cuò)誤實(shí)例,它包括message屬性與name屬性,當(dāng)然還有stack堆棧屬性.
下面介紹一下JS中原生的Error對(duì)象:
1.SyntaxError:語法錯(cuò)誤
2.ReferenceError:引用錯(cuò)誤
3.RangeError:區(qū)間錯(cuò)誤,通常是操作數(shù)組不當(dāng)時(shí)發(fā)生
4.TypeError :類型錯(cuò)誤,通常使用參數(shù)或者變量不是預(yù)期類型時(shí)發(fā)生
5.URIError :Uri相關(guān)錯(cuò)誤 - Try Catch
和其他語言一樣,JS提供了try catch
語句幫組我們捕獲錯(cuò)誤,當(dāng)然也同樣可以使用finally
,你也可以使用throw
關(guān)鍵字拋出一個(gè)錯(cuò)誤.
函數(shù)
- 我們知道JS是一門函數(shù)式的編程語言,所以函數(shù)在JS中是一等公民一樣的存在,函數(shù)可以作為參數(shù),返回值,表達(dá)式等使用.
- 在JS中聲明一個(gè)函數(shù)如下:
function name(params) {
}
使用fuction
關(guān)鍵字進(jìn)行聲明.因?yàn)镴S的函數(shù)與大部分語言都很類似,接下來講講JS中使用函數(shù)值得注意的一些地方.
1.如果聲明了多個(gè)同名函數(shù),那么后面聲明的函數(shù)會(huì)覆蓋前面的函數(shù)
function name(params) {
console.log(1);//1
}
function name(params) {
console.log(2);//2
}
name();
上面這段代碼輸出的結(jié)果為2,相信大家也注意到了,我聲明的函數(shù)name
有一個(gè)參數(shù),但是我在調(diào)用它的時(shí)候并沒給參數(shù),一樣不報(bào)錯(cuò)可以執(zhí)行.這也是JS的函數(shù)一個(gè)不同點(diǎn),這里用到一個(gè)知識(shí)點(diǎn)agrument
等會(huì)再講.在這里如果要查看定義函數(shù)的參數(shù)個(gè)數(shù)可以使用length
屬性,它返回函數(shù)在定義時(shí)的參數(shù)個(gè)數(shù),比如上面上的代碼的調(diào)用name.length
則返回1.此時(shí)無論你在調(diào)用時(shí)輸入多少個(gè)參數(shù),它始終返回的是函數(shù)定義時(shí)的參數(shù)
函數(shù)的作用域
這里只講ES5的作用域,因?yàn)镋S6的我也沒有學(xué)- -,JS中作用域分為:全局作用域和局部作用域
- 全局作用域:變量在整個(gè)程序中都存在,任何位置都可以訪問
- 局部作用域:變量只能存在于函數(shù)內(nèi)部
我們用一段代碼來看看這個(gè)定義
var a = 1;
function name(params) {
var a = 2;
console.log("局部作用域:" + a);
}
name();
console.log("全局作用域:" + a);
可以看到局部作用域只在函數(shù)內(nèi)部有作用,同時(shí)函數(shù)內(nèi)的a覆蓋了全局變量.同時(shí)注意函數(shù)內(nèi)部的變量提升,接下來我們改造下代碼看看
var a = 1;
function name(params) {
console.log("局部作用域:" + a); //undefined
var a = 2;
console.log("局部作用域:" + a);//2
}
name();
console.log("全局作用域:" + a);//1
這個(gè)時(shí)候第一句console
輸出了undefined
,是不是感覺應(yīng)該輸出全局變量1
,這里就是JS的變量提升在搞怪了,上面的代碼在JS引擎解析時(shí)候會(huì)變成這樣:
function name(params) {
var a ;
console.log("局部作用域:" + a); //undefined
a = 2;
console.log("局部作用域:" + a);//2
}
將函數(shù)內(nèi)部的var a =2
變量a
提到了頭部,因?yàn)?code>a在頭部沒有賦值,所以是undefined
了
函數(shù)本身的作用域
- 由于在JS中函數(shù)是一等公民一樣的存在,你就可以把它和變量看做是一樣的,它的作用域和變量也是一樣的,就是在其聲明時(shí)的作用域.舉個(gè)例子
var a =1;
//全局作用域
function name(params) {
console.log(a);
}
//函數(shù)內(nèi)部調(diào)用
function test(params) {
var a = 2;
name();
}
test();//1
我們?cè)诳匆粋€(gè)作用域在函數(shù)內(nèi)部的
var a =1;
//函數(shù)內(nèi)部調(diào)用
function test(params) {
var a = 2;
return function name(params) {
console.log(a);
}
}
var f= test();
f();//2
上面這種結(jié)構(gòu)又被稱為閉包
參數(shù)
在JS中,參數(shù)是可以省略的,我們來看看下面的代碼
function name(a, b) {
console.log(a + b);
}
name();//NaN 因?yàn)闆]傳參數(shù),所以a,b都是undefined,他們進(jìn)行相加返回NaN
name(1);//NaN
name(1, 2);//3
- 在JS中根據(jù)傳遞的參數(shù)的類型
- 傳原始數(shù)值:傳值傳遞,函數(shù)內(nèi)部修改不影響原值(類似形參)
var a = 1;
function name(params) {
params = 3;
console.log(params);//3
}
name(a);
console.log(a);//1
2.傳對(duì)象:傳址傳遞,會(huì)修改對(duì)象的內(nèi)存地址,修改參數(shù)會(huì)影響到原值(類似實(shí)參)
var people = {
name:"xiaoming"
}
function test(params) {
params.name="xiaomi"
}
test(people);
console.log(people.name);//xiaomi
此時(shí)people.name
已經(jīng)變更成了xiaomi
agrument對(duì)象
這個(gè)對(duì)象主要用來在函數(shù)內(nèi)部獲取參數(shù),因?yàn)閖s允許參數(shù)數(shù)目不定,所以需要argument來獲取,它包括了函數(shù)運(yùn)行時(shí)的所有參數(shù),這里所幾個(gè)常用的屬性
- callee:返回它對(duì)應(yīng)的函數(shù)
- length:返回函數(shù)調(diào)用時(shí)的參數(shù)個(gè)數(shù)
閉包
要理解閉包得先了解作用域,我們知道在函數(shù)的內(nèi)部是可以訪問全局變量的,但是外部是無法訪問函數(shù)內(nèi)部的變量的,但是有時(shí)候我們又需要在外部訪問函數(shù)內(nèi)部的變量怎么辦?
我們先看下這段代碼
function f1(params) {
var a = 666;
return function f2(params) {
return a;
}
}
//返回函數(shù)f2
var f2 = f1();
//返回值a
var a = f2();
console.log(a);//666
我們要想拿到函數(shù)內(nèi)部的變量a
,又重新定義了一個(gè)函數(shù)f2
,對(duì)函數(shù)f2
而言,f1
內(nèi)部的變量是可以訪問的,但是f2
卻是對(duì)f1
不可訪問的,這就是JS的鏈?zhǔn)阶饔糜?/strong>,因?yàn)楹瘮?shù)在JS中是可以作為返回值的,我們使f2
攜帶f1
中的變量a
并作為f1
的返回值返回不就可以最終訪問到a
了嗎?
總結(jié)一下閉包得兩個(gè)特點(diǎn):
1.讀取函數(shù)內(nèi)部變量
2.使這些變量始終在內(nèi)存中,通過栗子說明:
function f1(params) {
return function f2() {
return params++;
}
}
var a = f1(5);
console.log(a());//5
console.log(a());//6
console.log(a());//7
可以看到參數(shù)的值都在遞增,說明上一次調(diào)用時(shí)候返回值是保存在了內(nèi)存當(dāng)中
3.閉包還有個(gè)用處就是用來封裝私有屬性和函數(shù)
函數(shù)立即執(zhí)行
格式:函數(shù)+(),在函數(shù)后面立馬跟上一個(gè)圓括號(hào),表示該函數(shù)立即執(zhí)行
通常這么定義(function(){}())
在外面再加一個(gè)大括號(hào),防止JS引擎解析時(shí)產(chǎn)生歧義.