JavaScript 是一種輕量級的編程語言。
JavaScript 是可插入 HTML 頁面的編程代碼。
JavaScript 插入 HTML 頁面后,可由所有的現代瀏覽器執行。
JavaScript 很容易學習。
一、如何編寫?
1.JavaScript代碼存在形式
<!-- 方式一 -->
<script type="text/javascript" src="JS文件"></script>
<!-- 方式二 -->
<script type="text/javascript">
Js代碼內容
</script>
2.JavaScript存放位置
HTML 中的腳本必須位於 <script> 與 </script> 標簽之間。
腳本可被放置在 HTML 頁面的 <body> 和 <head> 部分中。
由於Html代碼是從上到下執行,如果Head中的js代碼耗時嚴重,就會導致用戶長時間無法看到頁面,如果放置在body代碼塊底部,那么即使js代碼耗時嚴重,也不會影響用戶看到頁面效果,只是js實現特效慢而已。
這里,推薦放在body體底部;
3.注釋
JavaScript 不會執行注釋。
我們可以添加注釋來對 JavaScript 進行解釋,或者提高代碼的可讀性。
單行注釋以 // 開頭。
// 輸出標題:
document.getElementById("myH1").innerHTML="歡迎來到我的主頁";
// 輸出段落:
document.getElementById("myP").innerHTML="這是我的第一個段落。";
多行注釋以 /* 開始,以 */ 結尾。
/* 下面的這些代碼會輸出 一個標題和一個段落 並將代表主頁的開始 */
二、變量
JavaScript中變量的聲明是一個非常容易出錯的點,局部變量必須一個 var 開頭,如果未使用var,則默認表示聲明的是全局變量。
JavaScript 變量可用於存放值(比如 x=5)和表達式(比如 z=x+y)。
var x=5; var y=6; var z=x+y;
變量可以使用短名稱(比如 x 和 y),也可以使用描述性更好的名稱(比如 age, sum, totalvolume)。
- 變量必須以字母開頭
- 變量也能以 $ 和 _ 符號開頭(不過我們不推薦這么做)
- 變量名稱對大小寫敏感(y 和 Y 是不同的變量)
JavaScript 語句和 JavaScript 變量都對大小寫敏感。
<script type="text/javascript">
// 全局變量
name = 'seven';
function func(){
// 局部變量
var age = 18;
// 全局變量
gender = "男"
}
</script>
三、數據類型
JavaScript 中的數據類型分為原始類型和對象類型:
- 原始類型
- 數字
- 字符串
- 布爾值
- 對象類型
- 數組
- 字典
- ...
1.數字
JavaScript中不區分整數值和浮點數值,JavaScript中所有數字均用浮點數值表示。
轉換:
- parseInt(..) 將某值轉換成數字,不成功則NaN
- parseFloat(..) 將某值轉換成浮點數,不成功則NaN
特殊值:
- NaN,非數字。可使用 isNaN(num) 來判斷。
- Infinity,無窮大。可使用 isFinite(num) 來判斷。
2.字符串
字符串是由字符組成的數組,但在JavaScript中字符串是不可變的:可以訪問字符串任意位置的文本,但是JavaScript並未提供修改已知字符串內容的方法。
常見功能:
obj.length 獲取當前字符串長度
obj.trim() 移除空白
obj.trimLeft()
obj.trimRight)
obj.charAt(n) 返回字符串中的第n個字符
obj.concat(value, ...) 拼接
obj.indexOf(substring,start) 子序列位置
obj.lastIndexOf(substring,start) 子序列位置
obj.substring(from, to) 根據索引獲取子序列---起始位置,結束位置
obj.slice(start, end) 切片
obj.toLowerCase() 大寫
obj.toUpperCase() 小寫
obj.split(delimiter, limit) 分割
obj.search(regexp) 從頭開始匹配,返回匹配成功的第一個位置(g無效)
obj.match(regexp) 全局搜索,如果正則中有g表示找到全部,否則只找到第一個。
obj.replace(regexp, replacement) 替換,正則中有g則替換所有,否則只替換第一個匹配項,
$數字:匹配的第n個組內容;
$&:當前匹配的內容;
$`:位於匹配子串左側的文本;
$':位於匹配子串右側的文本
$$:直接量$符號
3.布爾類型
布爾類型僅包含真假,與Python不同的是其首字母小寫。
- == 比較值相等
- != 不等於
- === 比較值和類型相等
- !== 不等於
- || 或
- && 且
4.數組
JavaScript中的數組類似於Python中的列表。
常見功能:
obj.length 數組的大小
obj.push(ele) 尾部追加元素
obj.pop() 尾部獲取一個元素
obj.unshift(ele) 頭部插入元素
obj.shift() 頭部移除元素
obj.splice(start, deleteCount, value, ...) 插入、刪除或替換數組的元素
obj.splice(n,0,val) 指定位置插入元素
obj.splice(n,1,val) 指定位置替換元素
obj.splice(n,1) 指定位置刪除元素
obj.slice( ) 切片
obj.reverse( ) 反轉
obj.join(sep) 將數組元素連接起來以構建一個字符串
obj.concat(val,..) 連接數組
obj.sort( ) 對數組元素進行排序
四、小知識匯總
1. 序列化
序列化就是將JavaScript中的數據類型轉換成字符串,反序列化的過程則相反;
var a="ss"; ret = JSON.stringify(a);//序列化 console.log(ret); console.log(JSON.parse(ret));//反序列化
結果如下:

2. 轉義
一般使用在URL中字符的轉義等,下面來看一下具體的用法
var a='http://www.baidu.com?name=民資'; console.log(encodeURI(a)); console.log(decodeURI(encodeURI(a))); console.log(encodeURIComponent(a)); console.log(decodeURIComponent(encodeURIComponent(a)));
結果如下:

3. eval
JavaScript中的eval是Python中eval和exec的合集,既可以編譯代碼也可以獲取返回值。
console.log(eval('1+2*5'));
console.log(eval(a = 1));
結果如下:

4. 時間
在JavaScript中,Date對象用來表示日期和時間。JavaScript中提供了時間相關的操作,分別為獲取時間和設置時間,時間操作中分為兩種時間,統一時間(UTC),以及本地時間(東8區)
var now = new Date(); now.getFullYear(); //2016 now.getMonth(); // 月份,注意月份范圍是0~11,6表示7月 now.getDate(); // 日期 now.getDay(); // 表示星期幾 now.getHours(); // 24小時制 now.getMinutes(); // 分鍾 now.getTime(); // 以number形式表示的時間戳
結果如下:

五、循環和條件語句
1. 條件語句
if(條件){
}else if(條件){
}else{
}
switch(name){
case '1':
age = 123;
break;
case '2':
age = 456;
break;
default :
age = 777;
}
2.for循環和while循環
for循環
循環時,循環的元素是索引
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var names = ["cc", "tony", "rain"];
for(var i=0;i<names.length;i++){
console.log(i);
console.log(names[i]);
}
</script>
</body>
</html>
執行結果:

while循環,同python中的while循環
while(條件){
}
五、函數
1.函數類型
JavaScript中函數基本上可以分為以下三類:普通函數,匿名函數,自執行函數。
此外需要注意的是對於JavaScript中函數參數,實際參數的個數可能小於形式參數的個數,函數內的特殊值arguments中封裝了所有實際參數。
//函數
function func(arg){
return arg+1
}
var result = func(1)
console.log(result);
//普通函數:
function func(){
}
//匿名函數:
function func(arg){
return arg+1
}
setInterval("func()", 5000);
setInterval(function(){
console.log(123);
},5000)
//自執行函數(創建函數並且自動執行):
(function(arg){
console.log(arg);
})(1)
//自執行函數等同於以下代碼:
function func(arg){
console.log(arg);
}
func(1)
2.函數作用域
作用域在許多程序設計語言中非常重要。
通常來說,一段程序代碼中所用到的名字並不總是有效/可用的,而限定這個名字的可用性的代碼范圍就是這個名字的作用域。
作用域的使用提高了程序邏輯的局部性,增強程序的可靠性,減少名字沖突。
首先,了解下其他語言的作用域:
- 其他語言:以代碼塊為作用域
public void Func(){
if(1==1){
string name = 'Java';
}
console.writeline(name);
}
Func()
// 報錯
- python:以函數作為作用域
情況一:
def func():
if 1==1:
name = 'alex'
print(name)
func()
// 成功
情況二:
def func():
if 1==1:
name = 'alex'
print(name)
func()
print(name)
// 報錯
而javascript的作用域具有如下特點:
2.1 以函數作為作用域
先看下以下代碼:
var name='cc';
function func(){
console.log(name);
if(1==1){
var name = 'dd';
}
console.log(name);
}
func()
第一句輸出的是:undefined,而不是cc;
第二句輸出的是:dd
大家可能認為第一句會輸出cc,因為代碼還未執行var name='dd';所以肯定會輸出cc;
上面我們已經說過,javascript是以函數作為作用域。實際上以上代碼可重新編寫:
var name='cc';
function func(){
var name;
console.log(name);
if(1==1){
var name = 'dd';
}
console.log(name);
}
func()
name聲明覆蓋了全局的name,但還沒有賦值,所以輸出undefined;
2.2 函數的作用域在函數未被調用之前,已經創建
function func(){
if(1==1){
var name = 'cc';
}
console.log(name);
}
2.3 函數的作用域存在作用域鏈,並且也是在被調用之前創建
我們來看第一個例子:
xo = "cc";
function func(){
var xo = 'eric';
function inner(){
var xo = 'tony';
console.log(xo);
}
inner()
}
func()
輸出:tony;
注釋掉var xo='tony';一行,輸出:eric;
同時注釋掉var xo='tony';和var xo='eric';輸出cc;
示例二:
xo = "cc";
function func(){
var xo = 'eric';
function inner(){
console.log(xo);
}
return inner;
}
var ret = func()
ret()
示例三:
xo = "alex";
function func(){
var xo = 'eric';
function inner(){
console.log(xo);
}
var xo = 'tony';
return inner;
}
var ret = func()
ret()
2.4 函數內局部變量聲明提前
function func(){
console.log(name);
}
func();
// 程序直接報錯
function func(){
console.log(name);
var name = 'cc';
}
//解釋過程中:var name;
func();
// undefined
3. javascript高級知識-詞法分析
js運行前有一個類似編譯的過程即詞法分析,詞法分析主要有三個步驟:
-
分析參數;
-
再分析變量的聲明;
-
分析函數說明;
具體步驟如下:
-
函數在運行的瞬間,生成一個活動對象(Active Object),簡稱AO;
-
分析參數
-
函數接收形式參數,添加到AO的屬性,並且這個時候值為undefine,例如AO.age=undefined;
-
接收實參,添加到AO的屬性,覆蓋之前的undefined;
-
分析變量聲明,如var age;或var age=23;
-
如果上一步分析參數中AO還沒有age屬性,則添加AO屬性為undefined,即AO.age=undefined;
-
如果AO上面已經有age屬性了,則不作任何修改;
-
分析函數的聲明,如果有function age(){};把函數賦給AO.age ,覆蓋上一步分析的值;
這樣說可能大家不是很理解,下面結合具體的例子看下:
3.1 例1:
<script>
function t1(age) {
console.log(age);
var age = 27;
console.log(age);
function age() {}
console.log(age);
}
t1(3);
</script>
詞法分析階段:
1)首先形成active object對象,即AO對象;
2)第一步分析形參:
AO.age=undefined;
傳入實參即對AO.age=undefined進行覆蓋:AO.age=3;
3)第二步分析局部變量:
存在var age=27;
這個時候遵循如果AO.age存在值則不作任何修改.按照第一步分析的最后結果AO.age = 3,所以這里不作任何修改即:AO.age = 3
4)第三步:分析函數的聲明:
因為函數中存在function age(){}函數
所以按照規則應該將函數賦值給AO.age覆蓋第二步分析的AO.age = 3即:
AO.age = function age(){}
執行階段:
執行t1函數,到console.log(age)時,詞法分析的最后AO.age= function age(){},所以會打印:
function age(){}
var age=27;給age賦值27
到第二個console.log(age)這個時候age已經重新被賦值27,所以這個時候會打印:
27
function age() 並沒有調用所以並不會執行
到第三個console.log(age)這個時候age的值並沒有被再次修改,所以這個時候會打印:
27
運行js查看結果如下與我們分析的完全相符:

3.2 代碼例子2:
function t1(age) {
var age;
console.log(age);
var age = 23;
console.log(age);
function age() {}
console.log(age);
}
t1(22)
詞法分析階段:
-
首先形成Active Object即AO對象
-
第一步:分析形式參數
AO.age = undefine
傳入實參即對AO.age=undefine進行覆蓋:
AO.age = 22
-
第二步:分析局部變量
第一步中最后得到AO.age = 22
所以這里var age;以及var age =23 ,因為AO.age屬性已經存在值,所以這個時候遵循如果存在則不作任何修改,即:
AO.age = 22
-
第三步:分析函數的聲明,
因為函數中存在function age(){}函數
所以按照規則應該將函數賦值給AO.age覆蓋第二步分析的AO.age = 22即:
AO.age = function age(){}
執行階段:
執行t1函數,到console.log(age)時,詞法分析的最后AO.age= function age(){},所以會打印:
function age(){}
var age=23;給age賦值23
到第二個console.log(age)這個時候age已經重新被賦值23,所以這個時候會打印:
23
function age() 並沒有調用所以並不會執行
到第三個console.log(age)這個時候age的值並沒有被再次修改,所以這個時候會打印:
23
運行js查看結果如下與我們分析的完全相符:

3.3 代碼例子3
function t1(age) {
var age;
console.log(age);
age = 23;
console.log(age);
function age() {
console.log(age);
}
age();
console.log(age)
}
t1(22)
詞法分析階段:
-
首先形成Active Object即AO對象
-
第一步:分析形式參數
AO.age = undefine
傳入實參即對AO.age=undefine進行覆蓋:
AO.age = 22
-
第二步:分析局部變量
第一步中最后得到AO.age = 22,所以這里遵循,如果AO.age存在值則不作任何修改即:
AO.age = 22
-
第三步:分析函數的聲明
因為函數中存在function age(){console.log(age)}函數
所以按照規則應該將函數賦值給AO.age覆蓋第二步分析的AO.age = 22即:
AO.age = function age(){console.log(age)}
執行階段:
執行t1函數,到console.log(age)時,詞法分析的最后AO.age= function age(){console.log(age)},所以會打印:
function age(){console.log(age)}
age = 23,這個時候會覆蓋原來的function age(){console.log(age)},所以第二個console.log(age)會打印:
23
function age() 是一個函數表達式,所以不會做任何操作
age() 這個時候的age還是23,並不是函數表達式,所以這里會報錯
運行js查看結果如下與我們分析的完全相符:

六、面向對象
1. 創建對象
function Foo(n){ //構造函數
this.name = n;//this等同於python面向對象的self
this.sayName = function(){
console.log(this.name);
}
}
var obj1 = new Foo('we'); //要創建對象的實例必須要用new操作符
obj1.name
obj1.sayName()
var obj2 = new Foo('wee'); //obj1 obj2都是Foo對象的實例
obj2.name
obj2.sayName()
構造函數的缺點:使用構造函數創建每個實例的時候,構造函數里的方法都要在每個實例上重新創建一遍,這樣會浪費內存;
2. 原型
為了解決上述問題,javascript引入了一個prototype-原型;
我們創建的每個函數都有一個prototype(原型)屬性,這個屬性是一個對象;
用途:包含可以由特定類型的所有實例共享的屬性和方法;
理解:prototype是通過調用構造函數創建的那個對象的原型對象;
使用原型的好處是可以讓所有對象實例共享它所包含的屬性和方法;
也就是說,不必在構造函數中定義對象信息(屬性/方法),而是可以直接將這些信息添加到原型中;
function Foo(n){
this.name = n;
}
# Foo的原型
Foo.prototype = {
'sayName': function(){
console.log(this.name)
}
}
obj1 = new Foo('we');
obj1.sayName()
obj2 = new Foo('wee');
