JS課程安排:
- JS基礎 :6天
- WebAPI: 6-7天
- JS高級:5天
- jQuery:5天
JS基礎:
- 基本介紹、語法、變量、數據類型、運算符
- 條件、循環
- 數組、函數
- 函數——作用域、預解析
- 創建對象、數據類型深入、內置對象
- 內置對象和方法
目錄
1. 簡介
Brendan Eich 在95年花了10天時間設計出了JavaScript,並且因爲它不喜歡Java,所以也不喜歡JavaScript
1.1 JS分三個部分:
- ECMAScript 標準——基本語法
- DOM——Document Object Model
- BOM—— Browser Object Model
1.2 JS能做的東西:
- 網頁特效
- 服務端開發 node.js
- 命令行工具 node.js
- 桌面 Electron
- App Cordova
- 控制硬件-物聯網 Ruff
- 遊戲開發 cocos2d-js
1.3 JavaScript語言特點
- 腳本語言
- 解釋性語言
- 動態類型語言
- 基於對象的語言
1.4 Js代碼書寫位置
- 在script標籤中
<script>
alert('haha');
</script>
- 寫在html標籤中:
<button onclick="alert('abc');" />
- **在外部.js文件中,由html文件引入: **
<script src="demo.js" ></script>
1.5 js代碼的注意問題
- 在一對
script
標籤中有錯誤的代碼,後面的代碼也不會執行 - 一對
script
標籤的錯誤,不會影響其他script
標籤中的代碼執行; - 在
script
標籤中,本來要寫type="text/javascript"
或者language="JavaScript"
,但是html5標準中可以省略 type
和language
也可以同時寫在script
中script
標籤在頁面中可以出現多個script
標籤的位置一般放在<body>
內部的最後端,有時會放在head中- 如果一個
script
標籤的作用是引入外部的js文件,那麼這個script
標籤中不要寫代碼
WebStorm不是直接打開文件顯示的,而是自己以一個小型服務器的方式瀏覽頁面
2. 變量
2.1 變量聲明初始化
a. 基本代碼規範:
- JS變量區分大小寫
- 聲明變量使用
var
- 字符串使用單引號或者雙引號
- 語句用分號結尾
b. 變量名規範:
- 一般以字母,$,下劃線,數組組成,但不能以數字開頭
- 變量名一般小寫
- 使用camelCase方式命名
- 不能使用關鍵字
- 第二次初始化同一個變量名,則初始化會變成賦值
c. 聲明+初始化:
var num = 10;
var num1, num2, num3;
var num1, num2, num3 = 10;
var num1=10, num2 = 10, num3 = 20;
var num1 = num2 = num3 = 30;
var name = '小黑'; // 字符串使用 " 或者 '
var flag = true;
var obj = null;
console.log(flag);
2.2 代碼註釋
// 單行註釋
/*
多行註釋
*/
/**
* 這是說明這個函數是幹什麼的
* @param param1 這裏說明這個param1參數是幹什麼的
* @return {} 這裏說明返回值是個什麼
* */
2.3 變量類型
a. 原始數據類型:
number
: 整數和小數都是 number 類型, NaN也是number類型string
boolean
null
: 類型還是 objectundefined
: 變量聲明沒賦值、 函數沒有返回值確賦值給了一個變量; undefined 和數字運算,結果爲 NaN,也是number類型object
b. 查看變量類型:
typeof(變量);
typeof 變量;
// number string boolean object undefined object function
c. 進製表示
十六進制: 0x
八進制: 0
d. 數字類型
數字最大最小值
Number.MAX_VALUE
Number.MIN_VALUE
Infinity // 無窮大
-Infinity //無窮小
不要用小數和小數相等
(0.1+0.2) == 0.3 // false
和NaN比較
- 數字和undefined運算,結果是NaN,類型爲number;
- 數字和NaN運算,結果是NaN,類型爲number
- 使用
isNaN
判斷 isNaN
不光能用來判斷NaN
,主要可以判斷是不是數字
var num;
typeof (num+10); // number---NaN
num+10 == NaN; // false , NaN之間用 == 比較都是false
// 使用 isNaN判斷
isNaN(10); // NaN != NaN
e. 字符串
長度
// 長度
var strvar = "hahsasdsad";
strvar.length
拼接
- 加法中有一個是字符串,則會轉變成字符串拼接
- 如果使用了減法、乘法、除法,則會嘗試將字符串變成數字後運算。如果轉換失敗,則返回
NaN
// 拼接:
str3 = str1 + str2
console.log(10+"20"); // 1020
console.log(10-"20"); // -10
console.log(10 * "5"); // 50
2.4 ★類型轉換
其他類型轉數字:
parseInt("10"); //10
parseInt("10asdasdasd"); //10
parseInt("10.98"); //10
parseInt("asd10"); //NaN
parseFloat("10") //10
parseFloat("10asdasd") //10
parseFloat("10.98") //10.98
parseFloat("10.98asdsad") //10.98
parseFloat("asd10asdasd") //NaN
Number
就是轉數字, 和parse不同,它需要全部都是數字,更加嚴格。
Number("10"); //10
Number("10asdasd"); //NaN
Number("10.98"); //10.98
Number("10.98asdsad"); //NaN
Number("asd10asdasd"); //NaN
其他類型 轉字符串:
第一種:(要變量有意義,比如不能爲 undefined, null)
num.toString(); //變量無意義,則無法使用 toString()
第二種:
String(var);
第三種:
var + '';
其他類型轉boolean:
Boolean(var):
1 true
0 false
11 true
-10 true
"hah" true
"" false
null false
undefined false
3. 操作符
- 算數運算符:
+ - * / %
( python沒有整除,需要用 parseInt來取整) - 一元運算符:
++ --
- 二元運算符:
- 三元運算符:
?:
- 賦值運算符:
+= -= /= %= *=
(字符串和數字比較的時候會有類型轉換) - 關係運算符:
> >= < <= == === != !===
== 不嚴格的等於:
var str = "5";
var int = 5;
str == int ; // true
=== 嚴格的等於:
str === int ; // false
- 邏輯運算符:
&& || !
var a = null;
// 沒報錯,短路比較
if(a != null && a.length > 5){
alert(a.length);
}
算術運算表達式
關係運算表達式
邏輯運算表達式
優先級
優先級從高到底
1. () 優先級最高
2. 一元運算符 ++ -- !
3. 算數運算符 先* / % 後 + -
4. 關係運算符 > >= < <=
5. 相等運算符 == != === !==
6. 邏輯運算符 先&& 後||
7. 賦值運算符
4. 條件
if (條件){ // 條件部分會被轉換成 Boolean
}
if(){
} else{
}
if(){
} else if(){
} else{
}
//三元表達式
let result = a?b:c;
// switch判斷
switch (key) {
case value:
//代碼..
break;
default:
break;
}
switch 注意事項
switch內部的比較是使用的===
,判斷類型+內容,而不是==
var age = "10"
switch (key) {
case 10:
..
break;
case "10":
console.log("字符串10"); // 會執行這一句
break;
}
5. 循環
document.write()
寫到HTML文檔中的東西,在源代碼中看不到,而在調試窗口的element能看到。
- while
- do-while
- for
continue
,break
while (condition) {
語句
}
do {
語句
} while (condition);
for (let index = 0; index < array.length; index++) {
const element = array[index];
}
for in
for of
a.foreach
6. 數組
6.1 創建數組
- 通過構造函數
var ar = new Array(); // 構造函數創建空數組
var ar = new Array(5); // 創建長度爲5的數組, 每個元素都是 undefined
var ar = new Array(1,2,"3",new Object()); // 直接傳入內容
console.log(arra.length);
- 通過字面量
var ar = []; //字面量創建
數組特點
- 使用長度的方式創建數組,數組內部的值都是
undefined
- 數組可以存儲不同類型內容
- 可以動態給數組的任意索引賦值,這能改變數組長度,並且沒有值的都是
undefined
6.2 動態改變數組長度
var ar = [];
alert(a.length); // 0
ar[1] = "";
alert(a.length); // 2
a[2] ; //undefined 不存在的值會undefined
6.3 遍歷
for(let i = 0; i < a.length; i++){
}
a.forEach(element => {
console.log(element);
});
for (const iterator of a) {
console.log(iterator);
}
7. 函數
7.1 函數定義
function funcname(arg1, arg2){
...
return result;
}
Math.PI
★函數的注意問題:
- 函數一旦重名(多次定義),後面的會覆蓋前面的函數
function f1(){
console.log('1');
}
f1();
function f1(){
console.log('2');
}
f1();
// 結果會打印2次 2
- 形參的個數和實參的個數可以不一致(可多可少), 沒有傳遞的值或者接收了沒有return的函數值,結果是
undefined
function haha(x,y) {
console.log(x);
console.log(y);
console.log(arguments.length);
}
haha(); // undefined undefined 0
haha(1,2,3); // 1 2 3
- 直接輸出函數名字,結果爲函數的代碼
7.2 函數的參數和返回值
a. 返回值問題
- 如果沒有return,函數返回值爲
undefined
- 如果return後面沒有內容,則返回值也是
undefined
b. arguments
arguments
是一個僞數組
function funcname(x, y){
console.log(arguments); // 獲取所有傳入的參數 arguments.length
}
7.3 命名函數和匿名函數
函數有名字就是命名函數,沒名字就是匿名函數
function(){
// 這是匿名函數
}
function f1(){
// 這是匿名函數
}
函數自調用——匿名函數直接調用
(function (){
})()
7.4 ★函數聲明和函數表達式
- 函數能夠調用,是因爲函數名存儲的函數的代碼:
- 如果函數能被調用,則調用方式爲:
函數的代碼();
1. 函數聲明
function f1(){
}
f1(); // 函數代碼();
2. 函數表達式
函數表達式後面要加分號
var f2 = function (){
};
f2();
3. 函數表達式的覆蓋問題
函數聲明重名的,後面覆蓋前面的,導致前面的失效; 而函數表達式,只有在賦值的時候,纔會覆蓋:
function f1(){
console.log('1');
}
f1(); // 2
function f1(){
console.log('2');
}
f1(); // 2
f2 = function (){
}
f2();
// 1
f2 = function (){
console.log('2');
}
f2();
// 2
7.5 函數作爲參數和返回值
函數作爲參數,叫做回調函數
typeof f1 // function
function f1(f2){
f2();
}
function f2(){
}
作爲返回值:
function f3(){
return function(){
console.log();
}
}
fn = f3();
fn();
7.6 ★作用域
1. 跨越script標籤
跨越script標籤,也可以引用:
<script>
var num = 10;
console.log(num); // 10
</script>
<script>
console.log(num); // 10
</script>
2. 塊級作用域
在沒有
let
之前,js沒有塊級作用域
{
var num = 10;
}
console.log(num); // 10
使用let
定義的,纔是塊級作用域; 用var
的話,沒有塊級作用域
3. 全局變量
var
在函數外面聲明的變量是全局變量- 除了函數內部定義的, 其他定義的都是全局變量(除了let)
4. 局部變量
函數內部定義的是局部變量, 只在函數內部有效
5. 隱式全局變量
- 聲明變量沒有使用
var
,叫作隱式全局變量 - 隱式全局變量定義在函數中,外面也能訪問
- 定義變量使用
var
是不會被刪除的,沒有使用var
是會被刪除的
var num1 = 10;
num2 = 20;
delete num1;
delete num2;
console.log(typeof num1); // number
console.log(typeof num2); // undefined
6. 作用域鏈
- 標籤內定義的叫做0級作用域
- 0級作用域定義的函數內部,叫做1級作用域
- …
- 函數最內層查找變量的順序,是 N級–> … --> 3級–> 2級–>1級–>0級
下面的num
,會一層層向上找,直到找到
var num = 10;
function f1(){
var num = 20;
function f2(){
var num = 30;
function f3(){
var num = 40;
console.log(num);
}
f3();
}
f2();
}
f1();
7.5 ★★預解析
JavaScript代碼的執行是由瀏覽器中的JavaScript解析器來執行的。JavaScript解析器執行JavaScript代碼的時候,分爲兩個過程:
- 預解析過程
- 代碼執行過程
- 把變量的聲明提升到當前作用域的最前面,只會提升聲明,不會提升賦值。
- 把函數的聲明提升到當前作用域的最前面,只會提升聲明,不會提升調用。
- 先提升var,在提升function
- 變量提升
定義變量的時候,變量的聲明會被提升到作用域的最上面,變量的賦值不會提升。 - 函數提升
JavaScript解析器首先會把當前作用域的函數聲明提前到整個作用域的最前面
特點
- 瀏覽器把變量、函數的聲明提前了,提前到當前作用域的最上面,不會提升到作用域之外
- 多對
<script>
之間的預解析不會衝突——只會在各自範圍內進行預解析 - 先提升
var
再提升function
,即 var在function之前 - 函數表達式不會提升
例子
例1——預解析提前 變量聲明
console.log(num); // 結果爲 undefined,代表變量聲明瞭但是沒賦值
var num = 10;
例2——預解析提前函數聲明
f1() // 調用成功,說明函數聲明被提前了
function f1(){
console.log("haha")
}
例3——num提前到作用域內部的頂端
var num = 20;
function f1(){
console.log(num); // 結果爲undefined, 說明 內部的num被提升到了 f1內部作用域的頂端
var num = 10;
}
f1();
//相當於:
var num = 20;
function f1(){
var num;
console.log(num);
num = 10;
}
例4:
f1(); // 打印 undefined
var num = 20;
function f1(){
console.log(num);
}
// 相當於:
var num;
function f1(){
console.log(num);
}
f1(); // 所以是undefined
num = 20;
例5——預解析不會把變量提升到函數外
function f1(){
console.log(num); // undefined
var num = 10;
}
f1();
console.log(num); // 報錯
//相當於
function f1(){
var num;
console.log(num);
num = 10;
}
f1();
console.log(num);
例6:——預解析只在script標籤內部(同一個全局作用域內)
<script>
f1(); // 1
function f1(){
console.log("1");
}
</script>
<script>
function f1(){
console.log("1");
}
</script>
<script>
function f1(){
console.log("1");
}
</script>
<script>
f1(); // 2
function f1(){
console.log("1");
}
</script>
例7:
console.log(a); // 易錯點:輸出函數代碼
function a(){
console.log('hahaha');
}
var a = 1;
console.log(a); // 輸出1
// 相當於
var a ;
function a(){...} // 此處a就變成了代碼
console.log(a);
a = 1;
console.log(a);
例8:—— 隱式全局變量的提升
f1();
console.log(c); // 9
console.log(b); // 9
console.log(a); // 報錯
function f1(){
var a = b= c = 9; //易錯點
console.log(a);
console.log(b);
console.log(c);
}
//提升後爲:
function f1(){
var a; //局部變量
a = 9;
b = 9; //隱式全局變量
c = 9; //隱式全局變量
console.log(a);
console.log(b);
console.log(c);
}
f1();
console.log(c);
console.log(b);
console.log(a);
例9——函數表達式不會提升
f1(); //無法調用, 因爲函數表達式不會提升, 只提升函數定義
var f1 = function(){
console.log(a);
var a = 10;
}
// 提升後爲:
var f1;
f1();
f1 = function(){...};
8. 對象
- JS本來沒有類的概念,只有對象。
- JS是基於對象的語言——萬物皆對象,而不是真正的面向對象的語言,但是可以模擬面向對象
- 判斷對象類型:
變量 instanceof 類型
- 訪問自己對象的屬性/方法:
this
8.1 創建對象
1. 通過調用系統的構造函數創建
new Object()
var obj = new Object();
// 添加屬性和方法
obj.age = 18;
obj.name = "foo";
obj.eat = function(){
this.age ... //當前對象中使用 this關鍵字
};
1b 工廠方法創建對象
function createPeople(name, age){
var person = new Object();
person.name = name;
person.age = age;
person.sayHi = function(){
};
}
2. 自定義構造函數創建
Object
是系統構造函數,系統定義方式爲:
function Object(value){}
使用構造函數. 和普通函數的區別就是名字開頭是否大寫
function Person(name, age){
this.name = name;
this.age = age;
this.sayHi = function(){
console.log(this.name);
}
}
var obj = new Person('haha',18);
obj instanceof Person
創建對象經歷的事情:
- 在內存中申請一塊空閒的空間,創建對象
- 把
this
設置爲當前對象 - 設置對象屬性和方法
- 返回this對象
3. 字面量形式創建
var obj = {};
obj.name = "";
obj.sayHi = function(){
console.log(this.name):
}
var obj = {
name: "小明",
age: 20;
sayHi: function(){
},
eat: function(){
}
};
8.2 獲取和設置對象的屬性、方法—— .
和 []
以某個變量值當做屬性名來訪問,就只能使用[]
obj.屬性名 // 不管有沒有,都能 點出來,點出來是 undefined
obj["屬性名"] = 值
obj.plary();
obj['play']();
8.3 Json
- 對象:是 屬性與方法的集合
- 對象:也是一組無序屬性的集合,屬性的值可以是任意類型
json: 鍵/值 都用雙引號括起來
var json = {
"name":"ab",
"age" : "18",
"sex": "male"
}
json.ddsdsd // 能點出來,但是沒有的屬性,都是 undefined
json.name
json["name"]
// 遍歷對象
for(var key in obj){
console.log(key); // 遍歷對象的屬性
console.log(obj[key]); // 注意不要使用 obj.key,這就成了訪問 'key'這個屬性了
}
8.4 JS的數據類型
原始數據類型: number, string, boolean, undefined, null, object:
- 基本類型(簡單),值類型: number, string, boolean
- 複雜類型(引用):object
- 空類型: undefined, null
var num1 = 66;
var num2 = 88;
function f1(num, num1) {
num = 100;
num1 = 100;
num2 = 100;
console.log(num1);
console.log(num2);
console.log(num);
}
f1(num1, num2);
console.log(num1);
console.log(num2);
console.log(num);
9. 內置對象
JS有三種對象:內置對象、自定義對象、瀏覽器對象
在MDN上自學
9.1 Math對象——是一個對象,但不是函數對象
Math的所有屬性都是靜態屬性
Math在內部的定義方式:
Math = {} //Math是用 {}定義的,而不是 function Math() , 所以無法new
Math.abs = function(){} //靜態
可以new的對象是這麼定義的:
function XXX(){
}
XXX.prototype.funcname = function(){} // 實例方法
// Math 的方法/屬性
Math.random(); // 返回[0,1)的小數
Math.PI
Math.E
Math.abs(null); ---0
Math.abs("abc"); ---NaN
.ceil .floor
.max .min
Math.pow(7,2); -- 49
Math.sqrt(16); -- 4
9.2 Date——創建實例對象使用
創建:
var birthday = new Date(1231252151251); // timestamp創建
var birthday = new Date(1995, 11, 17); // 12月17日,月份從0開始
var birthday = new Date(1995, 11, 17, 3, 24, 0);
var d = new Date('2019-9-11')
var current = new Date();
var now = Date.now(); 返回當前時間的timestamp(毫秒)
獲取方法:
var now = new Date();
now.getFullYear(); // 獲取年份
now.getMonth(); // 獲取月份,從0開始
now.getDate(); // 獲取日期
now.getDay(); // 獲取星期,從0開始
now.getHours();
now.getMinutes();
now.getSeconds();
now.getMilliseconds()
d.valueof() //獲得毫秒
var d = + new Date() //不支持H5的瀏覽器 通過這種方式獲取毫秒
封裝獲取日期時間函數:
function formatDate(d) {
//如果date不是日期對象,返回
if (!date instanceof Date) {
return;
}
var year = d.getFullYear(),
month = d.getMonth() + 1,
date = d.getDate(),
hour = d.getHours(),
minute = d.getMinutes(),
second = d.getSeconds();
month = month < 10 ? '0' + month : month;
date = date < 10 ? '0' + date : date;
hour = hour < 10 ? '0' + hour : hour;
minute = minute < 10 ? '0' + minute:minute;
second = second < 10 ? '0' + second:second;
return year + '-' + month + '-' + date + ' ' + hour + ':' + minute + ':' + second;
}
9.3 String
字符串是不可變的
string
——字符串類型——基本類型
var str = "內容";
String
——字符串類型——引用類型
var str2 = new String("內容"); // 引用類型
str.length
str.concat(str2,str3..)
str.indexOf('substr')
str.match(regex)
.replace .search .slice .split .substr .substring
.toLowerCase .toUpperCase .trim()
String.fromcharcode()
9.4 Array
創建方式
- 字面值:
[]
- 構造函數:
new Array()
判斷是不是數組
Array.isArray()
ar instanceof Array
方法 | 描述 |
---|---|
Array.isArray() |
判斷是不是數組 |
arr.length | 獲取長度 |
Array.from([1,2,3,4]) |
從已有數組創建新數組 |
arr1.concat(arr2) |
數組拼接 |
arr.every(callback[, thisArg]) |
所有元素都要滿足條件,才返回true |
arr.filter(callback[, thisArg]) |
返回滿足條件元素構成的新數組 |
添加和刪除方法 | |
arr.pop() |
從後面刪除並且返回 |
arr.push(值) |
在後面插入,返回數組長度 |
arr.shift() |
刪除第一個元素並且返回 |
.arr.unshift(值) |
在前面插入,返回長度 |
arr.foreach(callBack) |
遍歷 |
arr.indexOf() |
|
var str = arr.join('符號') |
|
arr.map(callback) |
|
arr.reverse() |
|
arr.sort(callback) |
|
arr.slice(1,3) |
返回淺拷貝,第一個包括,第二個參數不包括 |
9.5 基本包裝類型
隱式轉換成基本包裝類型
- 普通變量沒法調用屬性和方法
- 本身是基本類型,但是在執行代碼的過程中,如果這種類型變量調用了屬性或者方法,那麼這種類型就不再是基本類型了, 而是基本包裝類型; 這個變量也就變成了包裝類型:
基本類型:
- string
- number
- boolean
var str1 = "hello";
str1.replace("ll","HH"); // 調用了方法, 這個變量就成了基本包裝類型對象
str.indexOf()
num.toString()
Boolean的基本包裝類型
- 如果是一個對象&&true, 結果爲true
- 如果是 true&&對象,返回結果爲 這個對象
// boolean的基本包裝類型
var flag = new Boolean(false);
flag && true // true , 因爲第一個是對象,對象是true
true && flag // 返回是這個對象
基本包裝類型 vs. 類型轉換
var num2 = Number("10"); //類型轉換
var num3 = new Number("10"); //基本包裝類型
案例練習
交換2個變量的值:
var num1 = 10, num2 = 20;
var num1 = num1 + num2;
num2 = num1 - num2;
num1 = num1 - num2;
var num1 = 10, num2 = 20;
var temp = num2;
num2 = num1;
num1 = temp;
console.log(num1,num2);
var num1 = 10, num2 = 20;
num1 = num1 ^ num2;
num2 = num1 ^ num2;
num1 = num1 ^ num2;
++、–練習
var a = 1;
alert( ++a + ++a + ++a); //9
alert(a); //4
閏年
let year = parseInt(prompt("請輸入年份"));
if (year % 400 == 0){
alert("閏年");
}
else if(year % 4 == 0 && year % 100 != 0 ){
alert("閏年");
}
else{
alert("不是閏年");
}
畫星星、乘法口訣表
冒泡排序
var a = [4, 6, 7, 1, 3, 8, 10, 9, 5];
for (let i = 0; i < a.length - 1; i++) {
for (let j = 0; j < a.length -i-1; j++) {
if (a[j] > a[j + 1]) {
let temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
alert(a);