JavaScript介紹
什麼是JavaScript?
Javascript是一門物件導向的,跨平臺的指令碼語言。
JavaScript有什麼特點?
- 解釋性指令碼語言
- 執行在瀏覽器(瀏覽器核心帶有js直譯器,Chrome v8引擎)
- 弱型別語言(鬆散型)
- 事件驅動(動態)
- 跨平臺
JavaScript有什麼用途?
- 嵌入動態文字於HTML頁面
- 對瀏覽器事件做出響應
- 讀寫HTML元素
- 在資料被提交到伺服器之前驗證資料
- 檢測訪客的瀏覽器資訊(可以使用js程式碼判斷瀏覽器型別)
- 控制cookies,包括建立和修改等
- 基於Node.js技術進行伺服器端程式設計
JavaScript作用域?
作用域:變數的作用範圍,主要有以下幾種:
- 全域性變數
作用範圍為整個程式的執行範圍,在函式體外部定義的變數就是全域性變數,在函式體內部不使用var定義的也是全域性變數。
- 區域性變數
作用範圍是某個函式體內部,在函式體內部通過var關鍵字定義的變數或者形參,都是區域性變數,當區域性變數與全域性變數重名時,在函式體內部區域性變數優先於全域性變數。
- 變數提升
變數的宣告會提升至當前作用域的最頂端,但不會提升賦值
暫存性死區
在相同的函式或塊作用域內重新宣告同一個變數會引發SyntaxError;
在宣告變數或常量之前使用它, 會引發ReferenceError. 這就是暫存性死區。
這裡主要存在兩個坑點:
- switch case中case語句的作用域
switch (x) {
case 0:
let foo;
break;
case 1:
let foo; // TypeError for redeclaration.
break;
}
會報錯是因為switch中只存在一個塊級作用域, 改成以下形式可以避免:
let x = 1;
switch(x) {
case 0: {
let foo;
break;
}
case 1: {
let foo;
break;
}
}
- 與詞法作用域結合的暫存死區
function test(){
var foo = 33;
if (true) {
let foo = (foo + 55); // ReferenceError
}
}
test();
在if語句中使用了let宣告瞭foo, 因此在(foo+55)中引用的是if塊級作用域中的foo, 而不是test函式中的foo; 但是由於if中的foo還沒有宣告完。
在這一行中,if塊的“foo”已經在詞法環境中建立,但尚未達到(並終止)其初始化(這是語句本身的一部分)
因此它仍處於暫存死區
變數生命週期
全域性變數的生命週期直至瀏覽器解除安裝頁面才會結束。
區域性變數只在函式的執行過程中存在,而在這個過程中會為區域性變數在棧或堆上分配相應的空間,以儲存它們的值,然後再函式中使用這些變數,直至函式結束
執行環境執行棧
執行環境執行棧(也稱執行上下文–execution context)。
當JavaScript直譯器初始化執行程式碼時,它首先預設進入全域性執行環境,從此刻開始,函式的每次呼叫都會建立一個新的執行環境,每一個執行環境都會建立一個新的環境物件壓入棧中。
當執行流進入一個函式時,函式的環境物件就會被壓入一個環境棧中(execution stack)。在函式執行完後,棧將其環境彈出,把控制權返回給之前的執行環境。
嚴格模式
除了正常執行模式,ECMAscript 5 新增了第二種執行模式:"嚴格模式"(strict mode)。顧名思義,這種模式使得Javascript在更嚴格的條件下執行。其主要有下面這幾個目的:
- 消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為;
- 消除程式碼執行的一些不安全之處,保證程式碼執行的安全;
- 提高編譯器效率,增加執行速度;
- 為未來新版本的Javascript做好鋪墊。
"嚴格模式"體現了Javascript更合理、更安全、更嚴謹的發展方向,包括IE 10在內的主流瀏覽器,都已經支援它。
同樣的程式碼,在非嚴格模式下可以執行,但是嚴格模式下可能將不能執行。
如何進入嚴格模式
<script>
"use strict"
console.log("已經進入嚴格模式");
</script>
嚴格模式行為變更
- 全域性變數宣告時 必須加var
<script>
"use strict"
a = 10;//報錯 因為 a沒有被var 宣告
//Uncaught ReferenceError: a is not defined; 引用錯誤: a 沒有被宣告
</script>
- this 無法指向全域性物件
<script>
"use strict"
// console.log("已經進入嚴格模式");
function a(){
this.b = 10; //報錯 , 因為this指向了window物件;
//Uncaught TypeError: Cannot set property 'b' of undefined; 型別錯誤 : 不能給undefined設定屬性b;
}
window.a();
</script>
- 函式內重名屬性
<script>
"use strict";
function a(b,b,c){ //報錯
console.log(b,b,c); // 正常模式下 2,2,3
// Uncaught SyntaxError: Duplicate parameter name not allowed in this context ;語法錯誤:在此上下文中不允許重複的引數名稱
}
a(1,2,3)
</script>
- arguments物件
arguments物件不允許被動態改變;
<script>
function fn1(a) {
a = 2;
return [a, arguments[0]];
}
console.log(fn1(1)); // 正常模式為[2,2]
function fn2(a) {
"use strict";
a = 2;
return [a, arguments[0]];
}
console.log(fn2(1)); // 嚴格模式為[2,1]
</script>
arguments物件不允許被自呼叫
<script>
"use strict";
var f = function() { return arguments.callee; };
f(); // 報錯
//Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
//型別錯誤:“caller ”,“arguments.callee ”,不能在嚴格模式中使用;
//caller返回撥用當前函式的函式的引用 (正在執行的函式的屬性)
// callee返回正在執行的函式本身的引用 (arguments的屬性)
</script>
this
this是js的關鍵字,他是根據執行上下文(執行環境)動態指向當前呼叫的物件;
誰呼叫,就指誰;
call()、apply()、bind() 可以改變this的指向
js的物件
js語言中一切皆為物件,比如數字、字串、陣列、Math、Object、函式
js中物件的本質:屬性和方法的集合(無序,所以物件沒有length屬性)。
用官方一點的語言來解釋物件:
什麼是物件,其實就是一種型別,即引用型別。而物件的值就是引用型別的例項。在 ECMAScript 中引用型別是一種資料結構,用於將資料和功能組織在一起。它也常被稱做為類,但 ECMAScript6以前卻沒有這種東西。雖然 ECMAScript 是一門物件導向的語言,卻不具備傳統面嚮物件語言所支援的類等基本結構。
特點
封裝、繼承、多型
- 封裝:
1、寫物件
2、用物件
把一些相關的物件和屬性放到一起,用一個變數抽象出來,那麼這就完成了這個物件的封裝
- 繼承:
子承父業
子物件可以使用父物件的一些屬性和方法
- 多型:
過載,重寫
過載就是根據不同的引數型別,引數個數實現不同的功能
重寫就是父類的方法不好用,我自己重新定義一個方法名相同的不同方法
定義方式
- 字面量
var obj = {
鍵值對
key:value
}
- new運算子
var obj = new Object()
- 建構函式
function Person(name,age,job){
this.name= name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
}
}
var person1 = new Person('monkey',30,'web');
var person2 = new Person('zhu',25,'h5');
- 工廠模式
工廠模式抽象了建立具體物件的過程。由於在ECMAScript中無法建立類,開發人員就發明了一種函式,用函式來封裝以特定介面建立物件的細節,如下面的例子:
function createPerson(name,age,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
}
return o;
}
var person1 = createPerson('monkey',30,'web');
var person2 = createPerson('zhu',25,'h5');
- ES6 class語法糖
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
常用方法
內建物件
String
字串的兩種建立方式(常量和建構函式),常用api有:
- charAt() 返回在指定位置的字元
- indexOf() 檢索字串,返回下標
- lastIndexOf() 從後向前搜尋字串。
- charCodeAt() 返回在指定的位置的字元的 Unicode 編碼。
- fromCharCode() 從字元編碼建立一個字串。
- concat() 連線字串。
- match() 找到一個或多個(正規表示式的)匹配。
- replace() 替換與正規表示式匹配的子串。
- search() 檢索與正規表示式相匹配的值。
- slice() 提取字串的片斷,並在新的字串中返回被提取的部分。
- split() 把字串分割為字串陣列。
- substr() 從起始索引號提取字串中指定數目的字元。
- substring() 提取字串中兩個指定的索引號之間的字元。
- toLowerCase() 把字串轉換為小寫。
- toUpperCase() 把字串轉換為大寫。
- trim() 去掉字串前後空格(ES5)
- startsWith() 字串是否以某個字元開頭(ES6)
- endsWith() 字串是否以某個字元結尾(ES6)
- includes() 字串是否包含某個字元(ES6)
- repeat() 重複某個字串幾次(ES6)
Math
Math的常用屬性有:
- Math.E 返回算術常量 e,即自然對數的底數(約等於2.718)。
- Math.LN2 返回 2 的自然對數(約等於0.693)。
- Math.LN10 返回 10 的自然對數(約等於2.302)。
- Math.LOG2E 返回以 2 為底的 e 的對數(約等於 1.414)。
- Math.LOG10E 返回以 10 為底的 e 的對數(約等於0.434)。
- Math.PI 返回圓周率(約等於3.14159)。
- Math.SQRT1_2 返回返回 2 的平方根的倒數(約等於 0.707)。
- SQRT1_2.SQRT2 返回 2 的平方根(約等於 1.414)。
常用api有:
- abs(x) 返回數的絕對值。
- sin(x) 返回數的正弦。
- cos(x) 返回數的餘弦。
- tan(x) 返回角的正切。
- ceil(x) 對數進行上舍入。
- floor(x) 對數進行下舍入。
- round(x) 把數四捨五入為最接近的整數。
- max(x,y) 返回 x 和 y 中的最高值。
- min(x,y) 返回 x 和 y 中的最低值。
- pow(x,y) 返回 x 的 y 次冪。
- sqrt(x) 返回數的算術平方根。
- random() 返回 0 ~ 1 之間的隨機小數,包含0不包含1
Date
常用api有:
- getDate() 從 Date 物件返回一個月中的某一天 (1 ~ 31)。
- getDay() 從 Date 物件返回一週中的某一天 (0 ~ 6)。
- getMonth() 從 Date 物件返回月份 (0 ~ 11)。
- getFullYear() 從 Date 物件以四位數字返回年份。
- getYear() 請使用 getFullYear() 方法代替。
- getHours() 返回 Date 物件的小時 (0 ~ 23)。
- getMinutes() 返回 Date 物件的分鐘 (0 ~ 59)。
- getSeconds() 返回 Date 物件的秒數 (0 ~ 59)。
- getMilliseconds() 返回 Date 物件的毫秒(0 ~ 999)。
- getTime() 返回 1970 年 1 月 1 日至今的毫秒數。
- getTimezoneOffset() 返回本地時間與格林威治標準時間 (GMT) 的分鐘差。
- parse() 返回1970年1月1日午夜到指定日期(字串)的毫秒數。
- setDate() 設定 Date 物件中月的某一天 (1 ~ 31)。
- setMonth() 設定 Date 物件中月份 (0 ~ 11)。
- setFullYear() 設定 Date 物件中的年份(四位數字)。
- setYear() 請使用 setFullYear() 方法代替。
- setHours() 設定 Date 物件中的小時 (0 ~ 23)。
- setMinutes() 設定 Date 物件中的分鐘 (0 ~ 59)。
- setSeconds() 設定 Date 物件中的秒鐘 (0 ~ 59)。
- setMilliseconds() 設定 Date 物件中的毫秒 (0 ~ 999)。
- setTime() 以毫秒設定 Date 物件。
js陣列
上學時,班上的同學會進行分組,如下圖,一豎排是一組
一列就是一個陣列,一個陣列裡面有很多個元素(多個同學),因為js是弱型別語言,所以陣列也是弱型別,同一個陣列變數裡可以有各種不同型別的元素。
定義方式
- 字面量
var arr = [];
- new運算子
var arr = new Array();
//建構函式的方式
var arr = new Array(10);//一個引數指陣列長度為10
var arr = new Array(10,20,30);//多個引數指定義陣列元素
常用方法
- concat():連線兩個或更多的陣列,並返回結果。
- join():把陣列的所有元素放入一個字串。元素通過指定的分隔符進行分隔。
- pop():刪除並返回陣列的最後一個元素
- push():向陣列的末尾新增一個或更多元素,並返回新的長度。
- shift():刪除並返回陣列的第一個元素
- unshift():向陣列的開頭新增一個或更多元素,並返回新的長度
- reverse():顛倒陣列中元素的順序
- slice():從某個已有的陣列返回選定的元素
- sort():對陣列的元素進行排序
- splice():刪除元素,並向陣列新增新元素
- toString():把陣列轉換為字串,並返回結果
ES5新增陣列方法
- indexOf()
判斷一個元素是否存在於陣列中,若不存在返回-1,若存在就返回它第一次出現的位置
- lastIndexOf()
lastIndexOf() 方法可返回一個指定的字串值最後出現的位置,在一個字串中的指定位置從後向前搜尋
- forEach()
迴圈遍歷陣列中的每一個元素,這個函式包含三個形參,分別為:item, index, array, 用不到時可以不寫
- map()
返回一個新陣列,新陣列是原陣列的對映,不改變原陣列,新陣列的元素值是每次函式return的返回值,若不寫return,接收的新陣列的元素值將全為空
- filter()
過濾元素,返回一個新陣列,新的陣列由每次函式返回值為true對應的元素組成;
原陣列不受影響
- some()
return返回的值只要有一項為true,最終的返回值就為true,不會繼續遍歷後邊的元素,若沒有一項滿足返回值為true的,就返回false,原陣列不受影響;
- every()
對陣列的每一項執行給定的函式,假如該函式每一項都返回true,最後結果才為true;只要有一項返回值為false,最後結果就是false。且後邊的元素都不會再繼續執行函式;原陣列不受影響
- reduce()
reduce() 方法接收一個函式作為累加器,陣列中的每個值(從左到右)開始縮減,最終計算為一個值。reduce() 可以作為一個高階函式,用於函式的 compose
reduce() 對於空陣列是不會執行回撥函式的
- reduceRight()
reduceRight() 方法的功能和 reduce() 功能是一樣的,不同的是 reduceRight() 從陣列的末尾向前將陣列中的陣列項做累加。
reduceRight() 對於空陣列是不會執行回撥函式的
ES6新增陣列方法
- find()
傳入一個回撥函式,找到陣列中符合當前搜尋規則的第一個元素,返回它,並且終止搜尋
- findIndex()
傳入一個回撥函式,找到陣列中符合當前搜尋規則的第一個元素,返回它的下標,並且終止搜尋
- fill()
用新元素替換掉陣列內的元素,可以指定替換下標範圍。
格式:arr.fill(value, start, end)
- copyWithin()
選擇陣列的某個下標,從該位置開始複製陣列元素,預設從0開始複製。也可以指定要複製的元素範圍。
格式:arr.copyWithin(被替換的起始位置,選取替換值的起始位置,選取替換值的結束位置)
- Array.from()
將類似陣列的物件(array-like object)和可遍歷(iterable)的物件轉為真正的陣列
- Array.of()
用於將一組值,轉換為陣列
- entries()
返回迭代器:返回鍵值對
- values()
返回鍵值對的value
- keys()()
返回鍵值對的key
- includes()
判斷陣列中是否存在該元素,引數:查詢的值、起始位置,可以替換 ES5 時代的 indexOf 判斷方式。indexOf 判斷元素是否為 NaN,會判斷錯誤。
ES6新增
let/const
塊級作用域:一種普遍存在於各個語言中的作用域範圍;
擴充套件運算子 ...
三個點號,功能是把陣列或類陣列物件展開成一系列用逗號隔開的值
var foo = function(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}
var arr = [1, 2, 3];
//傳統寫法
foo(arr[0], arr[1], arr[2]);
//使用擴充套件運算子
foo(...arr);
//1
//2
//3
rest運算子
rest運算子也是三個點號,不過其功能與擴充套件運算子恰好相反,把逗號隔開的值序列組合成一個陣列
//主要用於不定引數,所以ES6開始可以不再使用arguments物件
var bar = function(a, ...args) {
console.log(a);
console.log(args);
}
bar(1, 2, 3, 4);
//1
//[ 2, 3, 4 ]
模板字串
ES6中存在一種新的字串, 這種字串是 以
(波浪線上的那個字元 > 反引號)括起來表示的;
通常我們想要拼接一個帶有標籤的字串, 是用這樣的方式:
bianliang + " <strong>這是一個文字" + obj.name + "</strong> " + bianliang
但是有了ES6字串一切都變得非常簡單了;
` ${bianliang} <strong>這是一個文字${obj.name}</strong>${bianliang} `
用 ${ } 擴住變數讓拼接變得非常容易;
=>箭頭函式
原來的寫法
var test = function(x){
return x+2;
}
使用箭頭函式:
var test = x =>x+2;
var 函式名 = 引數 => 運算規則;
箭頭函式this指向的固定化,並不是因為箭頭函式內部有繫結this的機制,實際原因是箭頭函式根本沒有自己的this,導致內部的this就是外層程式碼塊的this。正是因為這個,所以箭頭函式也不能做建構函式。主要有兩個缺陷:
- 箭頭函式是不能new的,它的設計初衷就跟建構函式不太一樣
- 箭頭函式如果要返回一個JSON物件,必須用小括號包起來 var test = ()=>({id:3, val=20})
解構賦值
var [a,b,c] = [1,2,3];
var {a,b,c} = {
a:1,
b:2,
c:3
}
var username = "zhangsan";
var age = 18;
var obj = {username,age};
Set和Map結構
想當初設計JS的時候,由於有SUN公司人員的參與 再加上當時如日中天的JAVA及其優秀的設計,才使得JS語法及記憶體設計跟JAVA會如此的接近。但JAVA很多優秀的內容,JS不知道為了什麼目的並沒有引入,例如Set和Map集合
Set集合
Set集合,本質上就是對陣列的一種包裝 例如:
let imgs = new Set();
imgs.add(1);
imgs.add(1);
imgs.add(5);
imgs.add("5");
imgs.add(new String("abc"));
imgs.add(new String("abc"));
// 列印的結果: 1 5 '5' 'abc' 'abc'
Set集合是預設去重複的,但前提是兩個新增的元素嚴格相等 所以5和"5"不相等,兩個new出來的字串不相等
關於遍歷的方法 由於Set集合本質上還是一個map,因此會有以下幾種奇怪的遍歷方法
var imgs = new Set(['a','b','c']);
//根據KEY遍歷
for(let item of imgs.keys()){
console.log(item);
} //a //b //c
//根據VALUE遍歷
for(let item of imgs.values()){
console.log(item);
} //a //b //c
//根據KEY-VALUE遍歷
for(let item of imgs.entries()){
console.log(item);
} //['a','a'] //['b','b'] //['c','c']
//普通for...of迴圈(for...of跟for-in的區別很明顯,就是直接取值,而不再取下標了)
for(let item of imgs){
console.log(item);
} //a //b //c
SET集合沒有提供下標方式的訪問,因此只能使用for來遍歷。
// 下面展示了一種極為精巧的陣列去重的方法
var newarr = [...new Set(array)];
Map集合
Map集合,即對映
let map = new Map();
map.set("S230", "張三");
map.set("S231", "李四");
map.set("S232", "王五");
獲取某一個元素 map.get("s232"); //王五
//迴圈遍歷,配合解構賦值
for(let [key,value] of map){
console.log(key,value);
}
BOM
BOM(Browser Object Model 瀏覽器物件模型),結構如下圖所示:
window是全域性瀏覽器內建頂級物件,表示瀏覽器中開啟的視窗(沒有應用於window物件的公開標準,不過所有瀏覽器都支援該物件)。
在客戶端 JavaScript 中,Window 物件是全域性物件,所有的表示式都在當前的環境中計算。
也就是說,要引用當前視窗根本不需要特殊的語法,可以把那個視窗的屬性作為全域性變數來使用。
例如,可以只寫 document,而不必寫 window.document。
同樣,可以把當前視窗物件的方法當作函式來使用,如只寫 alert(),而不必寫 Window.alert()。
除了上面列出的屬性和方法,Window 物件還實現了核心 JavaScript 所定義的所有全域性屬性和方法。
全域性變數
全域性變數預設是掛在window下的,例如:
var a = 123;
alert(window.a)//123
window下的子物件
location:
- window.location.href 當前頁面的 URL,可以獲取,可以修改(頁面跳轉)。
- window.location.hostname web 主機的域名
- window.location.pathname 當前頁面的路徑和檔名
- window.location.port web 主機的埠 (80 或 443)
- window.location.protocol 所使用的 web 協議(http:// 或 https://)
- window.location.search 請求引數(?後面的內容)
- window.location.reload() 重新整理頁面的方法。
一般情況下給reload()傳遞一個true,讓他重新整理,並不使用快取。快取的東西一般為js檔案,css檔案等。用這個方法可以讓自己不能動的頁面動起來了。重新整理當前頁面。
window.navigator:
- navigator.appName 返回獲取當前瀏覽器的名稱。
- navigator.appVersion 返回 獲取當前瀏覽器的版本號。
- navigator.platform 返回 當前計算機的作業系統。
以上屬性已經在逐漸被拋棄了。
一個新的屬性將替代這些屬性。
navigator.userAgent 返回瀏覽器資訊(可用此屬性判斷當前瀏覽器)
判斷當前瀏覽器型別的,示例:
function isBrowser() {
var userAgent = navigator.userAgent;
//微信內建瀏覽器
if(userAgent.match(/MicroMessenger/i) == 'MicroMessenger') {
return "MicroMessenger";
}
//QQ內建瀏覽器
else if(userAgent.match(/QQ/i) == 'QQ') {
return "QQ";
}
//Chrome
else if(userAgent.match(/Chrome/i) == 'Chrome') {
return "Chrome";
}
//Opera
else if(userAgent.match(/Opera/i) == 'Opera') {
return "Opera";
}
//Firefox
else if(userAgent.match(/Firefox/i) == 'Firefox') {
return "Firefox";
}
//Safari
else if(userAgent.match(/Safari/i) == 'Safari') {
return "Safari";
}
//IE
else if(!!window.ActiveXObject || "ActiveXObject" in window) {
return "IE";
}
else {
return "未定義:"+userAgent;
}
}
history:
- history.go(1) 引數可寫任意整數,正數前進,負數後退
- history.back() 後退
- history.forward() 前進
screen: 螢幕
- window.screen.width 返回當前螢幕寬度(解析度值)
- window.screen.height 返回當前螢幕高度(解析度值)
window下的彈框方法:
- alert() 彈出一個提示框
- prompt() 彈出一個輸入框
- confirm() 彈出一個確認框
DOM
DOM(Document Object Model 文件物件模型),DOM定義了表示和修改文件所需的物件、行為和屬性,以及這些物件之間的關係。
獲取DOM節點
- document.getElementById(id名)
- getElementsByTagName(標籤名)
得到的是一個集合(不止一個,是一堆)
- getElementsByName( ) 通過Name值獲取元素,返回值是集合,通常用來獲取有name的input的值
不是所有的標籤都有name值,低版本的瀏覽器會有相容問題
- getElementsByClassName(class名稱)
IE8以下不能用
- document.querySelector () (ES5)>>>> 一旦匹配成功一個元素,就不往後匹配了
- document.querySelectorAll () (ES5)>>>> 強大到超乎想象;匹配到所有滿足的元素, 支援IE8+
屬性獲取和操作
- getAttribute( )獲取元素的屬性值
- setAttribute( )設定元素的屬性
- removeAttribute( )刪除屬性
小編更精心準備了前端知識體系,及JavaScript知識體系,需要的小夥伴關注小編公眾號【小猴子的web成長之路】,回覆知識體系獲取。