JavaScript
- 引入方法
- 輸入輸出
- 變量
-
- var指令
- 資料類型
-
- number
- string
- boolean
- null
- undefined
- array
- object
- symbol(ES6增加的基本資料類型)
- 判斷類型——類型運算符
- 變量提升
- 比較語句
- 循環語句
- 運算符
- 類
-
- 原型 prototype
- 原型鍊 __ proto__
- 繼承
-
- js繼承機制:基于原型的繼承機制
- this 指向
- 函數
-
- 作用域
- 函數提升
- 常見兩種錯誤類型
- 閉包
-
- 應用:點選事件中輸出循環中對應的 i
- 函數節流 throttle
- 函數防抖 debounce
- 事件
-
- 滑鼠相關事件
- 鍵盤相關事件
- 事件監聽
-
- 直接把事件的方法寫在頁面結構上
- 事件綁定:給事件屬性指派.onclick
- addEventListener / removeEventListener
- attachEvent / detachEvent
- 阻止浏覽器預設行為
-
- 讓a标簽失效,不跳轉不重新整理頁面
- 事件流
- 事件冒泡、捕獲
-
- 阻止事件冒泡
- 冒泡事件流
- 捕獲事件流
- 事件委托
-
- 後生成元素的事件綁定問題
- 事件循環
- 任務隊列
-
- 宏任務
- 微任務
- 浏覽器對象模型 BOM
-
- window對象
-
- 視窗尺寸
- 其他方法
-
- 建立窗體
- 窗體控制(不常用)
- 窗體滾動軸控制
- 窗體焦點控制
- window.history 對象
- window.location 對象
- window.navigator 對象
- window.screen 對象
- document 對象
-
- cookie
-
- document.cookie 屬性
- window.frames 對象
- 三種類型的彈出框
-
- window.alert() 警告框
- window.confirm() 确認框
- window.prompt() 提示框
- 折行
- 定時事件( Timing Events)
-
- window.setTimeout()
- window.setInterval()
- 文檔對象模型 DOM
-
- DOM程式設計界面
- 擷取元素的常用方法
- 節點
-
- 類型
- 節點屬性
- 節點的操作(方法)
- 擷取設定樣式
- 動畫
- jQuery
-
- jq底層原理
- 文檔就緒函數
- 擷取jQuery 對象
- 與原生對象轉化
- jQuery 選擇器
- 屬性 / CSS
- 事件
-
- 事件綁定
-
- 後生成元素事件綁定
- 自動擷取焦點
- 滑鼠事件
- jQuery簡單仿寫
- AJAX
-
- AJAX的優點:
- AJAX原理/原生AJAX
-
- 建立 XMLHttpRequest 對象,有相容性問題
- 向伺服器發送請求
-
- get 和 post 差別:
- 伺服器響應
- readyState — >XMLHttpRequest 的狀态
- status 狀态碼:
-
- 完整的HTTP狀态碼如下:
- 優點
- 缺點
- 在浏覽器位址欄裡輸入一個位址回車
- ES6
-
- 作用域
- 聲明
-
- const 指令
- let 指令
- let 與 var 的差別
- 變量的解構指派
- 對象擴充
-
- 對象的屬性和方法的簡寫方式
- 新增的方法
-
- Object.is()
- symbol 增加的基本資料類型
- 箭頭函數 =>
-
- this 指向
- 箭頭函數不能用于構造函數
- 箭頭函數中不能使用arguments(類數組)
- 運算符
-
- rest 運算符
- ... 擴充運算符
- set()
- map()
- Promise
-
- 使用的2個步驟
- Promise 對象的三個狀态
- generator
-
- 特點
- ES7 :async函數 await 異步回調
-
- 文法
- 特點
- defer和async
引入方法
1、body内嵌套:html結構加載完就會執行script
<body>
<script>
</script>
</body>
2、head 内檔案引用:
<script src=""></script>
3、head内直接嵌套:可能取不到下面元素
<head>
<script>
</script>
</head>
解決方法:
window.onload
等頁面中資源加載完才會執行
寫多個window.onload時,後面的會覆寫前面的
<head>
<script>
window.onload = function(){
......
}
</script>
</head>
輸入輸出
輸入
彈框提示輸入:
var 變量名 = prompt();
輸出
1、控制台輸出:
console.log();
2、頁面輸出:
document.write();
3、彈框輸出:
alert();
變量
var指令
JavaScript中的變量用var聲明,是弱類型。變量名區分大小寫,允許包含字母、數字、美元符号($)和下劃線,但第一個字元不允許是數字,不允許包含空格和其他标點符号
資料類型
基本資料類型: number(數值型)、string(字元串)、boolean(布爾值)、null(空)、undefined(未定義)
引用資料類型: array(數組)、object(對象)
number
NaN屬性 是代表非數字值的特殊值,該屬性用于訓示某個值不是數字。
Number.NaN是一個特殊值,說明某些算術運算(如求負數的平方根)的結果不是數字。
用 isNaN() 全局函數——判斷一個值是否是 NaN 值。
string
1、string.length 傳回字元串的長度
2、parseInt:字元串轉整型
var str = "124.2345";
console.log( parseInt(str) );
//輸出結果:124
3、parseFloat:字元串轉浮點型
var str = "124.2345";
console.log( parseFloat(str) );
//輸出結果:124.234
4、charAt():傳回在指定位置的字元。
5、concat():連接配接兩個或多個字元串。
6、indexOf():傳回某個指定的字元串值在字元串中首次出現的位置,找不到傳回-1
7、lastIndexOf():傳回一個指定的字元串值最後出現的位置,在一個字元串中的指定位置從後向前搜尋。
8、replace() :用于在字元串中用一些字元替換另一些字元,或替換一個與正規表達式比對的子串。
9、slice():提取字元串的片斷,并以新的字元串中傳回被提取的部分。
10、split():把一個字元串分割成字元串數組。
11、substr(start,length):在字元串中抽取從 start 下标開始的指定數目的字元。
boolean
取值情況:
1、字元串:非空即為真
2、數值:非0即為真
3、undefined null:假
快速輸出一個字元串變量的布爾值:
null
表示一個“空”的值。
使用情況:
1、取不到id為div2元素的傳回null
2、object 表示為空對象
undefined
表示“未定義”
使用情況:
1、定義變量沒有指派
var a;
console.log(a);
console.log( typeof a);//undefined
2、函數沒有傳回值 預設傳回undefined
function b(){
}
console.log( b() );
3、通路數組越界
4、通路對象沒有的屬性
5、判斷函數參數是否傳遞
array
1、concat:連接配接兩個或更多的數組,并傳回結果。傳回新的數組。
2、join:把數組的所有元素放入一個字元串,元素通過指定的分隔符進行分隔。 傳回字元串。
解決字元串拼接:先将字元串轉化為數組,然後調用join實作字元串拼接
arr.push(str);
return arr.join("");
3、pop:用于删除并傳回數組的最後一個元素。 修改原數組。
4、shift:删除并傳回數組的第一個元素。
5、push:方法可向數組的末尾添加一個或多個元素并傳回新的長度。 修改原數組。
6、reverse:用于颠倒數組中元素的順序,該方法會改變原來的數組。傳回原數組。
7、slice:可從已有的數組中傳回標明的元素。 傳回一個新的數組,包含從 start 到 end (不包括該元素)的 arrayObject 中的元素。
8、sort:用于對數組的元素進行排序。 數組在原數組上進行排序。
//從小到大排序
var a9 = [];
a8.sort(function(a,b){
return a-b;
})
//從大到小排序
var a10 = a8.sort(function(a,b){
return b-a;
})
9、splice:
splice(index,howmany,item,…) 向/從數組中添加/删除項目,然後傳回被删除的項目。
該方法會改變原始數組。
index:必需;整數;規定添加/删除項目的位置,使用負數可從數組結尾處規定位置。
howmany:必需;要删除的項目數量,如果設定為 0,則不會删除項目。
item:可選;向數組添加的新項目。
object
1、取對象的屬性
可變的、動态的 屬性———> [ ]
var person1 = {
name : "zs";
age :10;
}
var person2 = {};
for(key in person1) //循環對象屬性
{
console.log(key); //輸出屬性名
console.log(person1[key]); //輸出屬性值
person2[key] = person1[key];
}
寫死的屬性 —> .
2、克隆對象,傳回一個新對象
var person1 = {
name : "zs",
age :10,
father:{
name:"zxx",
age:40
}
}
function clone (obj){
var result = {};
for(var key in obj){
result[key] = obj[key];
}
return result;
}
var person3 = clone (person1);
person1.name = "lisi";
person1.father.name = "zyy";
console.log(person3);
//person3.name = "zs"
//person3.father.name = "zyy"
如果克隆的屬性是對象——>深克隆
//遞歸調用clone函數進行深克隆
if(typeof obj[key] == "object"){
result[key] = clone (obj[key]);
}else{
result[key] = obj[key];
}
symbol(ES6增加的基本資料類型)
let name = Symbol();
obj[name] = ‘XX';
// 該屬性不會出現在for...in、for...of循環中
判斷類型——類型運算符
判斷資料類型:typeof **
1、typeof “123” —— “string”
2、typeof 123 —— “number”
3、typeof true —— “boolean”
4、typeof undefined —— “undefined”
5、typeof {name:‘zs’} —— “object”
6、typeof null —— “object”
7、typeof [1, 2, 3] —— “object”
8、typeof 函數名 —— “function”
在使用 typeof 運算符時采用引用類型**存儲值會出現一個問題,無論引用的是什麼類型的對象,它都傳回 “object”。
判斷數組和對象
1、Array.isArray() —— 數組(true); 對象(false)
2、instanceof:
具體執行個體化對象 instanceof Array —— 數組(true); 對象(false)
具體執行個體化對象 instanceof Object —— 數組(false);對象(true)
3、具體執行個體化對象object.constructor 傳回構造函數
變量提升
var 定義的變量會發生變量提升 :目前作用域的最上邊聲明變量但是沒有指派
console.log(a);
var a = 5; //報錯 : undefined
//相當于:
var a;
console.log(a);
a=5;
var a = 5;
function fn(){
( var a; )
console.log(a);
var a = 10;
} //輸出:undefined 變量提升
var a = 5;
function fn(){
console.log(a);
a = 10;
} //輸出:5
var a = 5;
function fn(){
var a = 10;
console.log(a);
} //輸出:10
比較語句
if-else
使用 if 來規定要執行的代碼塊,如果指定條件為 true
使用 else 來規定要執行的代碼塊,如果相同的條件為 false
使用 else if 來規定要測試的新條件,如果第一個條件為 false
var condition = false;
if (condition) {
alert("我不會出現!");
}
else {
alert("我會出現!");
}
switch-case
使用 switch 來規定多個被執行的備選代碼塊
var a = '3';
switch(a) {
case 4:
alert("4");
break;
case '3':
alert("3");
break;
case 2:
alert("2");
break;
case 1:
alert("1");
break;
default:
alert('錯誤。。。');
}
//執行結果:彈框顯示3
循環語句
for:多次周遊代碼塊
for/in:周遊對象屬性
while:當指定條件為 true 時循環一段代碼塊
do/while:當指定條件為 true 時循環一段代碼塊
while
while( num > 0 ){
console.log(num);
num--;
}
do-while
do{
console.log(num);
num--;
}while( num > 0);
運算符
指派運算符
作用:把值賦給變量
指派運算符 | 示例 | 等同表達 |
---|---|---|
= | x = y | x = y |
+= | x += y | x = x + y |
-= | x -= y | x = x - y |
*= | x * y | x = x * y |
/= | x /= y | x = x / y |
%= | x %= y | x = x % y |
算數運算符
+、++
1、+
應用:字元串拼接 、 數學運算
x = 7 + 8; //15
y = "7" + 8; //78
z = "Hello" + 7; //Hello7
2、++ (遞加)
c++;
先參與運算 再++
++c;
先++ 再參與運算
-、–(遞減)、*、/、%
能轉成數值型——做運算 ;轉不了輸出NaN
比較運算符
比較運算符 | 描述 |
---|---|
== | 等于 |
=== | 等值等型 |
!= | 不相等 |
!== | 不等值或不等型 |
> | 大于 |
< | 小于 |
>= | 大于或等于 |
<= | 小于或等于 |
? : | 三目運算符 |
邏輯運算符
邏輯運算符 | 描述 |
---|---|
&& | 邏輯與 |
|| | 邏輯或 |
! | 邏輯非 |
類型運算符
類型運算符 | 描述 |
---|---|
typeof | 傳回變量的類型 |
instanceof | 如果對象是對象類型的執行個體傳回 true |
位運算符
位運算符處理 32 位數,該運算中的任何數值運算數都會被轉換為 32 位的數,結果會被轉換回 JavaScript 數
運算符 | 描述 | 例子 | 等同于 | 結果 | 十進制 |
---|---|---|---|---|---|
& | 與 | 5 & 1 | 0101 & 0001 | 0001 | 1 |
|| | 或 | 5 || 1 | 0101 || 0001 | 0101 | 5 |
~ | 非 | ~ 5 | ~0101 | 1010 | 10 |
^ | 異或 | 5 ^ 1 | 0101 ^ 0001 | 0100 | 4 |
<< | 零填充左位移 | 5 << 1 | 0101 << 1 | 1010 | 10 |
>> | 有符号右位移 | 5 >> 1 | 0101 >> 1 | 0010 | 2 |
>>> | 零填充右位移 | 5 >>> 1 | 0101 >>> 1 | 0010 | 2 |
上例使用 4 位無符号的例子。但是 JavaScript 使用 32 位有符号數。
是以,在 JavaScript 中,~ 5 不會傳回 10,而是傳回 -6。
~00000000000000000000000000000101 将傳回 11111111111111111111111111111010
類
類:具有相同屬性和方法的集合。
原型 prototype
構造函數有一個prototype屬性,這個屬性是一個指針,指向它的原型對象
原型對象下的屬性和方法 可以被執行個體化對象所共享
原型下有一個constructor 屬性指向它的構造函數
原型鍊 __ proto__
當從一個對象那裡調取屬性或方法時,如果該對象自身不存在這樣的屬性或方法,就會去自己關聯的prototype對象那裡尋找,
如果prototype沒有,就會去prototype關聯的前輩prototype那裡尋找,
如果再沒有,則繼續查找Prototype.Prototype引用的對象,以此類推,
直到Prototype. … .Prototype為undefined(Object的Prototype就是undefined),進而形成了原型鍊
繼承
調用父類.call(this, ) 繼承屬性:
function Coder(name, age) {
Person.call(this, name, age);
}
繼承父類的方法:
Coder.Prototype = new Person();
//需要手動把 Coder 的原型對象下的 constructor屬性 指向Coder
Coder.prototype.constructor = Coder;
js繼承機制:基于原型的繼承機制
舉個例子來說:假設有一個ClassA和ClassB,ClassB想繼承ClassA
首先要在ClassA的構造函數裡定義屬性,在ClassA的原型裡定義方法:
function ClassA() {
this.color = sColor;
}
ClassA.prototype.sayColor = function () {
alert(this.color);
};
然後在ClassB的構造函數中使用ClassA.call(this)來繼承ClassA中的屬性:
function ClassB() {
ClassA.call(this);
}
再用ClassB.prototype等于ClassA的一個執行個體對象來繼承ClassA中的方法:
this 指向
改變this 指向的方法:call()、apply()、bind()
差別:
1、apply,call 是直接執行函數調用,bind是綁定,執行需要再次調用.
2、apply和call 的差別是apply接受數組作為參數,而call是接受逗号分隔的無限多個參數清單,call bind —> ,,,,;apply —> (this),[,,,,(其它參數)]
3、call(obj,1,2,3,) 從第二個參數開始有多個參數,用來代表函數的實參 apply(obj,[1,2,3]) 第二個參數是一個數組,數組中的每一個元素對應一個實參 bind(obj,1,2,3,)();
// this指向的幾種情況:
function a() {
console.log(this);
}
a(); //Window
setTimeout(function(){
console.log(this);
},10); //Window
var aLi = document.getElementsByTagName('li');
for (var i = 0; i < aLi.length; i++) {
aLi[i].onclick = function(){
console.log(this);
}
} //<li>111</li> <li>222</li> <li>333</li>
for (var i = 0; i < aLi.length; i++) {
aLi[i].onclick = function(){
setTimeout(function(){
console.log(this);
},500);
}
} //Window Window Window
for (var i = 0; i < aLi.length; i++) {
aLi[i].onclick = function(){
setTimeout((function(){
console.log(this);
}).bind(this),500);
}
} //<li>111</li> <li>222</li> <li>333</li>
// 構造函數 this指的是new出來的執行個體化對象
function Person(name,age){
this.name = name,
this.age = age,
this.say = function(){
//console.log( this.name +"Hehe");
console.log(this);
}
}
var p1 = new Person("zs",20);
p1.say();
//Person {age:20, name: "zs", say: f()}
var obj = {
name:'zs',
age:20,
say:function(msg,mag1,msg2){
console.log(this,msg,mag1,msg2);
}
}
obj.say();
//{name: "zs", age:20, say: f} undefined undefined undefined
obj.say("我是obj","哈哈","呵呵");
//{name: "zs", age:20, say: f} "我是obj","哈哈","呵呵"
//改變this指向
var obj2 = {
name:'xiaowu'
}
obj.say.call(obj2,"我是小吳","哈哈","呵呵");
//{name: "xoapwu"} "我是小吳","哈哈","呵呵"
obj.say.apply(obj2,["我是小吳","哈哈","呵呵"]);
//{name: "xoapwu"} "我是小吳","哈哈","呵呵"
obj.say.bind(obj2); //僅改變this指向沒有調用
obj.say.bind(obj2,"我是小吳","哈哈","呵呵")();
//{name: "xoapwu"} "我是小吳","哈哈","呵呵"
函數
1、JavaScript 函數是被設計為執行特定任務的代碼塊,會在某代碼調用它時被執行。
2、使用函數的優點:
能夠對代碼進行複用:隻要定義一次代碼,就可以多次使用它
能夠多次向同一函數傳遞不同的參數,以産生不同的結果
作用域
全局作用域、函數作用域
優先級:在函數作用域中,局部變量的優先級比同名的全局變量高。
**隐藏全局變量:**如果給一個局部變量或函數的參數聲明的名字與某個全局變量的名字相同,那麼就會有效地隐藏這個全局變量。
//示例:
var a = 3;
function fn(){
var b= 10; // 局部作用域 局部變量
c = 20; // 不寫 var 定義到全局變量
console.log(c +"fn"); //10fn
console.log(a);//3
}
fn();
console.log(c);//20
console.log(b);//undefined
函數提升
console.log( add(2,3) );
function add(x,y){
return x+y;
}
常見兩種錯誤類型
1、is not defined
console.log( add(2,3) );
add = function(x,y){
return x+y;
}
2、is not a function
console.log( add(2,3) );
var add = function(x,y){
return x+y;
}
閉包
含義:外部函數中聲明一個内部函數,内部函數引用外部函數中的局部變量,這樣當外部函數調用完畢後,外部函數中的變量不釋放,可以一直使用。
好處:變量長期駐紮在記憶體中,避免全局變量的污染(代碼子產品化),允許私有成員的存在
缺點:可能會造成記憶體洩露
function a(){
var x = 1;
function b(){
console.log(x);
}
return b;//将内部函數暴露出去
}
var bFn = a();
bFn(); //輸出結果:1
應用:點選事件中輸出循環中對應的 i
var aLi = document.getElementsByTagName("li");
for(var i=0;i<aLi.length;i++){
//函數的立即調用(聲明就調用) —— (function(){......})();
(function(i)
{
aLi[i].onclick = function()
{
console.log(i);
}
}
)(i)
}
函數節流 throttle
一個函數執行一次後,隻有大于設定的執行周期才執行第二次
有個需要頻繁觸發的函數
出于優化性能角度,在規定時間内,隻讓函數觸發第一次生效,後面不生效
用到的知識點:閉包 、this指向
function throttle(fn, delay) {
var startTime = 0;
return function() {
var nowTime = Date.now();
if (nowTime - startTime > delay) {
//fn();
fn.call(this);
startTime = nowTime;
}
}
}
document.onmousemove = throttle(function(){
console.log(Date.now());
console.log(this); // fn()——Window fn.call(this)——document
}, 1000);
函數防抖 debounce
一個需要頻繁觸發的函數,在規定時間内隻讓最後一次生效,前面的不生效
function debounce(fn, delay) {
var timer = null;
return function(){
clearTimeout(timer);
timer = setTimeout(function(){
//fn();
fn.apply(this);
}.bind(this), delay);
}
/*
//箭頭函數 ES6
return function(){
clearTimeout(timer);
timer = setTimeout(() => {
//fn();
fn.apply(this);
}, delay);
}
*/
}
var oBtn = document.getElementById('btn');
oBtn.onclick = debounce(function(){
console.log(Date.now());
console.log(this);
//fn()——Window {fn.apply(this)}.bind(this)
// 箭頭函數——<button id="btn">click</button>
}, 1000);
事件
三要素:事件源 、事件處理函數 、事件
滑鼠相關事件
e.clientX:擷取滑鼠點選時距離可視區(螢幕)左邊的距離 (Integer)
e.clientY:擷取滑鼠點選時距離螢幕上邊的距離 (Integer)
鍵盤相關事件
altKey——Boolean
keyCode——Integer
事件監聽
直接把事件的方法寫在頁面結構上
function eventfun(){
//console.log(this);
}
這裡涉及到一個this作用域的問題,eventfun在這裡是一個全局函數, 對象是[object Window],this指向的是window。要解決this作用域的問題,可以使用為全局函數添加event變量的方法,在頁面結構上将this對象作為參數傳遞到函數内部使用
function eventfun2(eve){//在這裡把事件對象作為參數傳遞到全局方法裡
eve.name="alex";
window.name="robin";
console.log(this);//[object Window]
console.log(eve);// [object HTMLInputElement]
console.log(this.name);// robin
console.log(eve.name);// alexvar
self=eve;
console.log(this.name);//robin
console.log(self.name);//alex
alert(window.name);
alert(self.name);
}
事件綁定:給事件屬性指派.onclick
局限性:隻能為事件綁定一個方法,如果綁定多個就會以後一個方法為準
使用這種為事件屬性指派的方法,this的指針會指向window對象,而不是被事件對象,是以這種方法是引用
HTMLElementobject.onclick = fucntion(){
fun1();
fun2();
fun3();
console.log(this);//window.object
}
function dosomething(){
//js code
}
HTMLElementobject.onclick = dosomething;
//使用這種為事件對象屬性指派的形式,this指針指向事件執行對象
console.log(this);//htmlElementObject
addEventListener / removeEventListener
obj.addEventListener(evtype,fn,useCapture):
W3C提供的添加事件處理函數的方法。
obj是要添加事件的對象;evtype是事件類型,不帶on字首;fn是事件處理函數;如果useCapture是true,則事件處理函數在捕獲階段被執行,否則在冒泡階段執行。
obj.removeEventListener(evtype,fn,useCapture):
W3C提供的删除事件處理函數的方法
attachEvent / detachEvent
obj.attachEvent(evtype,fn):
IE提供的添加事件處理函數的方法。
obj是要添加事件的對象,evtype是事件類型,帶on字首,fn是事件處理函數,IE不支援事件捕獲
obj.detachEvent(evtype,fn,):
IE提供的删除事件處理函數的方法,evtype包含on字首
阻止浏覽器預設行為
所有浏覽器都支援 :return false;
标準浏覽器下:e.preventDefault();
IE浏覽器下 :e.returnValue = false;
讓a标簽失效,不跳轉不重新整理頁面
href:
<a href="javascript:void(0)"></a>
<a href="javascript:;"></a>
css: 在css中添加以下樣式,應用到a标簽中
.disableCss{
pointer-events:none;
color:#afafaf;
cursor:default
}
jQuery:
1、removeAtttr:
即可使a标簽點選上去,完全沒有效果
在a标簽加屬性
style="cursor:pointer"
,移動上去變成手指形狀
2、使用jQuery來将a标簽置為不可用的方法:
if(boolean){
$("a").attr("disabled", true);
//僅僅為其添加disabled屬性隻能将其置灰,點選的時候依然會進行跳轉
$("a").click(function(){});
}
事件流
三階段:
1、事件捕獲
2、事件目标
3、事件冒泡
iscaptrue為true代表捕獲階段;為false是冒泡階段;預設是冒泡
事件冒泡、捕獲
冒泡:從裡往外,事件從裡往外發生,點選子元素先執行子元素,再執行父元素
捕獲:從外到裡,事件從裡往外發生,點選子元素先執行父元素,再執行子元素
捕獲與冒泡同時存在:先捕獲再冒泡,先從外到裡,再從裡到外
示例
阻止事件冒泡
标準浏覽器:e.stopPropagation()
IE:e.cancelBubble = true;
冒泡事件流
當事件在某一DOM元素被觸發時,例如使用者在客戶名位元組點上點選滑鼠,事件将跟随着該節點繼承自的各個父節點冒泡穿過整個的DOM節點層次,直到它遇到依附有該事件類型處理器的節點,此時,該事件是onclick事件。在冒泡過程中的任何時候都可以終止事件的冒泡,在遵從W3C标準的浏覽器裡可以通過調用事件對象上的stopPropagation()方法,在Internet Explorer裡可以通過設定事件對象的cancelBubble屬性為true。如果不停止事件的傳播,事件将一直通過DOM冒泡直至到達文檔根。
捕獲事件流
事件的處理将從DOM層次的根開始,而不是從觸發事件的目标元素開始,事件被從目标元素的所有祖先元素依次往下傳遞。在這個過程中,事件會被從文檔根到事件目标元素之間各個繼承派生的元素所捕獲,如果事件監聽器在被注冊時設定了useCapture屬性為true,那麼它們可以被分派給這期間的任何元素以對事件做出處理;否則,事件會被接着傳遞給派生元素路徑上的下一進制素,直至目标元素。事件到達目标元素後,它會接着通過DOM節點再進行冒泡。
事件委托
後生成元素的事件綁定問題
為解決後生成元素的事件綁定問題:把事件綁定在父元素身上,點選子元素時,通過事件冒泡到父元素身上,判斷事件源判定是否是要綁定的元素
//以點選事件為例
oBtn.onclick = function()
{
var oLi = document.createElement('li');
oLi.innerHTML = Math.random();
oUl.appendChild(oLi);
}
oUl.onclick = function(e)
{
e = e || window.event; //相容問題
var target = e.target;
if(target.tagName == "LI" )
{
console.log(target.innerHTML);
}
}
事件循環
1、所有同步任務都在主線程上執行,形成一個執行棧。
2、主線程之外,還存在一個“任務隊列”。隻要異步任務有了運作結果,就在“任務隊列中放置一個事件”。
3、一旦“執行棧”中的所有同步任務執行完畢,系統就會讀取“任務隊列”,看看裡面有哪些事件,那些對應的異步任務,于是結束等待狀态,進入執行棧,開始執行。
4、主線程不斷重複上面的第三步。
任務隊列
js是單線程
同步任務:在主線程上排隊執行的任務,隻有前一個任務完畢,才能執行後一個任務。
異步任務:不進入主線程,而進入“任務隊列”的任務,隻有“任務隊列”通知主線程,某個異步任務可以執行了,該任務才會進入主線程執行。
宏任務
1、包括整體代碼 script,setTimeout,setInterval
2、宏任務所處的隊列就是宏任務隊列
3、宏任務隊列可以有多個
微任務
1、new Promise(正常執行)Promise.then(回調),process.nextTick(node裡的)
2、微任務所處的隊列就是微任務隊列
3、隻有一個微任務隊列
4、在上一個宏任務隊列執行完畢後,如果有微任務隊列就會執行微任務隊列中的所有微任務
5、當宏任務隊列中的人物執行完後,檢視是否有微任務,再執行宏任務
浏覽器對象模型 BOM
1、什麼是BOM
BOM是Browser Object Model的縮寫,浏覽器對象模型
BOM提供了獨立于内容而與浏覽器視窗進行互動的對象
由于BOM主要用于管理視窗與視窗之間的通訊,是以其核心對象是window
BOM由一系列相關的對象構成,并且每個對象都提供了很多方法與屬性
2、BOM的作用
BOM提供了一些通路視窗對象的一些方法,我們可以用它來移動視窗位置,改變視窗大小,打開新視窗和關閉視窗,彈出對話框,進行導航以及擷取客戶的一些資訊如:浏覽器品牌版本,螢幕分辨率。
BOM最強大的功能是它提供了一個通路HTML頁面的一入口——document對象,以使得我們可以通過這個入口來使用DOM的強大功能!!!
window對象
1、window對象是BOM的頂層(核心)對象,所有對象都是通過它延伸出來的,也可以稱為window的子對象。
2、由于window是頂層對象,是以調用它的子對象時可以不顯示的指明window對象,
如:document.write(“BOM”); 即:window.document.write(“BOM”);
3、window對象是BOM中所有對象的核心。window對象表示整個浏覽器視窗,但不必表示其中包含的内容。此外,window還可用于移動或調整它表示的浏覽器的大小,或者對它産生其他影響。
4、所有全局 JavaScript 對象,函數和變量自動成為 window 對象的成員:全局變量是 window 對象的屬性;全局函數是 window 對象的方法。
視窗尺寸
兩個屬性可用用于确定浏覽器視窗的尺寸:
window.innerHeight - 浏覽器視窗的内高度(以像素計)
window.innerWidth - 浏覽器視窗的内寬度(以像素計)
//顯示浏覽器視窗的高度和寬度:(不包括工具欄和滾動條)
var w = window.innerWidth|| document.documentElement.clientWidth|| document.body.clientWidth;
var h = window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight;
其他方法
建立窗體
window.open():打開(彈出)一個新的窗體,window.open(url, name, features, replace);
url – 要載入窗體的URL
name – 建立窗體的名稱(目标,将在a 标簽的target屬性中用到,當與已有窗體名稱相同時将覆寫窗體内容).open函數預設的打開窗體的方式為target的_blank彈出方式,是以頁面都将以彈出的方式打開
features – 代表窗體特性的字元串,字元串中每個特性使用逗号分隔
replace – 一個布爾值,說明新載入的頁面是否替換目前載入的頁面,此參數通常不用指定
window.close() - 關閉目前視窗
window.moveTo() -移動目前視窗
window.resizeTo() -重新調整目前視窗
窗體控制(不常用)
moveBy(x,y):從目前位置水準移動窗體x個像素,垂直移動窗體y個像素,x為負數,将向左移動窗體,y為負數,将向上移動窗體。
moveTo(x,y):移動窗體左上角到相對于螢幕左上角的(x,y)點,當使用負數做為參數時會把窗體移出螢幕的可視區域。
resizeBy(w,h):相對窗體目前的大小,寬度調整w個像素,高度調整h個像素。如果參數為負值,将縮小窗體,反之擴大窗體。
resizeTo(w,h):把窗體寬度調整為w個像素,高度調整為h個像素。
窗體滾動軸控制
scrollTo(x,y):在窗體中如果有滾動條,将橫向滾動條移動到相對于窗體寬度為x個像素的位置,将縱向滾動條移動到相對于窗體高度為y個像素的位置。
scrollBy(x,y):如果有滾動條,将橫向滾動條移動到相對于目前橫向滾動條的x個像素的位置(就是向左移動x像素),将縱向滾動條移動到相對于目前縱向滾動條高度為y個像素的位置(就是向下移動y像素)。
窗體焦點控制
focus():使窗體或控件擷取焦點
blur():使窗體或控件失去焦點
window.history 對象
window.history 對象:包含浏覽器曆史
1、屬性
屬性 | 描述 |
---|---|
length | 傳回浏覽器曆史清單中的 URL 數量 |
2、方法
history.back() - 加載曆史清單中前一個 URL,等同于在浏覽器點選後退按鈕
history.forward() - 加載曆史清單中下一個 URL,等同于在浏覽器中點選前進按鈕
history.go(num) - 加載 history 清單中的某個具體頁面
num正數:下num個曆史記錄
num負數:上num個曆史記錄
window.location 對象
與位址欄有關
1、屬性
屬性 | 描述 |
---|---|
hash | 設定或傳回從井号 (#) 開始的 URL(錨),和id配合跳轉 |
host | 設定或傳回主機名和目前 URL 的端口号 |
hostname | 設定或傳回目前 URL 的主機名 |
href | 設定或傳回完整的 URL |
pathname | 設定或傳回目前 URL 的路徑部分 |
port | 設定或傳回目前 URL 的端口号 |
protocol | 設定或傳回目前 URL 的協定 |
search | 設定或傳回從問号 (?) 開始的 URL(查詢部分) |
window.navigator 對象
window.navigator 對象:包含有關通路者的資訊
屬性 | 描述 |
---|---|
userAgent | 傳回由浏覽器發送到伺服器的使用者代理報頭(user-agent header) |
cookieEnabled | 如果 cookie 已啟用,傳回 true;否則傳回 false |
appName | 傳回浏覽器的應用程式名稱 |
appCodeName | 傳回浏覽器的應用程式代碼名稱 |
product | 傳回浏覽器引擎的産品名稱 |
appVersion | 傳回有關浏覽器的版本資訊 |
platform | 傳回浏覽器平台(作業系統) |
language | 傳回浏覽器語言 |
onLine | 假如浏覽器線上,傳回 true |
javaEnabled() 方法:如果 Java 已啟用,傳回 true
window.screen 對象
window.screen 對象:包含使用者螢幕的資訊
1、屬性
屬性 | 描述 |
---|---|
screen.width | 傳回以像素計的通路者螢幕寬度 |
screen.height | 傳回以像素計的通路者螢幕的高度 |
screen.availWidth | 傳回通路者螢幕的寬度,以像素計,減去諸如視窗工具條之類的界面特征 |
screen.availHeight | 傳回通路者螢幕的高度,以像素計,減去諸如視窗工具條之類的界面特征 |
screen.colorDepth | 傳回用于顯示一種顔色的比特數 |
screen.pixelDepth | 傳回螢幕的像素深度 |
document 對象
document對象是BOM的一部分,同時也是HTML DOM的HTMLDocument對象的一種表現形式,反過來說,它也是XML DOM Document對象。
JavaScript中的大部分處理DOM的過程都利用document對象,是以我們通路文檔需要使用BOM提供的這個入口
cookie
Cookie 是在您的計算機上存儲在小的文本檔案中的資料。當 web 伺服器向浏覽器發送網頁後,連接配接被關閉,伺服器會忘記使用者的一切。Cookie 是為了解決“如何記住使用者資訊”而發明的:當使用者通路網頁時,他的名字可以存儲在 cookie 中,下次使用者通路該頁面時,cookie 會“記住”他的名字。
Cookie 儲存在名稱值對中,當浏覽器從伺服器請求一個網頁時,将屬于該頁的 cookie 添加到該請求中。這樣伺服器就獲得了必要的資料來“記住”使用者的資訊。
要求:浏覽器不能關閉本地 cookie 支援
document.cookie 屬性
1、建立 cookie
您還可以添加有效日期(UTC 時間)。預設情況下,在浏覽器關閉時會删除 cookie:
通過 path 參數,您可以告訴浏覽器 cookie 屬于什麼路徑。預設情況下,cookie 屬于目前頁。
2、讀取 cookie
document.cookie 會在一條字元串中傳回所有 cookie,比如:cookie1=value; cookie2=value; cookie3=value;
3、改變cookie
舊 cookie 被覆寫:
4、删除 cookie
删除 cookie 時不必指定 cookie 值:直接把 expires 參數設定為過去的日期即可:
要求:應該定義 cookie 路徑以確定删除正确的 cookie,如果不指定路徑,一些浏覽器不會讓你删除 cookie。
window.frames 對象
windows.frames對象:傳回視窗中所有命名的架構。
該集合是 Window 對象的數組,每個 Window 對象在視窗中含有一個架構或 。屬性 frames.length 存放數組 frames[] 中含有的元素個數。
注意:frames[] 數組中引用的架構可能還包括架構,它們自己也具有 frames[] 數組。
三種類型的彈出框
window.alert() 警告框
如果要確定資訊傳遞給使用者,通常會使用警告框。
當警告框彈出時,使用者将需要單擊“确定”來繼續
window.confirm() 确認框
如果您希望使用者驗證或接受某個東西,則通常使用“确認”框。
當确認框彈出時,使用者将不得不單擊“确定”或“取消”來繼續進行。
如果使用者單擊“确定”,該框傳回 true。如果使用者單擊“取消”,該框傳回 false。
window.prompt() 提示框
如果您希望使用者在進入頁面前輸入值,通常會使用提示框。
當提示框彈出時,使用者将不得不輸入值後單擊“确定”或點選“取消”來繼續進行。
如果使用者單擊“确定”,該框傳回輸入值。如果使用者單擊“取消”,該框傳回 NULL。
折行
如需在彈出框中顯示折行,請在反斜杠後面加一個字元 n
定時事件( Timing Events)
window 對象允許以指定的時間間隔執行代碼,這些時間間隔稱為定時事件。
通過 JavaScript 使用的有兩個關鍵的方法:
1、
setTimeout(function, milliseconds)
:在等待指定的毫秒數後執行函數。
2、
setInterval(function, milliseconds)
:等同于 setTimeout(),但持續重複執行該函數。
setTimeout() 和 setInterval() 都屬于 HTML DOM Window 對象的方法
window.setTimeout()
暫停指定的毫秒數後執行指定的代碼
第一個參數是要執行的函數,第二個參數訓示執行之前的毫秒數。
clearTimeout() 方法停止執行setTimeout() 中規定的函數
window.setInterval()
在每個給定的時間間隔重複給定的函數
第一個參數是要執行的函數(回調函數),第二個參數每個執行之間的時間間隔的長度。
clearInterval() 方法停止 setInterval() 方法中指定的函數的執行
文檔對象模型 DOM
Document Object Model (DOM)是HTML和XML文檔的程式設計接口。它提供了上述文檔的一種結構化表示,同時也定義了一種通過程式來改變文檔結構,風格,以及内容的方式。DOM用一組結構化的節點以及對象來表示文檔。本質上就是将網頁和腳本語言以及程式設計語言連接配接起來。
一個網頁是一個文檔。這個文檔可以被顯示在浏覽器視窗中,也可以以html源碼的形式顯示。這兩中情況中,文檔都是同一個。DOM提供了另一種方式來表示,存儲,操作這個文檔。DOM是網頁的一種完全的面向對象的表示方法,可以通過腳本語言(比如說JavaScript)來改變。
W3C DOM标準形成了當今大多數浏覽器的DOM基礎。許多浏覽器提供超出W3C标準的擴充,是以當用在可能被擁有不同DOM的各種浏覽器使用的場合時 一定要多加注意
DOM标準主要要為:微軟DOM與W3C DOM,一般IE實作的是微軟DOM,而其它浏覽器則不同程度的實際了W3C DOM
DOM程式設計界面
在 DOM 中,所有 HTML 元素都被定義為對象。
程式設計界面是每個對象的屬性和方法。
屬性:能夠擷取或設定的值(就比如改變 HTML 元素的内容)
.innerHTML: 設定或傳回表格行的開始和結束标簽之間的 HTML。
oDiv1.innerHtml = "<h2>ha</h2>";
//輸出結果:ha (以h2樣式顯示)
.innerText: 不能識别HTML,隻能輸出“ ”中的文本内容
oDiv1.innerText = "<h2>ha</h2>";
//輸出結果:<h2>ha</h2>
方法:能夠完成的動作(比如添加或删除 HTML 元素)
擷取元素的常用方法
1、document.getElementById 通過id 擷取元素 傳回查找的dom對象
在一個文檔中id必須是唯一的,getElementById方法隻會傳回一個元素
var p1 = document.getElementById("p1");
//擷取ID為p1的那個元素
2、document.getElementsByTagName 通過标簽 擷取元素 傳回數組 數組中存放的是dom 對象 沒取到時傳回空數組,因為頁面中标簽相同的元素很多,是以即使頁面中隻有一個需要擷取的元素getElementsByTagName也會傳回一個集合
var allP = document.getElementsByTagName("p");
//擷取文檔中所有p标簽
3、document.getElementsByClassName 通過class名擷取元素 傳回數組 數組中存放的是dom 對象 dom3版本 ie6不支援該方法
相容——封裝函數:
function getElementsByClass(clsName)
{
// 取到頁面中所有的元素
var result = [];
var allELe = document.getElementsByTagName("*");
for(var i=0; i<allELe.length; i++){
// class 是保留字 用className取到class名
//"a b" == "a"
//"a b c" == ["a","b","c"] 通過split方法将字元串分隔成數組
var arr = allELe[i].className.split(" "); //["a","b"]
for(var k=0; k<arr.length; k++){
//判斷class名==傳進來的clsName push到數組
if(arr[k] == clsName){
result.push(allELe[i]);
}
}
}
return result;
}
var a2 = getElementsByClass('a');
4、document.getElementsByName 傳回數組 表單元素 name屬性 背景使用
節點
類型
共12種節點類型:
Node.ELEMENT_NODE (1) 【元素節點】
Node.ATTRIBUTE_NODE (2) 【屬性節點 (id)】
Node.TEXT_NODE (3)【文本節點】
Node.CDATA_SECTION_NODE (4)
Node.ENTITY_REFERENCE_NODE (5)
Node.ENTITY_NODE (6)
Node.PROCESSING_INSTRUCTION_NODE (7)
Node.COMMENT_NODE (8) 【注釋節點】
Node.DOCUMENT_NODE (9)
Node.DOCUMENT_TYPE_NODE (10)
Node.DOCUMENT_FRAGMENT_NODE (11)
Node.NOTATION_NODE (12)
節點屬性
1、nodeType
傳回值類型: Number
節點類型:oDiv.firstChild.nodeType
元素節點———— 1
屬性節點———— 2
文本節點———— 3
注釋節點———— 8
2、nodeName
傳回值類型:String
節點的名字:根據節點的類型而定義
元素節點傳回tagName,
文本節點傳回#text,
屬性節點傳回屬性名
3、nextSibling
傳回值類型:node
指向後一個兄弟節點;如果這個節點就是最後一個兄弟節點,那麼該值為null
.extSibling在IE6中可以找到下一個兄弟, 在标準浏覽器下會找到回車+空格
.nextElementSibling —— dom3的文法 存在相容性問題 IE6以下不相容
4、previousSibling
傳回值類型:node
指向前一個兄弟節點;如果這個節點就是第一個兄弟節點,那麼該值為null
previousElementSibling —— dom3
5、firstChild
傳回值類型:node
指向在childNodes清單中的第一個節點 firstElementChild
6、lastChild
傳回值類型:node
指向在childNodes清單中的最後一個節點 lastElementChild
7、children
所有浏覽器都支援
節點的操作(方法)
1、createElement()
2、appendChild(node):将node添加到childNodes的末尾
3、removeChild(node):從childNodes中删除node
4、replaceChild (newnode,oldnode):将childNodes中的oldnode替換成newnode
5、insertBefore (newnode,refnode):在childNodes中的refnode之前插入newnode
6、cloneNode(true):使用參數true表示克隆節點時包含子節點
7、.setAttribute(“屬性名”,“屬性值”) :設定屬性
8、.getAttribute(“屬性名”):擷取屬性(擷取屬性名對應的屬性值)
擷取設定樣式
1、可以擷取也可以設定,擷取到的是内聯樣式
elem.style.width
2、隻能擷取,不能設定
取到包括width(内容)+padding+border不包括margin
elem.offsetWidth
3、最近已定位的祖先元素
elem.offsetParent
4、相對于最近已定位的祖先元素,如果沒有相對于 body
動畫
animate(oDiv,{
width:500
},function(){
alert("哈哈");
})
jQuery
jQuery 是一個高效、精簡并且功能豐富的 JavaScript 工具庫。
jQuery教程
jq底層原理
1、 $() 是一個函數, 傳回值jq對象
2、 jQuery是一個類,在這個類的原形下有許多jq自定義的方法.每次調用$傳回一個新的jq對象,同時在$函數中根據傳入參數的類型、函數或者字元串。
3、把選中的元素存在數組中,周遊這個數組,取出每個元素進行dom操作。真正的DOM中查找周遊的操作是在構造函數裡面進行的,将查到的元素存到this.elements[i]數組裡,對數組的元素進行周遊,進行綁定事件。
4、在每一個方法中:
return this
,this就是在$函數中傳回的jq對象。
文檔就緒函數
等頁面的(HTML)結構加載執行
執行比 window.onload 快
寫多個時不會發生後面的覆寫前面的
$(document).ready(function(){
$("#div1").css("background","green");
})
//存在簡寫方式
$(function(){
$("#div1").css("background","green");
})
擷取jQuery 對象
沒有原生對象(.style.background)的方法,使用.css()方法
$div = $('#div1');
$div.css('background','#ff0036');
與原生對象轉化
1、把jQuery對象 轉化成原生對象
$div.get(0);
$div[0];
2、把原生對象轉化成jQuery對象
修改HTML内容:
jQuery 選擇器
1、後代選擇器
2、群組選擇器
屬性 / CSS
1、屬性
.attr()——設定普通屬性
.prop()——指定某些元素特有的屬性
.removeAttr()
2、CSS
.addClass()
事件
事件綁定
後生成元素事件綁定
$("ul").on("click","li",function (){
console.log( $(this).html() );
})
自動擷取焦點
$("#test").on("focus",function(){
$(this).css("background","pink");
})
$("#text").trigger("focus");
//跟滑鼠點上去情況一樣
//triggerHandler——隻會執行處理函數
滑鼠事件
mouseenter——不支援冒泡
mouseover——支援冒泡
jQuery簡單仿寫
function getStyle(elem, prop) {//樣式
if (elem.currentStyle) {
return elem.currentStyle[prop];
} else if (getComputedStyle) {
return getComputedStyle(elem, false)[prop];
} else {
return elem.style[prop];
}
}
function addEvent(elem, type, handler) {//事件
if (elem.addEventListener) {
elem.addEventListener(type, handler, false);
} else if (elem.attachEvent) {
elem.attachEvent('on' + type, handler)
} else {
elem['on' + type] = handler;
}
}
function $(args) {
return new MyJQuery(args);
}
function MyJQuery(args) {
this.elements = [];
switch (typeof args) {//判斷傳值類型
case 'function':
addEvent(window, 'load', args);
break;
case 'string':
var firstLetter = args.charAt(0);
switch (firstLetter) {
case '#': //#xxx
this.elements.push(document.getElementById(args.substring(1)));
break;
case '.':
this.elements = document.getElementsByClassName(args.substring(1));
break;
default:
this.elements = document.getElementsByTagName(args);
}
break;
case 'object':
this.elements.push(args);
break;
}
}
MyJQuery.prototype.addClass = function (clsName) {
for (var i = 0; i < this.elements.length; i++) {
var re = new RegExp('\\b' + clsName + '\\b', 'g');//邊界,取出原來的 classname
if (!re.test(this.elements[i].className)) {
this.elements[i].className += ' ' + clsName;
this.elements[i].className = MyJQuery.trim(this.elements[i].className);
//去空格
}
}
return this;
};
MyJQuery.prototype.width = function (length) {
if (length) {
for (var i = 0; i < this.elements.length; i++) {
this.elements[i].style.width = length + 'px';
}
return this;
}
return getStyle(this.elements[0], 'width');
};
MyJQuery.prototype.click = function (fn) {
for (var i = 0; i < this.elements.length; i++) {
addEvent(this.elements[i], 'click', fn);
}
return getStyle(this.elements[0], 'width');
};
MyJQuery.prototype.click = function (fn) {
for (var i = 0; i < this.elements.length; i++) {
addEvent(this.elements[i], 'click', fn);
}
return this;
};
MyJQuery.prototype.on = function (type, selector, fn) {
,click,'.l',function(){}
if (typeof selector == 'string') {
for(var i=0; i<this.elements.length; i++){
addEvent(this.elements[i], type, function (e) {
e = e || window.event;
var target = e.target || e.srcElement;
switch (selector.charAt(0)){
case '#':
break;
case '.':
if(target.className == selector.substr(1)){
fn.apply(target);//改變this指向,指向真實綁定的元素
}
break;
default: break;
}
});
}
} else {
for (var i = 0; i < this.elements.length; i++) {
addEvent(this.elements[i], type, fn);
}
}
return this;
};
MyJQuery.prototype.siblings = function (selector) {
var result = [];
for (var i = 0; i < this.elements.length; i++) {
var childs = this.elements[i].parentNode.children;
for(var j=0; j<childs.length; j++){
switch (selector.charAt(0)){
case '#':
break;
case '.':
if(childs[j].className == selector.substr(1)){
if(childs[j] != this.elements[i] && result.indexOf(childs[j]) == -1){
result.push(childs[j]);
}
}
break;
default: break;
}
}
}
return result;
};
MyJQuery.prototype.css = function (prop, value) {
if(value){
for (var i = 0; i < this.elements.length; i++) {
this.elements[i].style[prop] = value;
}
} else {
if (typeof prop == 'string'){
return getStyle(this.elements[0], prop);
} else if(typeof prop == 'object'){
for(var p in prop){ //p:background-color=>backgroundColor
p = p.replace(/\-[a-z]/g, function (word) {
return word.substring(1).toUpperCase();
}
);
for (var i = 0; i < this.elements.length; i++) {
this.elements[i].style[p] = prop[p];
}
}
}
}
};
MyJQuery.trim = function (str) {
var re = /^\s+|\s+$/g; // _abc_ return str.replace(re, '');
};
AJAX
AJAX的優點:
<1>.無重新整理更新資料:在無需重新加載整個網頁的情況下,能夠更新部分網頁的技術。
<2>.異步與伺服器通信:用戶端與伺服器端異步的通信的技術
AJAX原理/原生AJAX
建立 XMLHttpRequest 對象,有相容性問題
var xmlhttp;
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
向伺服器發送請求
XMLHttpRequest 對象的 open() 和 send() 方法:
① open(method,url,async):
method: 請求的類型:GET 或 POST
url: 檔案在伺服器上的位置
async: true(異步)或 false(同步)
② send(string):僅用于 POST 請求
get 請求方式: url 是否異步
xmlhttp.open("GET", "test1.txt?name=zs", true);
xmlhttp.send();
post 請求方式 :請求位址 url 是否異步
xmlhttp.open("POST","ajax_test.asp",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("fname=Bill&lname=Gates");
get 和 post 差別:
get — 請求 / post — 送出
get 資料量小(IE:2-4k) / post 向伺服器發送大量資料(POST 沒有資料量限制)
get 放在位址欄,不安全 / post 放在包體裡,相對安全
get 可以緩存 / post 無法使用緩存檔案(更新伺服器上的檔案或資料庫)
get 一般用于擷取資料 / post 一般用于表單送出
在發送包含未知字元的使用者輸入時,POST 比 GET 更穩定也更可靠
伺服器響應
XMLHttpRequest 對象的 responseText屬性 :獲得字元串形式的響應資料
或 responseXML屬性:獲得XML形式的響應資料。
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
console.log(xmlhttp.responseText); //取到傳回來的資料
}
}
當請求被發送到伺服器時,我們需要執行一些基于響應的任務。
每當 readyState 改變時,就會觸發 onreadystatechange 事件。
readyState 屬性存有 XMLHttpRequest 的狀态資訊。
readyState — >XMLHttpRequest 的狀态
從 0 到 4 發生變化:
0 - (請求未初始化) 還沒有調用send()方法
1 - (正在加載,伺服器連接配接已建立) 已調用send()方法,正在發送請求
2 - (加載完成,請求已接收) send()方法執行完成
3 - (互動,請求進行中) 正在解析響應内容
4 - (請求已完成,且響應已就緒) 響應内容解析完成,可以在用戶端調用了
status 狀态碼:
status屬性傳回目前請求的http狀态碼,此屬性僅當資料發送并接收完畢後才可擷取。
1、100-199 用于指定用戶端應相應的某些動作。
2、200-299 用于表示請求成功。
3、300-399 用于已經移動的檔案并且常被包含在定位頭資訊中指定新的位址資訊。
4、400-499 用于指出用戶端的錯誤。
5、500-599 用于支援伺服器錯誤。
200 (“OK”) 成功 一切正常,對GET和POST請求的應答文檔跟在後面,讀取response
500 伺服器方面的問題
503 (服務不可用)
404 找不到資源
301 永久重定向
302 臨時重定向
304 緩存
完整的HTTP狀态碼如下:
- 100 Continue 初始的請求已經接受,客戶應當繼續發送請求的其餘部分
- 101 Switching Protocols 伺服器将遵從客戶的請求轉換到另外一種協定
- 200 OK 一切正常,對GET和POST請求的應答文檔跟在後面。
- 201 Created 伺服器已經建立了文檔, Location頭給出了它的URL。
- 202 Accepted 已經接受請求,但處理尚未完成。
- 203 Non-Authoritative Information 文檔已經正常地傳回,但一些應答頭可能不正确,因為使用的是文檔的拷貝
- 204 No Content 沒有新文檔,浏覽器應該繼續顯示原來的文檔。如果使用者定期地重新整理頁面,而Servlet可以确定使用者文檔足夠新,這個狀态代碼是很有用的
- 205 Reset Content 沒有新的内容,但浏覽器應該重置它所顯示的内容。用來強制浏覽器清除表單輸入内容
- 206 Partial Content 客戶發送了一個帶有Range頭的GET請求,伺服器完成了它
- 300 Multiple Choices 客戶請求的文檔可以在多個位置找到,這些位置已經在傳回的文檔内列出。如果伺服器要提出優先選擇,則應該在Location應答頭指明。
- 301 Moved Permanently 客戶請求的文檔在其他地方,新的URL在Location頭中給出,浏覽器應該自動地通路新的URL。
- 302 Found 類似于301,但新的URL應該被視為臨時性的替代,而不是永久性的。
- 303 See Other 類似于301/302,不同之處在于,如果原來的請求是POST, Location頭指定的重定向目标文檔應該通過GET提取
- 304 Not Modified 用戶端有緩沖的文檔并發出了一個條件性的請求(一般是提供If-Modified-Since頭表示客戶隻想比指定日期更新的文檔)。伺服器告訴客戶,原來緩沖的文檔還可以繼續使用。
- 305 Use Proxy 客戶請求的文檔應該通過Location頭所指明的代理伺服器提取
- 307 Temporary Redirect 和302(Found)相同。許多浏覽器會錯誤地響應302應答進行重定向,即使原來的請求是POST,即使它實際上隻能在POST請求的應答是303時才能重定向。由于這個原因, HTTP 1.1新增了307,以便更加清除地區分幾個狀态代碼:當出現303應答時,浏覽器可以跟随重定向的GET和POST請求;如果是307應答,則浏覽器隻能跟随對GET請求的重定向。
- 400 Bad Request 請求出現文法錯誤。
- 401 Unauthorized 客戶試圖未經授權通路受密碼保護的頁面。應答中會包含一個WWW-Authenticate頭,浏覽器據此顯示使用者名字/密碼對話框,然後在填寫合适的Authorization頭後再次送出請求。
- 403 Forbidden 資源不可用。
- 404 Not Found 無法找到指定位置的資源
- 405 Method Not Allowed 請求方法(GET、 POST、 HEAD、 Delete、 PUT、 TRACE等)對指定的資源不适用。
- 406 Not Acceptable 指定的資源已經找到,但它的MIME類型和客戶在Accpet頭中所指定的不相容
- 407 Proxy Authentication Required 類似于401,表示客戶必須先經過代理伺服器的授權。
- 408 Request Timeout 在伺服器許可的等待時間内,客戶一直沒有發出任何請求。客戶可以在以後重複同一請求。
- 409 Conflict 通常和PUT請求有關。由于請求和資源的目前狀态相沖突,是以請求不能成功。
- 410 Gone 所請求的文檔已經不再可用,而且伺服器不知道應該重定向到哪一個位址。它和404的不同在于,傳回407表示文檔永久地離開了指定的位置,而404表示由于未知的原因文檔不可用。
- 411 Length Required 伺服器不能處理請求,除非客戶發送一個Content-Length頭
- 412 Precondition Failed 請求頭中指定的一些前提條件失敗
- 413 Request Entity Too Large 目标文檔的大小超過伺服器目前願意處理的大小。如果伺服器認為自己能夠稍後再處理該請求,則應該提供一個Retry-After頭
- 414 Request URI Too Long URI太長
- 416 Requested Range Not Satisfiable 伺服器不能滿足客戶在請求中指定的Range頭
- 500 Internal Server Error 伺服器遇到了意料不到的情況,不能完成客戶的請求
- 501 Not Implemented 伺服器不支援實作請求所需要的功能。例如,客戶發出了一個伺服器不支援的PUT請求
- 502 Bad Gateway 伺服器作為網關或者代理時,為了完成請求通路下一個伺服器,但該伺服器傳回了非法的應答
- 503 Service Unavailable 伺服器由于維護或者負載過重未能應答。例如, Servlet可能在資料庫連接配接池已滿的情況下傳回503。伺服器傳回503時可以提供一個Retry-After頭
- 504 Gateway Timeout 由作為代理或網關的伺服器使用,表示不能及時地從遠端伺服器獲得應答
- 505 HTTP Version Not Supported 伺服器不支援請求中所指明的HTTP版本
優點
1、無重新整理更新資料。
2、異步與伺服器通信。
3、前端和後端負載平衡。(減輕伺服器的負擔,AJAX的原則是“按需取資料”, 可以最大程度的減少備援請求和響應對伺服器造成的負擔)
4、基于标準被廣泛支援。
5、界面與應用分離。
缺點
1、AJAX沒有Back和History功能,即對浏覽器機制的破壞。
2、AJAX的安全問題。
3、違背URL和資源定位的初衷。
4、用戶端過肥,太多用戶端代碼造成開發上的成本。
在浏覽器位址欄裡輸入一個位址回車
1、浏覽器會發送一個get請求,該請求會被轉發到DNS伺服器,由DNS伺服器解析域名,然後再轉發到相應的IP位址對應的伺服器。
2、在伺服器端由Apache這樣的Web Server來接收請求,并進行相應的處理,然後 響應結果給用戶端浏覽器。
3、浏覽器接收響應的結果,并進行相應的文法檢查,如果有錯誤,可能會提示錯 誤,如果沒有錯誤,就進行渲染。
4、渲染的時候先生成DOM樹,然後根據CSS和JS規則生成渲染樹(渲染樹中的結構 往往比DOM樹要少,因為有些DOM樹中有些元素如果隐藏的話,不會出現在渲染樹 中),最後再渲染出來。
ES6
作用域
es5 隻有全局作用域、函數作用域(var)
es6 新增塊級作用域
聲明
const 指令
const 指令聲明一個隻讀的常量。一旦聲明,常量的值就不能改變。 實際上保證的是變量指向的那個記憶體位址不得改動 。
對于引用資料類型(對象 / 數組)來說:位址不能修改,值可以修改;
讓引用類型的值也不能修改:
Object.freeze(obj);
let 指令
let 指令聲明變量,所聲明的變量一定要在聲明後使用,否則報錯。
①不存在變量提升 ②不允許重複聲明 ③塊級作用域 ④暫時性死區(從函數體開始到定義之前)
let 與 var 的差別
1、let 不存在變量提升 var存在變量提升
2、let 塊級作用域:let 所聲明的變量,隻在let指令所在的代碼塊内有效。
3、let 不能重複聲明變量
let a = 10;
let a = 20; // [❌]
let a = 10;
var a = 20; // [❌]
4、let 暫時性死區 (臨時失效區):在目前作用域不允許有同名的變量進來
let a = 5;
function fn(){
console.log(a); //var存在變量提升
var a = 10;
} //undefined
let a = 5;
function fn(){
console.log(a); //let不存在變量提升
let a = 10;
} // [❌] a is not defined
let a = 5;
function fn(){
let a = 10;
console.log(a); //輸出:10
}
var a = 5;
function fn(){
let a = 10;
console.log(a);
} //輸出:10
let c = 10;
function fn(){
console.log(c); // 輸出:10
c = 30; //
console.log(c); // 輸出:30
}
變量的解構指派
1、數組解構
let arr = [1,2];
let [a,b] = arr;
console.log(a,b); //輸出:1 2
2、對象解構
//變量名與屬性名相同,順序無關
let p1 = {
name:"zs",
age:20
}
let {name ,age} = p1;
console.log(name,age);
//重命名 改變變量名
let p1 = {
name:"zs",
age:20
}
let {name ,age:n} = p1;
console.log(name,n);
3、字元串解構
對象擴充
對象的屬性和方法的簡寫方式
屬性名與變量名 同名
屬性名 存在 變量中 [變量名]
方法的簡寫
新增的方法
Object.is()
比較兩個值是否嚴格相等
與嚴格比較運算符(===)的行為基本一緻
//特殊情況:
NaN === NaN // false
Object.is(NaN,NaN) // true
+0 === -0 // true
Object.is(+0,-0) // false
symbol 增加的基本資料類型
let name = Symbol();
obj[name] = ‘XX';
// 該屬性不會出現在for...in、for...of循環中
箭頭函數 =>
箭頭函數:定義匿名函數;可以改變有些函數的this指向
this 指向
this 指的是聲明時的this:父作用域中的this(在父作用域中聲明)
普通函數:this 指的是調用時的this
箭頭函數不能用于構造函數
不可以當作構造函數,也就是說,不可以使用new指令,否則會抛出一個錯誤。
箭頭函數中不能使用arguments(類數組)
箭頭函數不可以使用arguments對象,該對象在函數體内不存在。如果要用,可以用 rest 參數代替。
運算符
rest 運算符
let a = (x, ...rest) => {
console.log(x, rest); // 1 (2) [2, 3]
}
a(1,2,3);
//普通函數:
function a(x, y, z) {
console.log(x, y, z); // 1 2 3
console.log(arguments);
//Arguments(3) [1, 2, 3, callee: f, Symbol(Symbol.iterator):f ]
console.log(arguments.callee()); //調用自己
}
a(1, 2, 3);
… 擴充運算符
1、複制數組
2、把一個數組作為另一個數組的一部分
3、合并數組 、 對象
4、類數組轉化為數組
let a = (...rest) => {
console.log(rest); // (3) [1, 2, 3]
}
a(1,2,3);
set()
1、Set函數可以接受一個數組(或類似數組的對象)作為參數,用來初始化
2、set也可以用來去重
var set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
3、4個方法
• add(value):添加某個值,傳回Set結構本身。
• delete(value):删除某個值,傳回一個布爾值,表示删除是否成功。
• has(value):傳回一個布爾值,表示該值是否為Set的成員。
• clear():清除所有成員,沒有傳回值
4、周遊其中元素用 for…of…
map()
1、相比于set的方法,map新增了set 和 get方法
let ar=new Map(); //鍵值對
ar.set('key','value'); //key也可以是變量或者對象
console.log(ar.get('key'));
2、可用的方法
執行個體屬性和方法:size、set、get、has、delete、clear
Promise
Promise對象: 代表了未來某個将要發生的事件(通常是一個異步操作)
- 有了promise對象, 可以将異步操作以同步的流程表達出來, 避免了層層嵌套的回調函數(俗稱’回調地獄’)
- ES6的Promise是一個構造函數, 用來生成promise執行個體
使用的2個步驟
// 建立promise對象
let promise = new Promise((resolve, reject) => {
//初始化promise狀态為 pending
//執行異步操作
if(異步操作成功) {
resolve(value);
//修改promise的狀态fullfilled
} else {
reject(errMsg);
//修改promise的狀态為rejected
}
})
//調用promise的then()
promise.then(function(
))
Promise 對象的三個狀态
- pending: 初始化狀态
- fullfilled: 成功狀态
-
rejected: 失敗狀态
把異步的操作以同步的流程表示出來
resolve成功回調函數 =>then
失敗調用reject() => catch/then第二個回調函數
generator
1、ES6提供的解決異步程式設計的方案之一
2、Generator函數是一個狀态機,内部封裝了不同狀态的資料,
3、用來生成周遊器對象
4、可暫停函數(惰性求值), yield可暫停,next方法可啟動。每次傳回的是yield後的表達式結果
特點
1、function 與函數名之間有一個星号
2、内部用yield表達式來定義不同的狀态
function* generatorExample(){
let result = yield 'hello'; // 狀态值為hello
yield 'generator'; // 狀态值為generator
}
3、generator函數傳回的是指針對象,而不會執行函數内部邏輯
4、調用next方法函數内部邏輯開始執行,遇到yield表達式停止,傳回{value: yield後的表達式結果/undefined, done: false/true}
5、再次調用next方法會從上一次停止時的yield處開始,直到最後
6、yield語句傳回結果通常為undefined, 當調用next方法時傳參内容會作為啟動時yield語句的傳回值。
ES7 :async函數 await 異步回調
真正意義上去解決異步回調的問題,同步流程表達異步操作
本質:Generator的文法糖
文法
async function foo(){
await 異步操作;
await 異步操作;
}
async function firstReq(){
return new Promise(function(resolve){
setTimeout(() => {
resolve()
}, 2000);
})
}
async function asyncPrint(){
console.log('開始');
await firstReq();
console.log('第一個請求完成');
}
asyncPrint();
特點
1、不需要像Generator去調用next方法,遇到await等待,目前的異步操作完成就往下執行
2、傳回的總是Promise對象,可以用then方法進行下一步操作
3、async取代Generator函數的星号*,await取代Generator的yield
4、語意上更為明确,使用簡單,經臨床驗證,暫時沒有任何副作用
defer和async
都能實作異步加載、延遲加載js
defer 是IE中支援的文法,defer 加載時可以幾個檔案都異步加載,等dom結構渲染完(頁面解析完畢) 都加載完再執行,理論上可以保證檔案加載順序。
async 等檔案加載完之後立即執行,不能保證檔案加載順序