此文是對js高級程序設計一書難點的總結,也是筆者在看了3遍以後的一些梳理和感想,但願能借此鞏固js的基礎和對一些核心概念有更深刻的瞭解。javascript
浮點數值的最高精度是17位小數,但在進行算術計算時精度遠遠不如整數。例如 0.1 + 0.2 === 0.300000000000004(大體這個意思,具體多少個零請實際計算) 因此永遠不要測試某個特定的浮點數值php
parseFloat主要用於解析有效的浮點數字,始終會忽略前導的零,可識別全部的浮點數格式,可是十六進制格式的字符串始終會被轉換成零。css
let num = 10;
num.toString(n) n表示進制,可選,如2,8,10,16
複製代碼
// 結合label,更精確的控制循環
outerMost:
for(var i=0;i<10;i++){
for(var j=0;i<10;j++){
if(i = 5){
break outerMost
}
}
}
//此時直接退出外部循環,continue也是相似
複製代碼
function add(n1, n2){
arguments[1] = 10;
}
複製代碼
此時讀取n2和arguments[1]並不會訪問相同的內存空間,他們的內存空間是獨立的,但他們的值保持同步html
1.全部的參數都是按值傳遞的。在向參數傳遞引用類型的值時,會把這個值在內存中的地址複製給一個局部變量,所以這個局部變量的變化會反應在函數外部前端
2.當在函數內部重寫obj時,這個變量引用的就是一個局部對象。而這個局部對象會在函數執行完畢後當即被銷燬。vue
js最經常使用的垃圾收集機制爲「標記清除」,另外一種不經常使用的是「引用計數」。java
原理:找出再也不繼續使用的變量,而後釋放其內存空間。垃圾收集器會在固定的時間間隔週期性的執行這一操做。node
解除引用:數據再也不有用,將其值設置爲nullreact
// 檢測數值ES5方法
Array.isArray(value) // 檢測值是否爲數組
// 轉換方法
toString() 將數組轉化爲以逗號分隔的字符串
valueOf() 返回的仍是數組
// 棧方法
push() 能夠接收任意數量的參數,把他們逐個添加到數組的末尾,返回修改後數組的長度
pop() 從數組末尾移除最後一項,返回移除的項
// 隊列方法
shift() 移除數組的第一項並返回該項
unshift() 向數組前端添加任意個項並返回新數組的長度
// 排序
sort(compare)
compare函數接收兩個參數,若是返回負數,則第一個參數位於第二個參數前面;若是返回零,則兩個參數相等;若是返回正數,第一個參數位於第二個參數後面
// 降序,升序相反
(a,b) => (b-a)
// 操做方法
concat(數組 | 一個或多個元素) // 合併數組,返回新數組
slice(起始位置 ,[結束位置]) // 切分數組,返回新數組,新數組不包含結束位置的項
splice(起始位置,刪除的個數,[插入的元素]) // 刪除|插入|替換數組,返回刪除的元素組成的數組,會修改原數組
// 位置方法
indexOf(查找的項,[查找起點位置]) // 使用全等操做符,嚴格相等
lastIndexOf()
// 迭代方法,都接收兩個參數,一個是要在每一項上運行的函數,一個是做用域(可選)
1.every 對數組中每一項運行給定函數,若是函數對每一項都返回true,則返回true
every(fn(value,index,array){return ...},[this])
2.some 對數組中每一項運行給定函數,若是函數對任一項都返回true,則返回true
3.filter 對數組中每一項運行給定函數,返回該函數會返回true的項組成的數組
4.forEach 對數組每一項運行給定函數,無返回值
5.map 對數組每一項運行給定函數,返回每次函數調用返回結果組成的數組
// 歸併方法 reduce和reduceRight(和前者遍歷的方向相反),構建一個最終返回的值
reduce(fn(prev,cur,index,array){ return ... },initValue)
1.fn返回的值會做爲第一個參數傳遞給下一項
2.initValue作爲歸併基礎的初始值
複製代碼
因爲RegExp構造函數的模式參數是字符串,因此在某些狀況下要進行雙重轉義,對於\n雙重轉義爲\\nandroid
使用正則字面量時會共享一個RegExp實例,而正則構造函數會爲每次調用建立一個新的regExp實例
RegExp實例屬性
let text = "xd ff gggg";
let pattern = /xd ((ff) gggg)?/g;
let matches = pattern.exec(text); //每次調用都返回一個匹配項,即便是全局模式
matches[0] //與整個模式匹配的字符串
matches[1] // 除了第一項之外,其餘項爲與模式中捕獲組匹配的字符串
複製代碼
// RegExp構造函數屬性
leftContext | $`(短屬性名) // 匹配項左部文本
rightContext | $'(短屬性名) // 匹配項右部文本
// 案例
if(pattern.test(text)){
console.log(RegExp.leftContext) // 或
console.log(RegExp["$`"])
}
// 用於獲取捕獲組
RegExp.$1, RegExp.$2, RegExp.$3
複製代碼
函數內部屬性 arguments對象有一個名叫callee的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數 arguments.callee(arg) //調用函數自身,在嚴格模式下運行時會致使錯誤
函數屬性 length 表示函數但願接收的命名參數的個數 prototype 保存全部實例方法
函數方法
apply() // 接收兩個參數,一個是做用域,另外一個是參數數組
call() // 第一個參數是做用域, 剩下的參數是函數須要接收的參數,須要一一列出
bind() // 該方法會創 建一個函數的實例,其this值會被綁定到傳給bind()函數的值 IE9+支持
valueOf() / toString() // 返回函數的代碼
複製代碼
toFixed(n) // 按照指定的小數位返回數值的字符串表示(能夠自動四捨五入)
複製代碼
charAt(n) // 返回給定位置的字符
charCodeAt(n) // 返回給定位置的字符編碼
"dddd"[n] // 訪問字符串特定索引的字符
concat() //用於將一個或多個字符串拼接起來
slice(start, end) / substring(start, end) // 返回一個新的從開始位置到結束位置的字符串,不包括結束位置
substr(start, len) // 返回一個新的從開始位置到指定長度的字符串
indexOf(str,[startIndex]) // 返回指定字符在字符串中的索引,第二個參數爲從指定位置開始搜索,可選
trim() // 該方法會建立一個字符串的副本,刪除前置與後綴的全部空格,返回結果
toLowerCase() / toUpperCase() // 小寫大寫轉換
// 字符串的模式匹配方法
1.match(pattern) //本質上與RegExp的exec()方法相同,只接受一個參數,即正則表達式或RegExp對象
2.search(pattern) // 參數與match參數相同,返回字符串中第一個匹配項的索引
3.replace(str | pattern, text | fn) //第一個參數爲想要被替換的字符串或正則表達式,第二個參數爲要替換的字符串或一個函數
* 若是第二個參數是字符串,可使用一些特殊的字符序列,將正則表達式操做獲得的值插入到結果字符串中。
$' //匹配的子字符串以後的子字符串
$` //匹配的子字符串以前的子字符串
$n //匹配第n個捕獲組的子字符串
* 若是第二個參數是函數,在只有一個匹配項時,會向函數傳遞3個參數,模式的匹配項,模式的匹配項在字符串中的位置,原始的字符串
正則表達式中定義了多個捕獲組的狀況下,傳遞的參數依次是模式的匹配項,第一個捕獲組的匹配項,第二個捕獲組的匹配項...,最後兩個參數和上者相同
如:
function htmlEscape(text){
return text.replace(/[<>&"]/g, (match, pos, originalText) => {
switch(match){
case "<":
return "<";
case ">":
return ">";
case "&":
return "&";
case "\"":
return """
}
})
}
4.split() // 第一個參數是須要指定分隔符匹配中的字符串或者正則表達式,也能夠傳遞第二個參數,用來限制返回數組的長度
例:
let text = "xujaing,red,ddd";
text.split(",") // ["xujaing", "red", "ddd"]
text.split(",", 2) // ["xujaing", "red"]
text.split(/[^\,]+/) //*** 匹配非字母,用字符串的非字母分割字符串,返回數組
* 5.localeCompare() // 比較兩個字符串,若是字符串在字母表中排在字符串參數以前,返回負數,相等返回0,反之正數
複製代碼
Global對象
1.URI編碼方法
encodeURI() // 除了空格以外其餘字符都不編碼
encodeURIComponent() //會對它發現的任何非標準字符進行編碼
decodeURI() //只能對使用encodeURI的字符進行解碼
decodeURIComponent() // 原理同上
Math對象
1.Math.max() / Math.min() // 接收任意多數值做爲參數
// 求數組中最大值 Math.max.apply(Math, arrValue)
2.Math.ceil() / Math.floor() / Math.round() //向上/下/四捨五入
3.Math.random() //返回大於等於0小於1的隨機數
4.Math.abs() //返回參數的絕對值
5.Math.pow(num,power) // 返回num的power次冪
6.Math.sqrt(num) // 返回num的平方根
複製代碼
// 1.數據屬性
let person = {};
Object.defineProperty(person, "name", {
configurable: true, //表示可否經過delete刪除屬性從而從新定義屬性,可否修改屬性
enumerable: true, //表示可否經過for-in循環返回屬性
writable: true, // 表示是否能修改屬性的值
value: "xujiang" // 屬性的值
})
/* 在調用Object.defineProperty()方法建立一個新屬性時,如不指定前三個屬性字段,默認值都爲false, 若是是修改已定義的屬性時,則沒有此限制 */
// 2.訪問器屬性get/set
let person = {name: "xujaijgn", year: 11};
Object.defineProperty(person, "_name", {
get: function(){
return this.name
},
// 定義Set時,則設置一個屬性的值時會致使其餘屬性發生變化
set: function(newValue){
this.name = newValue;
this.year = 12;
}
})
// 定義多個屬性
Object。defineProperties(book, {
_year: {
writable: false,
value: 2001
},
year: {
get: function(){
return _year
},
set: function(newValue){
this._year = newValue;
}
}
})
複製代碼
1.工廠模式---返回新對象的方式
2.構造函數---定義函數,經過new操做符建立對象(任何函數經過new操做符調用均可以看做構造函數)
缺點:每一個方法在實例中都要從新建立一遍
3.原型模式 (book.prototype.name = "aaa")
優勢:可讓每一個實例對象共享它所包含的方法
缺點: 屬性共享,對於引用類型值的屬性,實例會共享屬性
理解原型:
1.isPrototypeOf() // 肯定對象之間是否存在原型關係
2.Object.getPrototypeOf(object1) // 獲取實例對象的原型
3.咱們能夠經過對象實例訪問保存在原型中的值,但卻不能經過對象實例重寫原型中的值,若是該實例有與原型相同的屬 性名,則會屏蔽原型中的屬性
4.hasOwnProperty(name) // 檢測一個屬性是否在實例中
5.原型與in操做符 "name" in person // 對象能訪問到給定屬性時返回true
6.Object.keys(obj) // 返回一個包含全部可枚舉屬性的字符串數組(實例屬性)
7.Object.getOwnPropertyNames() //獲取全部實例屬性,包括不可美枚舉的
8.實例中的指針只指向原型,而不指向構造函數
9.重寫原型對象會切斷現有原型與以前存在的對象實例之間的聯繫,他們引用的任然是最初的原型
4.組合式(構造函數模式和原型模式)
1.用構造函數定義實例屬性,用原型定義方法和共享屬性
5.動態原型模式(經過檢查某個應該存在的方法是否存在,來決定須要初始化原型
6.穩妥構造函數模式(適合在某些安全環境下工做)
function Person(name,year,job){
var o = new Object();
// 這裏能夠添加私有變量和方法
o.sayName = () => name
return o
}
複製代碼
1.原型鏈的問題
1.包含引用類型值的原型屬性會被全部實例共享,在經過原型實現繼承時,原型實際上會變成另外一個類型的實例,原先的實例屬性變成了如今的原型屬性。
2.在建立子類型的實例時,沒法向父類構造函數傳遞參數
2.借用構造函數(在子類型構造函數的內部調用父類構造函數)
//此時實例不會共享屬性
function Parent(name){
this.colors = [1,3,4];
this.name = name;
}
function Child(name){
Parent.call(this, name);
this.age = 12;
}
// 存在的問題: 1.函數沒法複用 2.父類的原型對於子類是不可見的
3.組合繼承(使用原型鏈繼承原型屬性和方法,使用借用構造繼承實例屬性) ---最經常使用的繼承模式
缺點:不管如何都會調用兩次父類構造函數
// 父類
function Parent(name){
this.name = "xujaing";
this.age = 12;
};
Parent.prototype.say = function() { console.log(this.age) };
// 子類繼承父類
function Child(name){
Parent.call(this, name);
this.age = 13;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
Child.prototype.say = function() { alert(this.age) };
4.原型式繼承
實現1.
function object(o){
function F(){};
F.prototype = o;
return new F()
}
實現2.經過Object.create(prototype, properties) // 第一個參數爲建立新對象原型的對象,第二個參數爲對新對象定義額外屬性的對象(和defineProperties方法的第二個參數格式相同)
Object.create(person, {
name: {
value: "xujiang"
}
})
5.寄生組合式繼承(經過借用構造函數繼承屬性,經過原型鏈混成的方式繼承方法)---最理想的繼承範式
function inheritPrototype(sub,sup){
let prototype = Object.create(sup.prototype);
prototype.constructor = sub;
sub.prototype = prototype;
}
function Sup(){}
Sup.prototype.say = function(){}
function Sub(arg){
// 關鍵
Sup.call(this,arg);
}
// 關鍵
inheritPrototype(Sub, Sup);
複製代碼
解決方案
function createFunction(){
let arr = [];
for(let i=0; i< 10; i++){
arr[i] = function(num){
return num
}(i)
}
return arr
}
複製代碼
在全局函數中,this等於window,而當函數被看成某個對象的方法調用時,this等於那個對象。不過,匿名函數的執行環境具備全局性,所以其this對象一般指向window
(object.say = object.say)() 此時函數內部this指向window,由於該賦值表達式的值是函數自己,因此this的值不能獲得維持
function a(){
let el = $("#el");
let id = el.id;
el.click(function(){
alert(id)
})
// 清空dom,釋放內存
el = null;
}
複製代碼
窗口位置(不一樣瀏覽器實現不同,因此位置獲取的不精確和統一)
let leftPos = (typeof window.screenLeft == "number") ? window.screenLeft : window.screenX;
let top = (typeof window.screenTop == "number") ? window.screenTop : window.screenY;
// 獲取頁面視口
let pageWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
複製代碼
// 顯示打印對話框
window.print()
複製代碼
// location便是window對象的屬性也是document對象的屬性
1. hash // "#contents" 返回url的hash,若是不包含返回空
2. host // "www.wrox.com:80" 返回服務器名稱和和端口號
3. hostname // "www.wrox.com" 返回不帶端口號的服務器名稱
4. href // 返回當前加載頁面的完整url
5. pathname // "/a/" 返回url中的目錄或文件名
6. port // "8080" 返回url中指定的端口號
7. protocol // "http" 返回頁面使用的協議
8. search // "?q=java" 返回url中查詢字符串,以問號開頭
// 獲取查詢字符串
function queryObj(){
let qs = (location.search.length > 0 ? location.search.substring(1) : ''),
arg = {},
items = qs.length ? qs.split('&') : [],
item = null,
name = null,
value = null,
i = 0,
len = items.length;
for(i;i<len;i++){
item = items[i].split('=');
name = decodeURIComponent(item[0]);
value = decodeURIComponent(item[1]);
if(name.length){
arg[name] = value;
}
}
return args
}
// 位置操做
1.location.assign(url) //打開新連接,並在瀏覽器歷史記錄裏生成一條記錄
2.location.href = url; //打開新連接,並在瀏覽器歷史記錄裏生成一條記錄
3.location.hash = "#detail" // 在url後添加hash
4.location.hostname = "www.baidu.com" //修改服務器名稱
5.location.pathname = "home" //修改路徑
6.location.port = 8080; // 修改端口號
***經過以上方法修改url後會在瀏覽器歷史中生成一條記錄,用戶點擊後退能夠導航到前一個頁面。
7.location.replace(url) // 此方式不會在瀏覽器中生成新記錄,用戶不能回到前一個頁面
8.location.reload([true]) // 頁面會以最有效的方式從新加載(有可能從緩存中加載),若是參數爲true,則將從服務器中加載
複製代碼
navigator.language // "zh-CN" 瀏覽器的主語言
navigator.appName // "Netscape" 完整的瀏覽器名稱
navigator.appVersion // 瀏覽器的版本
// 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36
navigator.cookieEnabled // true 表示cookie是否啓用
navigator.javaEnabled() // 表示瀏覽器是否啓用java
navigator.onLine // true 表示瀏覽器是否鏈接到了因特網
navigator.platform // "Win32" 瀏覽器所在的系統平臺
navigator.userAgent // 瀏覽器用戶代理字符串
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36"
navigator.plugins // 檢測瀏覽器中安裝的插件的數組
複製代碼
1. history.go(0 | [123] | -1 | str) // 若是是Str,則會跳轉到歷史記錄中包含該字符串的第一個位置
2. history.back() //後退一頁
3. history.forward() //前進一頁
4. history.length // 保存着歷史紀錄的數量
複製代碼
let client = function() {
//呈現引擎
let engine = {
ie: 0,
gecko: 0,
webkit: 0,
khtml: 0,
opera: 0,
// 完整版本號
ver: null
};
// 瀏覽器
let browser = {
// 主要瀏覽器
ie: 0,
firefox: 0,
safari: 0,
konq: 0,
opera: 0,
chrome: 0,
// 具體版本號
ver: null
};
// 平臺/設備/操做系統
let system = {
win: false,
mac: false,
x11: false,
// 移動設備
iphone: false,
ipod: false,
ipad: false,
ios: false,
android: false,
nokiaN: false,
winMobile: false,
// 遊戲系統
wii: false,
ps: false
};
// 檢測呈現引擎和瀏覽器
let ua = navigator.userAgent;
if (window.opera) {
engine.ver = browser.ver = window.opera.version();
engine.opera = browser.opera = parseFloat(engine.ver);
} else if (/AppleWebKit\/(\S+)/.test(ua)) {
// \S 匹配一個非空白字符
engine.ver = RegExp["$1"];
engine.webkit = parseFloat(engine.ver);
// 肯定是chrome仍是safari
if (/Chrome\/(\S+)/.test(ua)) {
browser.ver = RegExp["$1"];
browser.chrome = parentFloat(browser.ver);
} else if (/Version\/(\S+)/.test(ua)) {
browser.ver = RegExp["$1"];
browser.safari = parentFloat(browser.ver);
} else {
//近似的肯定版本號
let safariVersion = 1;
if (engine.webkit < 100) {
let safariVersion = 1;
} else if (engine.webkit < 312) {
let safariVersion = 1.2;
} else if (engine.webkit < 412) {
let safariVersion = 1.3;
} else {
let safariVersion = 2;
}
browser.safari = browser.ver = safariVersion;
}
} else if (/KHTML\/(\S+)/.test(ua) || /Konqueror\/([^;]+)/.test(ua)) {
engine.ver = browser.ver = RegExp["$1"];
engine.khtml = browser.konq = parseFloat(engine.ver);
} else if (/rv:([^\)]+)\) Gecko\/\d{8}/.test(ua)) {
engine.ver = RegExp["$1"];
engine.gecko = parseFloat(engine.ver);
// 肯定是否是firefox
if (/Firefox\/(\S+)/.test(ua)) {
browser.ver = RegExp["$1"];
browser.firefox = parseFloat(browser.ver);
}
} else if (/MSIE ([^;]+)/.test(ua)) {
engine.ver = browser.ver = RegExp["$1"];
engine.ie = browser.ie = parseFloat(engine.ver);
}
// 檢測瀏覽器
browser.ie = engine.ie;
browser.opera = engine.opera;
// 檢測平臺
let p = navigator.platform;
system.win = p.indexOf("Win") == 0;
system.mac = p.indexOf("Mac") == 0;
system.x11 = (p == "x11") || (p.indexOf("Linux") == 0);
// 檢測window操做系統
if (system.win) {
if (/Win(?:dows)?([^do]{2})\s?(\d+\.\d+)?/.test(ua)) {
if (RegExp["$1"] == "NT") {
switch(RegExp["$2"]) {
case "5.0":
break;
case "5.1":
system.win = "XP";
break;
case "6.0":
system.win = "Vista";
break;
case "6.1":
system.win = "7";
break;
default:
system.win = "NT";
break;
}
} else if (RegExp["$1"] == "9x") {
system.win = "ME";
} else {
system.win = RegExp["$1"];
}
}
}
// 移動設備
system.iphone = ua.indexOf("iPhone") > -1;
system.ipod = ua.indexOf("iPod") > -1;
system.ipad = ua.indexOf("ipad") > -1;
system.nokiaN = ua.indexOf("NokiaN") > -1;
// windows mobile
if (system.win == "CE") {
system.winMobile = system.win;
} else if (system.win == "Ph") {
if (/Windows Phone OS (\d+.\d+)/.test(ua)) {
system.win = "Phone";
system.winMobile = parseFloat(RegExp["$1"]);
}
}
// 檢測ios版本
if (system.mac && ua.indexOf("Mobile") > -1) {
if (/CPU (?:iphone)?OS (/d+_\d+)/.test(ua)) {
system.ios = parseFloat(RegExp.$1.replace("_", "."));
} else {
system.ios = 2; //不能正確檢測出來,只能猜想
}
}
// 檢測android
if (/Android (\d+\.\d+)/.test(ua)) {
system.android = parsentFloat(RegExp.$1);
}
// 遊戲系統
system.wii = ua.indexOf("Wii") > -1;
system.ps = /playstation/i.test(ua);
// 返回檢測對象
return {
engine: engine,
browser: browser,
system: system
}
}();
複製代碼
let arrayNodes = Array.prototype.slice.call(someNode.childNodes, 0);
複製代碼
1.appendChild() //用於向childNodes末尾添加一個節點,返回新增的節點,若是節點已存在,那麼就是從原來的位置移動到新位置
2.insertBefore() //將節點插入指定位置,接收兩個參數,要插入的節點和做爲參照的節點,返回插入的節點
3.replaceChild() //替換指定節點,接收2個參數,要插入的節點和要替換的節點,返回被移除的節點
4.removeChild() //移除節點,返回被移除的節點
5.cloneNode([true]) //參數爲true,執行深複製,複製節點及整個子節點,爲false時複製節點自己。cloneNode不會複製節點的javascript屬性,但IE在此存在一個bug,因此建議在複製以前最好先移除事件處理程序
複製代碼
Node.firstChild[lastChild | parentChild | nextSibling | previousSibling]
複製代碼
1. document的節點類型nodeType的值爲9;
2. document.documentElement // 取得對<html>的引用
3. document.body // 取得對body的引用
4. document.title // 取得文章標題
5. document.title = "xxx" //設置文章標題
6. document.URL //取得完整的url
7. document.domain //取得域名
8. document.referrer //取得來源頁面的url
複製代碼
1.nodeType值爲:1
2.nodeName的值爲元素標籤名
3.tagName // 元素標籤名,返回大寫值,比較時通常採用 element.tagName.toLowerCase()
4.取得元素屬性 getAttribute() / setAttribute() / removeAttribute()
// 注:自定義屬性經過點語法訪問時會返回undefined
5.attributes // 獲取元素的屬性集合,訪問方法: element.attributes[i].nodeName / element.attributes[i].nodeValue
6.建立元素 // document.createElement("div" | "<div class=\"box\">aaa</div>")
7.建立文本子節點 // document.createTextNode("Hello world")
複製代碼
1.nodeType值爲:11
2.建立文檔片斷 document.createDocumentFragment()
// let fragment = document.createDocumentFragment()
複製代碼
// ie9+支持
1.childElementCount // 返回子元素的個數
2.firstElementChild // 指向第一個子元素
3.lastElementChild // 指向最後一個子元素
4.previousElementSibling // 指向前一個同輩元素
5.nextElementSibling // 指向後一個同輩元素
複製代碼
classList
1.classList.length // 返回包含元素的個數
2.classList.remove() //接收一個類名,從列表中刪除給定類名
3.classList.toggle() //若是列表中存在給定的值,刪除它,不然添加它
4.classList.add() //將給定的字符串添加到列表中,若是已經存在,就不添加
5.classList.contains() //代表列表中是否存在給定的值,存在則返回true,不然返回false
複製代碼
元素得到焦點的方式有: 頁面加載,用戶輸入,在代碼中調用focus
1.document.activeElement //始終會引用dom中得到焦點的元素,文檔剛剛加載完成時,保存的是document.body元素的引用,文檔加載期間的值爲null
2.document.hasFocus() //用於肯定文檔是否得到了焦點,是則返回true
複製代碼
readyState屬性
1.loading //正在加載文檔,能夠在onload外使用
2.complete //文檔加載完畢。只能在onload內獲取
// 例子
if(document.readyState == "complete") {
// 執行操做
}
複製代碼
insertAdjacentHTML()
// 1.做爲前一個同輩元素被插入
el.insertAdjacentHTML('beforebegin', '<p>hello world</p>');
// 2.做爲第一個子元素被插入
el.insertAdjacentHTML('afterbegin', '<p>hello world</p>');
// 3.做爲最後一個子元素被插入
el.insertAdjacentHTML('beforeend', '<p>hello world</p>');
// 4.做爲後一個同輩元素被插入
el.insertAdjacentHTML('afterend', '<p>hello world</p>');
複製代碼
// 獲取元素集合,只包含元素節點
el.children.length | el.children[i]
複製代碼
// 例子
parentEl.contains(childEl); // 若是childEl是parentEl的後代,則返回true
複製代碼
// 訪問內聯框架的文檔對象,若是內聯框架來自不一樣域或者不一樣協議,訪問該文檔時會報錯
let iframe = document.getElementById("iframe");
let iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
複製代碼
1.偏移量
1.offsetHeight/offsetWidth // 元素寬高,包括滾動條,邊框
2.offsetLeft/offsetTop // 元素外邊框到包含元素內邊框的距離
3.offsetParent //保存着包含元素的引用(具備大小的包含元素的引用)
// 獲取元素在頁面中的偏移量
function getElLeft(el){
let actualLeft = el.offsetLeft;
let current = el.offsetParent;
while(current !== null){
actualLeft += current.offsetLeft;
current = current.offsetParent;
}
return actualLeft
}
// 注: 這些偏移量都是隻讀的,每次訪問都要從新計算,所以最好將其保存到局部變量裏,以提升性能
2.客戶區大小clientWidth/clientHeight(元素內容及內邊距所佔據的空間)
獲取視口大小 clientW = document.body.clientWidth || document.documentElement.clientWidth;
3.滾動區大小
1.scrollHeight //在沒有滾動條的狀況下,元素內容總高度(內容+內邊距)
2.scrollWidth
3.scrollLeft //被隱藏在內容區域左側的像素數
4.scrollTop //被隱藏在內容區域上方的像素數,經過設置該值可讓滾動條滾動到響應位置
*** 肯定文檔總高度兼容方案
let scrollH = document.documentElement.scrollHeight || document.body.scrollHeight;
let clientH = document.documentElement.clientHeight || document.body.clientHeight;
let docHeight = Math.max(scrollH, clientH);
4.肯定元素大小 getBoundingClientRect()
該方法返回一個矩形對象,包括left,top,right,bottom屬性,表示元素在頁面中相對於視口的位置
複製代碼
1. 屬性或方法
type // 被觸發的事件類型
target // 事件的目標
currentTarget // 事件處理程序當前正在處理事件的那個元素
注: 在事件處理程序內部,對象this始終等於currentTarget的值,而target只包含事件的實際目標
*** 一個函數處理多個事件可使用switch(event.type)的方式
event.preventDefault() // 阻止事件的默認行爲
event.stopPropagation() // 阻止事件冒泡
複製代碼
1.鼠標和滾輪事件
1.客戶區座標位置clientX/clientY //表示事件發生時鼠標指針在視口中的水平和垂直位置
2.頁面座標位置 pageX/pageY //表示事件在頁面中發生的位置
3.屏幕座標位置 //獲取事件發生時在屏幕中的位置
2.修改鍵(若是用戶在觸發事件時按下了shift/ctrl/alt/Meta,則返回true)
event.shiftkey | event.altKey | event.metaKey | event.ctrlKey
3.鼠標按鈕(event.button)
// 對於mousedown和mouseup,其event中存在一個button屬性,值爲0表示主鼠標按鈕,1表示中間鼠標按鈕,2表示次鼠標按鈕
4.鼠標滾輪事件(mousewheel)
1.兼容方案:
let getWheelDelta = function(event){
let wheelDelta = event.wheelDelta ? event.wheelDelta : (-event.detail * 40);
return wheelDelta
}
*** 注:document在普通瀏覽器中經過mousewheel監聽鼠標滾輪事件,在火狐中使用DOMMouseScroll監聽
5.鍵盤與文本事件
6.變更事件
1.DOMSubtreeModified | DOMNodeInserted | DOMNodeRemoved
*例子
el.addEvent("DOMSubtreeModified", fn1)
7.HTML5事件
1.contextmenu事件(自定義上下文菜單)
2.DOMContentLoaded事件(在造成完整dom樹以後就觸發,不理會圖像,js文件,css文件等資源是否下載完成)
3.hashchange事件(在URL的參數列表發生變化【即#號後面的全部字符串】時觸發)
注:必需要把hashchange添加給window對象,event對象包含兩個屬性oldURL和newURL,分別保存着參數列表變化先後的完整URL
// 例子
window.addEvent("hashchange", function(event){
// oldURL和newURL存在兼容問題,最好用location.hash代替
console.log(event.oldURL, event.newURL);
})
複製代碼
若是在頁面寫在以前沒有清理乾淨事件處理程序,那他們就會滯留在內存中,每次加載完頁面再卸載時,內存中滯留的對象就會增長,由於事件處理程序佔用的內存並無被釋放。 【解決方案】再頁面卸載以前,先經過onunload事件處理程序移除全部事件處理程序。可是使用onunload時頁面不會被緩存bfcache(即往返緩存)中。
// ie9+ 爲被選擇的元素添加了兩個屬性,selectionStart和selectionEnd,保存的是基於零的數值,表示所選的文本範圍
function getSelectedText(textbox){
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd)
}
複製代碼
// 全部文本框都有一個setSelectionRange(startIndex, endIndex)
textbox.setSelectionRange(0, 3)
複製代碼
1.屏蔽字符
// 經過阻止鍵盤按壓事件的默認行爲來屏蔽字符
el.addEvent("keypress",function(event){
let charCode = event.charCode;
// String.fromCharCode(charCode) 將字符編碼轉換爲字符串
if(!/\d/.test(String.fromCharCode(charCode))){
event.preventDefault();
}
}, false)
複製代碼
1.使用contenteditable屬性 1.有三個屬性: true,false,inherit 2.例子:
2.操做富文本document.execCommand()
三個參數: 要執行的命令的名稱,表示瀏覽器是否爲當前命令提供用戶界面的一個布爾值,執行命令必須的一個值(若是不須要值,則爲null)
3.表單與富文本 *** 要想將富文本中的值傳遞給表單,則可在表單內建立一個隱藏的表單字段,將富文本的值賦給該表單字段的值
主要指來源於不一樣域的頁面間的消息傳遞,主要利用iframe
// 源頁面
window.onload = function(){
// 獲取源頁面iframe的內容window對象
var iframeWindow = document.querySelector("#iframe").contentWindow;
// 向iframe發送消息,並指定源的地址,兩個參數必填
iframeWindow.postMessage("xujiang", "http://127.0.0.1:5500");
var mesWrap = document.querySelector(".mes-wrap");
// 接收iframe傳來的消息
window.addEventListener("message",function(e){
// alert(e.data);
mesWrap.innerHTML = e.data;
iframeWindow.postMessage("你叫什麼?", "http://127.0.0.1:5500");
},false);
}
// iframe頁面,監聽其餘域傳來的消息
window.addEventListener("message",function(e){
// 向發送消息的域反饋消息,event對象的屬性以下:
// data 傳入的字符串數據
// origin 發送消息的文檔所在的域
// source 發送消息的文檔的window的代理
e.source.postMessage("hello", "http://127.0.0.1:5500");
},false);
複製代碼
// 使用video,audio元素的play()和pause()方法,能夠手工控制媒體的播放
// 根據媒體元素的屬性,咱們能夠本身實現一個視頻,音頻播放器
複製代碼
// ajax
var xhr = new XMLHttpRequest(); // 建立xhr對象
// 第一個方法:open(get | post等, "exam.php", false) 參數爲請求類型,請求url,是否異步的boolean
xhr.open("get","exam.php", false); // 調用該方法並非真正的請求,而是請求一個請求以備發送
// 發送真正的請求,接收一個參數,即做爲請求主體要發送的數據,不發送數據時必須傳遞null,由於對於某些瀏覽器來講該參數是必須的
xhr.send(null)
// 檢驗響應的狀態--->針對同步
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
var data = xhr.responseText;
}else{
console.log(xhr.status);
}
// 異步方案
xhr.onreadystatechange = function(){
// xhr.readyStatus表示請求/響應過程的當前活動階段
// 0 未初始化,還沒調用open()
// 1 啓動,已調用open()方法但未調用send()
// 2 發送, 已調用send()方法,但未收到響應
// 3 接收,已接收到部分響應數據
// 4 完成,已接受到所有響應數據
if(xhr.readyStatus == 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
var data = xhr.responseText;
}else{
console.log(xhr.status);
}
}
}
xhr.open("get","exam.php", false);
xhr.send(null);
// 在接收到響應以前還能夠取消異步請求
xhr.abort() // 在中止請求以後還應該進行解引用操做,防止內存堆積
// 設置http請求頭,必須放在open和send中間
xhr.open("get","exam.php", false);
xhr.setRequestHeader("accept", "application/json; charset=utf-8")
xhr.send(null);
// 獲取響應頭信息
xhr.getResponseheader("accept");
xhr.getAllResponseHeaders();
// get請求:向現有url中添加查詢字符串
function addUrlParam(url, name, value){
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
}
// post請求:模擬表單提交
xhr.open("get","exam.php", false);
// 設置提交時的內容類型
xhr.setRequestHeader("content-Type", "application/x-www-form-urlencoded")
// 假設表單form對象已獲取
xhr.send(serialize(form));
// XHR2級 -- formData --序列化表單以及建立和表單格式相同的數據(用於經過xhr傳輸)
var data = new FormData();
data.append(key,value);
// 也就能夠用表單元素的數據預先填入數據
var data = new FormData(document.forms[0]);
//使用FormData的好處在於沒必要明確地在xhr上設置請求頭部
xhr.send(new FormData(form));
// 進度事件
loadStart/progress/error/abort/load
// 跨域資源共享CORS
核心思想: 使用自定義的http頭部讓瀏覽器和服務器進行溝通,從而決定請求是成功仍是失敗
原理:
1.請求頭指定源:Origin: http://www.baidu.com
2.若是服務器認爲這個請求能夠接受,就在Access-Control-Allow-Origin頭部回發相同的源信息
Access-Control-Allow-Origin:http://www.baidu.com
(若是是公共資源,能夠回發「*」)
3.若是沒有這個頭部,或者有這個頭部可是源信息不匹配,瀏覽器就會駁回請求
// 主流瀏覽器對cros的實現方式: 在url中使用絕對路徑,但有限制:不能設置自定義頭部,不能發送和接收cookie,獲取不到getAllResponseHeaders()的返回值
// 帶憑據的請求
withCredentials屬性設置爲true
// 服務器接收到帶憑據的請求後,會用下面的頭部來請求,若是響應不包含這個頭部,瀏覽器將不會把響應數據交給js
Access-Control-Allow-Credentials: true
// 跨瀏覽器的cros
function createCORSRequest(method,url){
var xhr = new XMLHttpRequest();
if("withCredentials" in xhr){
xhr.open(method,url,true);
}else if(typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method,url);
}else{
xhr = null;
}
return xhr
}
var req = createCORSRequest("get","http://www.baidu.com/page/");
if(req){
req.onload = function(){
// 對響應數據進行處理
};
req.send();
}
// 以上提供的公共方法有
// abort() 用於中止正在進行的請求
// onerror 用於替代onreadystatechange檢驗錯誤
// onload 用於替代onreadystatechange檢驗成功
// responseText 用於取得響應內容
// send() 用於發送請求
// 其餘跨域技術
1.圖像ping---經常使用於跟蹤用戶點擊頁面和動態廣告曝光數,只能get請求
var img = new Image();
img.onload = img.onerror = function(){
// 操做
}
img.src = "http://baidu.com?name=xujaing";
2.JSONP---能夠直接訪問響應文本,能夠在瀏覽器和服務器之間進行雙向通訊,但有安全隱患
function handleResponse(data){
console.log(data);
}
var script = document.createElement("script");
script.src = "http://a.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);
3.Comet (服務器推送SSE)
經常使用的技術有長輪詢和流
4.Web Sockets
複製代碼
//安全類型檢測
function isArray(value){
return Object.prototype.toString.call(value) == "[object Array]";
}
// 注:在ie中在以COM對象形式實現的任何函數,isFunction()都將返回false
function isFunction(value){
return Object.prototype.toString.call(value) == "[object Function]";
}
// 使用做用域安全的構造函數
// 惰性載入函數
// 函數綁定 會佔用更多內存,因此只在必要時使用
function bind(fn, context){
return function(){
return fn.apply(context, arguments);
}
}
// ES5提供了原生的綁定方法:obj.bind(this);
// 函數柯里化
function curry(fn){
var args = Array.prototype.slice.call(arguments, 1);
return function(){
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs)
}
}
// 使用
function add(n1,n2){
return n1 + n2
}
var curriedAdd = curry(add, 5);
console.log(curriedAdd,5);
複製代碼
// 不可擴展對象,使用該方法可讓傳入的對象禁止添加屬性和方法
Object.preventExtensions(obj);
// 使用Object.isExtensible(obj)能夠判斷對象是否可擴展
Object.isExtensible(obj);
// 密封的對象,不可擴展,不能刪除,但能夠修改
object.seal(obj);
// 使用Object.isSealed()能夠肯定對象是否密封
Object.isSealed(obj);
// 凍結的對象,不可擴展,密封,不能修改,訪問器屬性可寫
Object.freeze(obj);
複製代碼
// 函數節流
function throttle(method,context){
clearTimeout(method.tId);
method.tId = setTimeout(function(){
method.call(context);
}, 100)
}
複製代碼
function EventTarget(){
this.handlers = {};
}
EventTarget.prototype = {
constructor: EventTarget,
addHandler: function(type, handler){
if(typeof this.handlers[type] == "undefined"){
this.handlers[type] = [];
}
this.handlers[type].push(handler);
},
fire: function(event){
if(!event.target){
event.target = this;
}
if(this.handlers[event.type] instanceof Array){
var handlers = this.handlers[event.type];
for(var i=0,len=handlers.length;i<len;i++){
handlers[i](event);
}
}
},
removeHandler: function(type, handler){
if(this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
for(var i=0, len=handlers.length; i<len; i++){
if(handlers[i] === handler){
break;
}
}
handlers.splice(i, 1);
}
}
}
複製代碼
// 離線檢測屬性
navigator.onLine // true or false
// 離線事件
online,offline
複製代碼
// 描述文件: offline.manifest,列出要下載和緩存的資源
// ***文件擴展名之前推薦manifest,如今推薦用appcache
CACHE MANIFEST
#Comment
file.js
file.css
// 與html文檔關聯
<html manifest="/offline.manifest">
複製代碼
(function(){
function draw(timestamp){
// 計算兩次重繪的時間間隔
var drawStart = (timestamp || Date.now()),
diff = drawStart - startTime;
// 使用diff肯定下一步的繪製時間
// 把startTime重寫爲這一次的繪製時間
startTime = drawStart;
// 重繪UI
requestAnimationFrame(draw);
}
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame,
startTime = window.mozAnimationStartTime || Date.now();
requestAnimationFrame(draw);
})();
複製代碼
//經過監聽change事件並讀取files集合,就能夠知道每一個文件信息
fileList.addEventListener("change", function(event){
var files = event.target.files,
i=0,
len = files.length;
while(i<len){
console.log(files[i].name, files[i].type, files[i].size);
i++;
}
}, false);
// FileReader類型
reader = new FileReader();
while(i<len){
// reader.readAsDataURL(files[0]);
reader.readAsText(files[0]);
// reader.readAsBinaryString(files[0]);
//reader.readAsArrayBuffer(files[0]);
// 因爲讀取是異步的,因此支持load,error,progress等事件,progress在當讀取了新數據是觸發,每50ms觸發一次
// 觸發error事件時會將相關信息保存在error屬性中,該屬性保存了一個對象,只有一個屬性code, 1表示未找到文件,2表示安全性錯誤,3表示讀取中斷,4表示文件不可讀
reader.onload = function(){
// 讀取結果存在result屬性中
console.log(reader.result);
}
// 若是想中斷讀取,能夠調用absort()方法,此時會觸發loadend事件
// console.log(files[i].name, files[i].type, files[i].size);
i++;
}
// 讀取部份內容--file對象支持slice屬性
function blobSlice(blob, startByte, length){
// blob爲文件對象,startByte爲起始字節,length爲要讀取的字節數
if(blob.slice){
return blob.slice(startByte, length)
}else if(blob.webkitSlice){
reutrn blob.webkitSlice(startByte, length)
}else if(blob.mozSlice){
return blob.mozSlice(startByte, length)
}else{
retun null
}
}
var reader = new FileReader(),
blob = blobSlice(files[0], 0, 32);
if(blob){
reader.readAsText(blob);
}
// 對象URL -- 指的是引用保存在File或Blob中數據的URL
function createObjectURL(blob){
if(window.URL){
return window.URL.createObjectURL(blob);
}else if(window.webkitURL){
return window.webkitURL.createObjectURL(blob);
}else{
return null
}
}
var url = createObjectURL(files[0]);
if(url){
img.src = url;
}
// 手工釋放window.URL內存
function revokeObjectURL(url){
if(window.URL){
window.URL.revokeObjectURL(url);
}else if(window.webkitURL){
window.webkitURL.revokeObjectURL(url);
}
}
// 讀取拖放的文件
//使用XHR上傳文件-- 利用FormData對象
複製代碼
// 頁面worker
var worker = new Worker("work.js");
worker.postMessage("hello");
worker.onmessage = function(event){
var data = event.data;
alert(data)
}
worker.onerror = function(event){
console.log("Error:" + event.filename,event.lineno,event.message);
}
// 任什麼時候候只要調用terminate()方法就能夠中止worker工做
// work對象內部 work.js
// importScripts會保證引入文件的前後順序執行,但下載是異步的
importScripts("k1.js","k2.js");
// k1.js中定義b=1,此時能夠直接引用k1,k2中定義的變量和方法
// work對象的全局對象:
// navigator對象:包含onLine,appName,appVersion,userAgent,platform
// 只讀的location
// setTimeout,setInterval,clearTimeout,clearInterval
// XMLHttpRequest構造函數
self.onmessage = function(event){
var data = event.data;
self.postMessage(c);
}
複製代碼
明天將推出CMS全棧的Node部分的實現。包括:
後期將更詳細的介紹系統的具體實現過程和細節以及服務器相關的配置,包括項目的開源地址我會在十一以前告訴你們,歡迎在公衆號《趣談前端》加入咱們一塊兒討論。