一、面向對象的程序設計
1. 屬性類型
// 1.數據屬性 object.defineproperty(屬相所在的對象,屬性名,(4種))
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;
}
}
})
2.創建對象
原型理解:
1.isPrototypeOf()-------確認對象之間有沒有原型關係
2.Object.getPrototypeOf()-------獲取實例對象的原型
3.我們不能通過實例重寫原型中的值,只能訪問,並且如果實例和原型有相同的屬性名,則會覆蓋原型中的屬性。
4.hasOwnProperty()-----檢測一個屬性是否在實例中
5.原型與in操作符:“name" in person:對象能訪問到給定屬性時返回true
6.Object.key(obj)---返回一個可以包含所有可枚舉的屬性
7.Object.getOwnPropertyNames() ---返回所有的實例屬性,包括不可枚舉的
8.實例中的指針只指向原型,而不是構造函數。 var person1=new Person() 那person1中的指針只指向Person.prototype 即 person1._proto_=Person.prototype
- 組合(構造函數模式和原型模式):用構造函數定義實例屬性,用原型定義方法和共享屬性。
3.繼承
1.原型鏈的問題
1.包含引用類型值的原型屬性會被所有實例共享,在通過原型實現繼承時,原型實際上會變成另一個類型的實例,原先的實例屬性變成了現在的原型屬性。
2.在創建子類型的實例時,無法向父類構造函數傳遞參數
function Parent(name){
this.name=name;
}
function Child(){
}
Child.prototype=new Parent('zhangsan');
var p=new Chlid();//構造出來子類的實例沒有辦法向父類傳參。
p.name;//可以繼承父類的屬性和方法
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);//1
this.age = 13;
}
Child.prototype = new Parent();//2
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方法的第二個參數格式相同)
A=Object.create(person, {//A._proto_=Person
name: {
value: "xujiang"
}
})
5.寄生組合式繼承(通過借用構造函數繼承屬性,通過原型鏈混成的方式繼承方法)---最理想的繼承範式
function inheritPrototype(sub,sup){
let prototype = Object.create(sup.prototype);//prototype._proto_=sup.prototype
prototype.constructor = sub;
sub.prototype = prototype;
}
function Sup(){}
Sup.prototype.say = function(){}
function Sub(arg){
// 關鍵
Sup.call(this,arg);//var sub=new sup()
}
// 關鍵
inheritPrototype(Sub, Sup);
二、函數表達式
閉包與變量
閉包:可以訪問定義它們的外部函數的參數和變量(除了this和arguments)。
閉包的優點:封裝私有變量,形成塊級作用域。
缺點:內存泄漏佔用內存。
function a(){
let el = $("#el");
let id = el.id;
el.click(function(){
alert(id)
})
// 清空dom,釋放內存
el = null;
}
三、BOM對象
Location對象:
// 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中查詢字符串,以問號開頭
navigator對象:
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 // 檢測瀏覽器中安裝的插件的數組
history對象:
1. history.go(0 | [123] | -1 | str) // 如果是Str,則會跳轉到歷史記錄中包含該字符串的第一個位置
2. history.back() //後退一頁
3. history.forward() //前進一頁
4. history.length // 保存着歷史紀錄的數量
四、DOM對象
1.將對象轉化成數組 Array.prototype.slice.apply(arguments,[0]);
2.將字符串轉化成數組:str.split(’ ')//split轉化成字符串數組
1.appendChild() //用於向childNodes末尾添加一個節點,返回新增的節點,如果節點已存在,那麼就是從原來的位置移動到新位置
2.insertBefore() //將節點插入指定位置,接收兩個參數,要插入的節點和作爲參照的節點,返回插入的節點
3.replaceChild() //替換指定節點,接收2個參數,要插入的節點和要替換的節點,返回被移除的節點
4.removeChild() //移除節點,返回被移除的節點
5.cloneNode([true]) //參數爲true,執行深複製,複製節點及整個子節點,爲false時複製節點本身。cloneNode不會複製節點的javascript屬性,但IE在此存在一個bug,所以建議在複製之前最好先移除事件處理程序
document類型:
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
element類型:
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.偏移量
offsetParent:獲取元素的最近的具有定位屬性(absolute或者relative)的父級元素。如果都沒有則返回body
offsetHeight:元素在垂直方向上佔用的空間大小。包括元素的高度、(可見的)水平滾動條的高度、上邊框高度和下邊框高度。(不包括外邊框margin)
offsetWidth:元素在水平方向上佔用的空間大小。包括元素的寬度、(可見的)垂直滾動條的寬度、左邊框寬度號右邊框寬度。
offsetLeft:元素的左外邊框至父元素的左內邊框之間的像素距離。
offsetTop:元素的上外邊框至父元素的上內邊框之間的像素距離。
2.客戶區的大小
clientWidth:元素內容區寬度加上左右內邊距寬度。可以通過document.body。clientWidth來獲取瀏覽器視口的大小。
clientHeight:元素內容區高度加上上下內邊距高度
3.滑動大小
scrollHeight:元素內容的實際總高度
scrollWidth:元素內容實際總寬度
scrollLeft:被隱藏的內容區域左側的像素數。通過設置這個屬性可以改變元素的滾動的位置
scrollTop:被隱藏的內容區域上方的像素數。通過設置這個屬性可以改變元素的滾動位置
六、事件
1.事件對象event
1. 屬性或方法
type // 被觸發的事件類型
target // 事件的目標 觸發事件的元素li
currentTarget // 事件處理程序當前正在處理事件的那個元素 邦定事件的元素ul
注: 在事件處理程序內部,對象this始終等於currentTarget的值,而target只包含事件的實際目標
*** 一個函數處理多個事件可以使用switch(event.type)的方式
event.preventDefault() // 阻止事件的默認行爲
event.stopPropagation() // 阻止事件冒泡
2.事件類型
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 vue的路由就是這個機制 通過haschange來監聽url的變化,實現url改變但是不刷新頁面的多頁面的效果
// 例子
window.addEvent("hashchange", function(event){
// oldURL和newURL存在兼容問題,最好用location.hash代替
console.log(event.oldURL, event.newURL);
})
3.性能問題
當你卸載頁面時,事件處理佔用的內存沒有釋放。所以在卸載之前通過unonload事件移除所有事件的處理程序。並且不會保存在緩存中。
七、跨域文檔傳遞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);
八、ajax和cors
// 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
九、高級技巧
1.高級函數
1.Object.prototype.toString.call(value) == "[object Array]";//檢測數據類型
2.//原生實現bind 柯理化思想
//1.this 指向 apply /call2.參數形式 可以通過call(參數多)和apply實現(apply更方便)3.返回一個待執行的函數 閉包
function testBind(that){
var _this=this;
var args=Array.prototype.slice.apply(arguments,[1]);//通過slice將arguments轉換成數組,取得bind的除第一個參數以外的參數
return function(){
return _this.apply(that,args.concat(Array.prototype.slice.apply(arguments,[0])))
}
}
2.高級定時器
//防抖
function decouce(fn,wait){
var timer=null;
return function(){
clearTimeout(timer);
var timer=setTimeout(()=>{
fn();
},wait);
}
}
//節流
function throttle(fn,time,wait){
var pre=null;
var timer=null;
var now=new Date();
if(pre==undifined) pre=now;
if(now-pre>time){
clearTimeout(timer);
fn();
pre=now;
}else{//小於time那麼在wait內再執行一次
clearTimeout(timer)
timer=setTimerout(()=>{
fn();
},wait)
}
}
十、新的API
1.requestAnimationFrame():計時器不需要設置時間間隔,比其他兩種精準
(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);
})();
https://www.cnblogs.com/AI-fisher/p/11178130.html
https://zhuanlan.zhihu.com/p/84326290