HTML專一於內容,CSS專一於表現,JavaScript專一於行爲。javascript
JavaScript術語包含三個部分:php
ECMAScript和JavaScript的區別:
ECMAScript是爲了規範各類前端腳本語法的標準(後端node.js也包含ECMAScript),JavaScript只是其的一種實現。css
共6大數據類型html
注意:前端
typeof(null) === 'object'; //true
typeof(somevar) !== "undefined"
NaN!=NaN;//true
,只能經過isNaN(變量)判斷是否爲數字,而不能經過=
。字符串 | 含義 |
---|---|
\\、\'、\" | 因爲\、'、"在js中是關鍵符號,因此須要轉義 |
\n | 換行符 |
\r | 回車符 |
\t | 製表符 |
\u | \u後面的字符將會被視爲Unicode碼 |
if(變量)
時,如下值被看成false。java
注意:node
null == false; //false
if('false')
、if('0')
都爲true,由於非空字符串看成true優先級:!> && > || ,但爲了可讀性,最好加括號。git
惰性求值:前面的知足,後面不會執行。es6
操做符 | 名稱 | 說明 | 例子 | |
---|---|---|---|---|
== | 相等運算符 | null == undefined;//true '1'==true; //true '1'==1; //true |
||
=== | 嚴格相等運算符 | 類型相同&&值相同 | null === undefined; //false 1 === '1'; //false |
|
!= | 不相等運算符 | NaN!=NaN;//true '1'!=1; //false |
||
!== | 嚴格不相等運算符 | '1'!==1; //true |
||
> | 大於運算符 | '2'>1 ;//true |
||
>= | 大於等於運算符 | 1>='1'; //true |
||
< | 小於運算符 | 1<'2'; //true |
||
<= | 小於等於運算符 | 1<='1'; //true |
注意:github
例子:
let somevar; somevar === undefined;//true
1*undefined;//NaN; 1*null;//0
數組爲引用類型,typeof([]) === 'object' //true
let a = [2,4,5]
a[4]=6;//跳過了a[3],a[3]將爲undefined
delete a[0];//刪除後數組長度不變,被刪除地方的值變爲undefined
a[4]=7
a[0]
注意:
初始化:
let m1 = new Map(); // 空Map let m2 = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
注意:map的鍵必須惟一,若加入重複的鍵,後面的值會沖掉前面的值。
初始化:
let s1 = new Set(); // 空Set let s2 = new Set([1, 2, 3]); // 含1, 2, 3
注意:
注意:for in循環遍歷鍵,而for of和forEach會遍歷鍵值。
聲明式定義
function func(){} //在全局中,或函數中的函數,多用此法定義
函數標識記法
let func = function(){} //函數看成對象一個屬性時,用詞定義法,以下: let student = { name:zhangsan, study:function(){ console.write('study hard!'); } }
js中函數也是一種數據(應該屬於六種數據類型的object,雖然說typeof爲'function',而不是'object'),故命名規則和變量同樣用駝峯,而不是C#中的帕斯卡。
arguments:能夠經過索引獲取傳過來的全部參數,相似數組但不是。
function foo(x) { for (let i=0; i<arguments.length; i++) { console.log(arguments[i]); } }
rest(ES6規範):獲取多餘的參數。
function foo(a, b, ...rest) { console.log('a = ' + a); console.log('b = ' + b); console.log(rest); } foo(1, 2, 3, 4, 5); // 結果: // a = 1 // b = 2 // Array [ 3, 4, 5 ] foo(1); // 結果: // a = 1 // b = undefined // Array []
parseInt()
轉換字符串爲整數
parseInt('123abc1');//輸出123,遇到第一個字母或其餘非法符號截斷 parseInt('FF',16);//輸出255,第二個參數爲進制 parseInt('0x377');//輸出887,以0x開頭表明16進制,無需指定進制 parseInt('0377');//輸出377,雖然以0開頭表明八進制,但易與十進制混淆,因此仍是當成十進制 parseInt('1.258e2');//125
a!==NaN
,由於NaN===NaN返回false,因此只能用isNaN判斷。isFinite()
表示是否有限,注意Infinity、-Infinity表明正負無限
isFinite(Infinity);//false isFinite(-Infinity);//false isFinite(1e309);//false,由於超出了js能表示的最大數字
/?&
等都是關鍵字符,有特殊含義,若須要他們僅僅做爲字符出現,則須要'轉義'/?&
等關鍵字,須要先用encodeURIComponent編碼,再與整個url拼接起來alert()
彈窗,且會阻塞js線程。
window.變量名
獲取到例子:
let a = 123; function f(){ alert(a); let a = 1; alert(a); } f(); //輸出:先彈出'undefined',再彈出1.
解釋:由於函數域始終優先與全局域,因此全局的123沒做用。上面代碼被等價的改寫爲下面
let a = 123; function f(){ let a; //變量會被提高至此,且js引擎默認初始化爲undefined alert(a); a = 1; //賦值不會提高,只提高了定義 alert(a); } f();
()=>{}
。(ES6規範)多用於執行一些一次性的或初始化的任務。
function (name){ alert('Hello'+name+'!'); }('dude'); //匿名自執行函數
函數內再定義函數。
function outer(param) { function inner(theinput) { return theinput * 2; } return 'The result is ' + inner(param); }
坑1:
let xiaoming = { birth: 1990, age: function () {//根據出生日期獲取xiaoming年齡 let y = new Date().getFullYear(); return y - this.birth; } }; let fn = xiaoming.age;//fn指向了age函數,fn跟xiaoming沒任何關係 fn(); //輸出:Uncaught TypeError: Cannot read property 'birth' of undefined //緣由:至關於window調用的fn,age中的this.birth就是window.birth.
坑2:
'use strict'; let xiaoming = { birth: 1990, age: function () {//根據出生日期獲取xiaoming年齡 console.log(this.birth);//這裏的this正常的指向xiaoming對象 function getAgeFromBirth() { let y = new Date().getFullYear(); return y - this.birth;//嵌套函數中的this又指向了window } return getAgeFromBirth(); } }; xiaoming.age(); //輸出:Uncaught TypeError: Cannot read property 'birth' of undefined //緣由:對象中的嵌套函數(第二層及以上)中的this指向window,只有直接子級函數的this指向該對象自己。
解決辦法:
let that = this;
保存住對象的引用,而後在孫子及更深層嵌套的函數中用that.屬性名
訪問對象屬性。let xiaoming = { birth: 1990, getAge: function () { let that = this; function getAgeFromBirth() { let y = new Date().getFullYear(); return y - that.birth;//that指向了xiaoming } return getAgeFromBirth(); } }; xiaoming.getAge();
let xiaoming = { birth: 1990, getAge: function () { let fn = () => new Date().getFullYear() - this.birth; // this指向xiaoming return fn(); } }; xiaoming.getAge();
function a(){ alert('A!'); return function(){ alert('B!'); } } let func = a();//彈出'A' func();//彈出'B' //或者直接以下 a()();//先彈出'A',後彈出'B'
function a() { alert('A!'); a = function(){ alert('B!'); }; } a();//彈出'A!' a();//彈出'B!'
應用場景:瀏覽器兼容性探測,初始化時根據瀏覽器類型,重寫某些方法。
私有變量能夠訪問自身做用域(var爲函數,let、const爲塊)和其外層做用域,就造成了一條做用域鏈。
用一個全局變量指向內層的函數,這樣經過這個全局變量就能夠訪問內層函數同級的變量,突破了做用域鏈。(看着像從外層訪問裏層)
let F = function () { let b = "local variable"; let N = function () { let c = "inner local"; return b; }; return N; }; let inner = F(); inner();//輸出"local variable"
let inner; let F = function (){ let b = "local variable"; let N = function () { return b; }; inner = N; }; F(); inner();//輸出"local variable"
函數所綁定的是做用域自己,而不是在函數定義時該做用域中的變量或變量當前所返回的值。
若須要綁定(非引用類型)變量當前值的快照,則能夠經過調用傳參。由於函數傳參是傳的當前值的拷貝。
getter與setter
經過setter給變量賦值能夠加驗證。
//變量寫成局部變量,不可直接訪問。經過getter和setter暴露取值和賦值的接口。 let getValue, setValue; (function() { let secret = 0; getValue = function(){ return secret; }; setValue = function (v) { if (typeof v === "number") { secret = v; } }; }()); getValue();//輸出0 setValue(123); getValue();//輸出123 setValue(false);//false驗證失敗,賦值不成功 getValue();//輸出123
迭代器
function setup(x) { let i = 0; return function(){ return x[i++]; }; } let next = setup(['a', 'b', 'c']); next();//輸出"a" next();//輸出"b" next();//輸出"c"
鍵類型 | 數據類型 |
---|---|
數字 | 數組 |
字符串 | 對象 |
任意類型 | map |
在一些程序語言中,一般會存在兩種不一樣的數組形式。
js中數組表示索引型數組,對象表示關聯型數組。
1.文本標識法
let obj = { breed: 'Turtle', occupation: 'Ninja' };
對象的屬性名若不符合變量命名規範,則屬性名須要加引號。
let obj = { 'this':'abc', '123':123 }
2.構造函數
function Hero() { this.occupation = 'Ninja'; } let hero = new Hero();
1.經過變量名.屬性名
訪問
hero.occupation;
2.經過變量名[屬性名]
訪問
hero['occupation'];
此種訪問有兩種使用場景:
增:hero.name = 'zhangsan'
;
改:hero.name = 'lisi'
;
刪:delete hero.name
;
瀏覽器環境中,全局對象爲window。
調用全局變量能夠 a 或 window.a 或 this.a 。
指向實例化時所用的構造函數。若用文本標識法建立對象,則它的constructor指向Object()。
h2.constructor; //輸出 //function Hero(name){ // this.name = name; //}
let o = {}; o.constructor; //輸出 function Object(){[native code]}
用於判斷某個對象是否由某個指定的構造器或其父級構造器所建立。
h instanceof Hero;//true h instanceof Object;//true
當且僅當倆引用指向同一對象時,倆對象相等且嚴格相等。
let fido = {breed: 'dog'}; let benji = {breed: 'dog'}; fido == benji;//輸出false
內建對象大體分三類。
Object是全部對象的父級對象。
let o = {}
和let o = new Object()
等價。
Object含如下三個內建屬性:
數組也是一種對象。
let a = []; typeof a;//Object a instanceof Object;//true
相比對象的特殊之處
length屬性會隨着數字鍵名的數量而更新,而忽略非數字鍵名屬性。
a[0] = 0; a.prop = 2;//非數字鍵名不會增長length a.length;//輸出1 a;//輸出[0,prop:2];
當手動設置length的值小於數組中的元素數量時,多出的部分元素被移除。
原素組會改變的方法:
splice————萬能改變數組的方法,截取數組同時填充若干元素,返回截取後的數組。
let a = [1,3,5,7,9]; let b = a.splice(1,2,100,101,102);//第二個參數爲截取長度,與slice的第二個參數不一樣 console.log(a);//[1,100,101,102,7,9] console.log(b);//[3,5]
原數組不受影響,返回一個改變後的數組的方法:
call和apply能夠指定方法的執行上下文,從而能夠實現一個對象去"借用"另外一個對象的方法爲己所用。
例如,arguments對象沒有數組的內建方法,能夠像以下方式調用
function f(){ let args = [].slice.call(arguments); }
經過該方法能夠實現子類對象中調用父類對象中的方法
例如:Array繼承自Object,Array中重寫了Object中的toString方法,但在Array中想調用Object中的方法時能夠Object.prototype.toString.call([])
apply和call的惟一區別是,apply傳參放在一個數組裏。
做用:
其餘幾種基本數據類型也有以上功能
五個基本類型數據都有一個對應的Object類型封裝。
('abcdefg').slice(0,2)
會發生裝箱拆箱。
由於slice方法在String類型對象上,因此會先把值類型轉換爲引用類型,獲得結果後再轉換回值類型。
做用與Boolean相同,但增長了一些屬性和方法。
把Number當成一個對象,該對象裏有如下屬性:
把Number當成構造函數,該構造函數prototype指向對象上有如下方法:
toString————重寫了object的toString,有一個可選的radix參數(默認10)
(255).toString(16);//'ff'
Math用法與上面不一樣,不能new。
經常使用屬性:
經常使用方法:
用於建立Date對象的構造器函數,能夠傳遞如下幾種參數
注意:js中的月份是從0開始,0表示一月,1表示二月...
經常使用方法
var now = new Date(); now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST) now.getFullYear(); // 2015, 年份 now.getMonth(); // 5, 月份,注意月份範圍是0~11,5表示六月 now.getDate(); // 24, 表示24號 now.getDay(); // 3, 表示星期三 now.getHours(); // 19, 24小時制 now.getMinutes(); // 49, 分鐘 now.getSeconds(); // 22, 秒 now.getMilliseconds(); // 875, 毫秒數 now.getTime(); // 1435146562875, 以number形式表示的時間戳
同時有相應的set方法設置值。
注意:getDay表示獲取星期,getDate才表示獲取日
Date.now();//返回當前時間的時間戳 Date.parse('Jan 11, 2018');//返回時間戳 Date.UTC(2018,0,11);//返回時間戳
寫法:
let re = new RegExp('j.*t','gmi')
let re = /j.*t/ig
組成部分:
修飾符:
RegExp對象的方法:
/j.*t/.test("Javascript");//false /j.*t/i.test("Javascript");//true /j.*t/i.exec("Javascript")[0];//Javascript
字符串中使用正則的方法:
let s = 'HelloJavaScriptWorld'; s.match(/a/);//返回["a"],沒有加g修飾符,故匹配到第一個就返回 s.match(/a/g);//返回["a","a"],加g後匹配全部 s.search(/j.*a/i);//返回5
s.replace(/[A-z]/,'');//返回elloJavaScriptWorld,替換首個大寫字母爲空 s.replace(/[A-Z]/g,'');//返回elloavacriptorld,替換全部大寫字母爲空 s.replace(/[A-Z]/g,"_$&");//返回_Hello_Java_Script_World,用$&代替所匹配的文本 s.replace(/([A-Z])/g, "_$1");//返回_Hello_Java_Script_World,若正則表達式中分了組(即帶括號),那麼能夠用$1表示分組中的第一組,$2表示第二組,依此類推
注意:replace中第一個參數不是正則而是字符串時,只會替換掉第一個。這是與其餘語言不一樣的。
"pool".replace('o','*');//返回"p*ol" "pool".replace('/o/g','*');//返回"p**l"
function replaceCallback(match){ return ""+match.toLowerCase(); } s.replace(/[A-Z]/g,replaceCallback);//輸出_hello_java_script_world
該回調函數接受一系列參數(以上示例僅用到了第一個參數)
包括一些派生的ReferenceError、RangeError、EvalError、SyntaxError、TypeError、URIError。
Error類對象都有兩個屬性:
try { var total = maybeExists(); if (total === 0) { throw new Error('Division by zero!'); } else { alert(50 / total); } } catch (e){ alert(e.name + ': ' + e.message); } finally { alert('Finally!'); }
IE瀏覽器跟Chrome、FireFox拋出異常的name和message不一樣,能夠自定義拋出一個匿名對象。
throw { name: "MyError", message: "OMG! Something terrible has happened" }
js中的繼承就是基於原型的。
函數也是對象,每一個函數上都有一個prototype屬性。
function foo(a,b){ return a*b; } typeof foo.prototype;//輸出"object"
函數的原型屬性只有在函數看成構造函數使用(即便用new調用)時才起做用。
this.屬性名
訪問實例屬性值和原型對象上的屬性。每一個對象都會有一個構造器,而原型自己也是一個對象,這意味着它必然也有一個構造器,而這個構造器又會有本身的原型。因而這種結構可能會一直不斷地持續下去,並最終造成原型鏈。
判斷一個對象是不是另外一個對象的原型對象
let monkey = { hair:true, feeds:'bananas', breathes:'air' }; function Human(name){ this.name = name; } Human.prototype = monkey; let george = new Human('George'); monkey.isPrototypeOf(george);//返回true
獲取一個對象的原型對象
Object.getPrototypeOf(george);//返回monkey對象 george.constructor.prototype;//這樣也能夠獲取
生成一個對象時,js引擎自動在對象上加了一個__proto__屬性,指向該對象的原型對象。而後原型對象也是對象,也有一個__proto__屬性指向一個原型對象...如此下去,便造成了一條原型鏈。
__proto__只能在學習或調試環境下使用
注意:以上爲對象層面的原型鏈。new一個對象時,js引擎把構造函數、原型對象層面的鏈狀關係轉化爲對象層面的原型鏈。構造原型對象和構造函數之間的鏈狀關係纔是咱們所需編寫的代碼。
//擴展Date,加一個format方法 Date.prototype.format = function (fmt) { var o = { "M+": this.getMonth() + 1, //月份 "d+": this.getDate(), //日 "h+": this.getHours(), //小時 "m+": this.getMinutes(), //分 "s+": this.getSeconds(), //秒 "q+": Math.floor((this.getMonth() + 3) / 3), //季度 "S": this.getMilliseconds() //毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return fmt; };
function Dog(){ this.tail = true; } let benji = new Dog(); Dog.prototype.say = function(){ return 'Woof!'; } benji.say();//對象生成後,再在原型對象上加方法,依然能夠調用該方法 beiji.constructor === Dog;//返回true Dog.prototype = { //此處徹底替換掉了原來的原型對象 paws:4, hair:true } typeof benji.paws;//返回'undefined' beiji.say();//返回'Woof!',由於beiji的__proto__屬性還連接着原來的原型對象 let lucy = new Dog();//在徹底替換掉原型對象後,再實例化對象 lucy.say();//TypeError:lucy.say is not a function lucy.paws;//4 lucy.constructor;//function Object(){[naticve code]},替換掉原型對象後,該原型對象的constructor屬性就不指向Dog了
最佳實踐:當咱們重寫對象的prototype時,須要重置相應的constructor屬性。
js引擎所作的:查找對象屬性時,先在對象自身屬性中查找,再沿着__proto__鏈着的對象上查找。
咱們所需作的:經過構造函數和原型對象構建連接關係。(new一個對象時,js引擎把轉化爲經過__proto__把對象之間鏈接起來)
Child.prototype = new Parent(); Child.prototype.constructor = Child;//重置原型對象上的constructor屬性,否則就指向了Parent
缺點:該方法不只繼承了父類的實例屬性,還繼承了父類的原型屬性
function extend(Child,Parent){ let F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; }
該方法只會繼承父類的原型屬性,不會繼承父類的實例屬性。
ES6中引入了class關鍵字,但並不是js中有了類,只是一個實現繼承的語法糖,實際仍是經過原型實現繼承。
class Student { constructor(name) { this.name = name;//實例屬性、方法放在constructor中 } hello() { //原型屬性、方法放在外面 alert('Hello, ' + this.name + '!'); } } class PrimaryStudent extends Student { //extends關鍵字表明繼承自誰 constructor(name, grade) { super(name); // 記得用super調用父類的構造方法! this.grade = grade; } myGrade() { alert('I am at grade ' + this.grade); } }
運行javascript代碼須要宿主環境,通常是瀏覽器環境。
BOM(瀏覽器對象模型)是一個用於訪問瀏覽器和計算機屏幕的對象集合。能夠經過window訪問這些對象。
window對象是瀏覽器中的全局對象,全部的全局變量和函數均可以經過window對象的屬性訪問。
navigator是一個反應瀏覽器及其功能信息的對象。如navigator.userAgent能夠識別不一樣的瀏覽器。
location是一個用於存儲當前載入頁面url信息的對象。
屬性:
//若果當前頁面的url爲http://search.phpied.com:8080/search?p=java&what=script#results for(var i in location) { if(typeof location[i] === 「string」) { console.log(i + ' = "' + location[i] + '"'); } } //輸出: //href = "http://search.phpied.com:8080/search?q=java&what=script#results" //hash = "#results" //host = "search.phpied.com:8080" //hostname = "search.phpied.com" //pathname = "/search" //port = "8080" //protocol = "http:" //search = "?q=java&what=script"
注:location的href中除了hash變化不會引發向服務端發起請求外,其餘部分變化都會從新向服務端發起請求。
方法:
window.histoty屬性容許咱們以有限的權限操做同一個瀏覽器會話中的已訪問頁面。
做用:讓無跳轉的單站點也能夠將它的各個狀態保存爲瀏覽器的多條歷史記錄。當經過歷史記錄從新加載站點時,站點能夠直接加載到對應的狀態。
API:
history.pushState(stateObject, title, url)
,包括三個參數。window.onpopstate
頁面前進後退時,若當前url有對應的stateObject則觸發事件,並在參數中包含stateObject。
//假如當前網頁地址爲http://example.com/example.html,則運行下述代碼後: window.onpopstate = function(event) { alert("location: " + document.location + ", state: " + JSON.stringify(event.state)); }; //綁定事件處理函數 history.pushState({page: 1}, "title 1", "?page=1"); //添加並激活一個歷史記錄條目 http://example.com/example.html?page=1,條目索引爲1 history.pushState({page: 2}, "title 2", "?page=2"); //添加並激活一個歷史記錄條目 http://example.com/example.html?page=2,條目索引爲2 history.replaceState({page: 3}, "title 3", "?page=3"); //修改當前激活的歷史記錄條目 http://ex..?page=2 變爲 http://ex..?page=3,條目索引爲3 history.back(); // 彈出 "location: http://example.com/example.html?page=1, state: {"page":1}" history.back(); // 彈出 "location: http://example.com/example.html, state: null history.go(2); // 彈出 "location: http://example.com/example.html?page=3, state: {"page":3}
window.frames屬性是當前頁面中全部框架的集合。
frames中的每一個元素都包含了一個頁面,都有各自的window全局對象。
screen所提供的是瀏覽器之外的環境信息。
打開窗口、關閉窗口
注:Chrome、edge中測試均無反應,已廢棄。
setTimeout:在必定時間後執行
function boo(){ console.log('boo!'); } let id = setTimeout(boo,2000);//2秒後執行boo方法 clearTimeout(id);//根據id取消計時器
setInterval:每隔多少毫秒執行一次
let id = setInterval(boo,2000);//每隔2秒執行一次 clearInterval(id);//根據id取消計時器
DOM是一種將XML或HTML文檔解析成樹形節點的方法。經過DOM的方法與屬性,咱們能夠訪問到頁面中的任何元素,並進行元素的修改刪除及添加操做。
基於DOM Level1用於解析全部XML文檔的那部分稱爲Core DOM,在Core DOM上進行擴展的那部分稱爲HTML DOM。
document表示當前所訪問的文檔。
document.documentElement表示document上的HTML節點。
document.documentElement(即HTML節點)有三個,即head元素、body元素,以及二者之間的空白(空白默認爲文本節點)。
節點對象.id
訪問id屬性的值,節點對象.className
訪問class屬性的值若一段HTML結構以下:
<html> <head></head> <!--這中間雖然什麼都沒有,但其實仍是有一個text節點--> <body> <p class="opener">first paragraph</p> <p><em>second</em> paragraph</p> <p id="closer">final</p> <!-- and that's about it --> </body> </html>
document.documentElement.childNodes[1];//#text,由於head和body之間存在一個空白,該空白爲text節點 document.documentElement.childNodes[1].parentNode;//<html>...</html> let bd = document.documentElement.childNodes[2]; bd.childNodes.length;//9,由於四個節點(包括註釋)之間、子節點和父節點之間一共存在5個空白的text節點,因此一共9個節點 bd.childNodes[1].hasAttributes();//true,第一個標籤有個class屬性。注意索引0是空白text,索引1纔是p標籤 bd.childNodes[1].attributes.length;//1 bd.childNodes[1].attributes[0].nodeName;//'class' bd.childNodes[1].attributes[0].nodeValue;//'opener' bd.childNodes[1].attributes['class'].nodeValue;//'opener' bd.childNodes[1].getAttribute('class');//'opener' bd.childNodes[1].className;//'opener' bd.childNodes[1].nodeName;//'p' bd.childNodes[1].textContent;//'first paragraph' bd.childNodes[1].innerHTML;//'first paragraph' bd.childNodes[3].textContent;//'second paragraph' bd.childNodes[3].innerHTML;//'<em>second</em> paragraph' bd.childNodes[1].childNodes[0].nodeValue;//'first paragraph'
索引法的問題:
快捷方法:
注:getElement系列除了getElementById返回一個Element外,其餘都返回一個HTMLCollection集合,HTMLCollection是動態的,會隨着文檔樹的變化動態更新。
querySelector系列返回一個NodeList,NodeList是靜態的,獲取後,文檔樹變化不會影響NodeList.
document.getElementsByTagName('p').length;//3 document.getElementsByTagName('p')[0];//<p class="opener">first paragraph</p> document.getElementsByTagName('p')[0].className;//'opener' document.querySlector('p').className;//'opener' document.querySlectorAll('p')[0].className;//'opener'
body雖說嵌套在html標籤裏,但document.body就能夠訪問到body,而不用document.documentElement.body。
let my = document.getElementById(,'closer'); my.innerHTML = 'final!!!'; my.innerHTML = '<em>my</em> final'; my.firstChild;//<em>my</em> my.firstChild.firstChild;//'my' my.firstChild.firstChild.nodeValue = 'your'; my.style.border = '1px solid red'; my.style.cssText += 'font-weight:bold;';//直接在原有cssText屬性上加css字符串文本
注意:後三個方法調用方是父容器節點。
let p = document.createElement('p'); p.innerHTML = '<em>yet</em> another'; p.style.border = '2px dotted blue'; document.body.appendChild(p); let list=document.getElementById("myList") list.insertBefore(p,list.childNodes[0]);//第一個參數爲新節點,第二個參數爲插入誰的前面 item.replaceChild(p,list.childNodes[0]);//第一個參數爲替換者,第二個爲被替換者 document.body.appendChild(p.cloneNode(false));//將只會拷貝一個p標籤,至關於document.body.appendChild(document.createElement('p')); document.body.appendChild(p.cloneNode(true));//p及p標籤裏的子元素都將拷貝
let p = document.getElementsByTagName('p')[1]; let removed = document.body.removeChild(p); let p1 = document.getElementsByTagName('p')[1]; let replaced = document.body.replaceChild(removed,p1); document.body.innerHTML = '';//清空body裏的全部HTML
以上總結的都是屬於DOM Level 0(或叫Core DOM),既適用於XML又適用於HTML。如下的只適用於HTML。
<a href='...'/>
的集合<a name='...'>
的集合document.forms————包含全部表單的集合
document.write()————在頁面載入時插入一些HTML元素,當載入完成後調用則會覆蓋整個HTML。通常沒什麼用。
document.location————同window.location
1.內聯HTML屬性法
<div onclick="alert('Ouch!')">click me</div>
缺點:Javascript代碼和HTML耦合在一塊兒。
2.元素屬性法
<div id="my-div">click</div>
let myelement = document.getElementById('my-div'); myelement.onclick = function() { alert('Ouch!'); }
缺點:只能指定一個事件函數。
3.事件監聽器法
<p id="closer">final</p>
let mypara = document.getElementById('closer'); mypara.addEventListener('click', function(){alert('Boo!')}, false); mypara.addEventListener('click', console.log.bind(console), false);
移除某個監聽器:
function func(){ alert('Woo'); } mypara.addEventListener('click', func, false); mypara.removeEventListener('click', func, false);
注意:移除某個監聽器時,傳遞的方法參數必須是同一個方法的引用,即便寫一個徹底相同的方法爺不行。故須要移除的監聽器在註冊時不能用匿名方法。
addEventListner方法的第三個參數,當置爲true時爲捕捉法,默認爲false即冒泡法。
<body> <ul> <li><a href="http://phpied.com">my blog</a></li> </ul> </body>
單擊連接
按照DOM2的規定,事件傳播分三階段:先捕捉標籤,而後到達標籤,再冒泡。
在最裏層的處理器中加e.stopPropagation()
,就不會觸發上層父容器的事件。
function paraHandler(e){ alert('clicked paragraph'); e.stopPropagation(); }
在瀏覽器中某些元素的事件有一些預約義行爲,例如,單機連接會載入另外一個頁面。能夠在事件處理器中加e.preventDefault()
來阻斷默認行爲。
// 在點擊全部連接前詢問是否導航至目標連接,若選擇否,則不導航 let all_links = document.getElementsByTagName('a'); for (let i = 0; i < all_links.length; i++) { all_links[i].addEventListener( 'click', function(e){ if (!confirm('Are you sure you want to follow this link?')){ e.preventDefault(); } }, false // don't use capturing ); }
現代瀏覽器還有dragstart、dragend、drop事件,觸控設備還有touchstart、touchmove、touchend事件。
let xhr = new XMLHttpRequest(); xhr.onreadystatechange = myCallback; xhr.open('GET','somefile.text',true); xhr.send('');//若要攜帶參數則以格式'key=value&key2=value2' fuction myCallback(){ if(xhr.readyState<4){ return; } if(xhr.status!==200){ alert('Error!'); return; } alert(xhr.responseText); }