該標籤可聲明三種DTD類型,分別表示嚴格版本、過渡版本以及基於框架的HTML版本。css
<!DOCTYPE>的用法:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
解析:在上面的聲明中,聲明瞭文檔的根元素是 html,它在公共標識符被定義爲 "-//W3C//DTD XHTML 1.0 Strict//EN" 的 DTD 中進行了定義。瀏覽器將明白如何尋找匹配此公共標識符的 DTD。若是找不到,瀏覽器將使用公共標識符後面的 URL 做爲尋找 DTD 的位置。
-:表示組織名稱未註冊。Internet 工程任務組(IETF)和萬維網協會(W3C)並不是註冊的 ISO 組織。
+爲默認,表示組織名稱已註冊。
DTD: 指定公開文本類,即所引用的對象類型。 默認爲DTD。
HTML: 指定公開文本描述,即對所引用的公開文本的惟一描述性名稱。後面可附帶版本號。默認爲HTML。
URL: 指定所引用對象的位置。
Strict:排除全部 W3C 專家但願逐步淘汰的表明性屬性和元素。
複製代碼
簡單的來講是爲了統一規則,共同使用了標準通用標記語言(SGML)的一種約定,來告訴瀏覽器使用的是哪種編程規範(DTD)。HTML5 不基於 SGML,因此不須要引用 DTD。HTML5提供的<!DOCTYPE html>
是標準模式,向後兼容的, 等同於開啓了標準模式,而且向後兼容。html
語義化的含義就是用正確的標籤作正確的事情,HTML語義化就是讓頁面的內容結構化,便於對瀏覽器、搜索引擎解析;在沒有樣式CCS狀況下也以一種文檔格式顯示,而且是容易閱讀的。搜索引擎的爬蟲依賴於標記來肯定上下文和各個關鍵字的權重,利於 SEO。使閱讀源代碼的人對網站更容易將網站分塊,便於閱讀維護理解。前端
HTML5添加了不少新的語法特徵其中包括<video>
、<audio>
和<canvas>
元素,同時集成了SVG內容。這些元素是爲了更容易的在網頁中添加和處理多媒體和圖片內容而添加的。其它新的元素如<section>
、<article>
、<header>
、和<nav>
則是爲了豐富文檔的數據內容。新的屬性的添加也是爲了一樣的目的。vue
HTML5除了更新了不少新的語義化標籤也有不少新標籤和特性: W3school裏邊有詳細的介紹。能夠大體的瞭解一下。重點關注<video>
、<audio>
、<canvas>
、localStorage
和sessionStorage
。html5
BOM是指瀏覽器對象模型,是用於描述這種對象與對象之間層次關係的模型,瀏覽器對象模型提供了獨立的內容的、可與瀏覽器窗口進行互動的對象結構。 詳情參考 node
DOM全稱DocumentObjectModel(文檔對象模型),是爲HTML和XML提供的API的標準。 本文說的DOM默認爲HTMl DOM。 jquery
CSS是前端三大件之一,一個頁面是否美觀CSS起到了決定性的做用。css3
通配符*{color: red;}
;nginx
元素選擇器div{color : red}
;git
類選擇器.high{color: red;}
;
id選擇器#test{color: red;}
;
並聯選擇器div, .high{color: red;}
;
複合選擇器div.high{background-color: green}
;
後代選擇器div p {background-color: blue;}
;
子元素選擇器h1 > strong {color:red;}
;
相鄰兄弟選擇器h1 + p {margin-top:50px;}
屬性選擇器a[href] {color:red;}
;
動態僞類選擇器:詳情請看大漠老師的僞類選擇器
.demo a:link {color:gray;}/*連接沒有被訪問時前景色爲灰色*/
.demo a:visited{color:yellow;}/*連接被訪問事後前景色爲黃色*/
.demo a:hover{color:green;}/*鼠標懸浮在連接上時前景色爲綠色*/
.demo a:active{color:blue;}/*鼠標點中激活連接那一下前景色爲藍色*/
複製代碼
通俗的講:從0開始,一個行內樣式+1000,一個id+100,一個屬性選擇器/class或者僞類+10,一個元素名,或者僞元素+1。
能夠參考大漠老師的這篇文章你應該知道的一些事情——CSS權重。
CSS盒子模型是經典面試題之一,回答這個問題首先要了解什麼是盒子模型:簡單地說每一個html標籤都是一個方塊,而後這個方塊又包着幾個小方塊。分別是:margin、border、padding、content。它們的關係是margin包着border包着padding包着content。就像盒子一層一層地包着同樣,這就是咱們所說的盒模型。
CSS盒子模型包括w3c標準盒子模型和怪異盒子模型又叫IE盒子模型,他們的差異在於:在w3c和模型中,設置的width/height是content的寬度/高度,在怪異模式中width/height設置的是content+padding+border寬度/高度。
div{display:table-cell; width:1em; height:1em; border:1px solid #beceeb; font-size:144px; text-align:center; vertical-align:middle;}
div img{vertical-align:middle;}
複製代碼
原來一直不是很清楚深拷貝和淺拷貝,在掘金上看了一篇文章js 深拷貝 vs 淺拷貝之後豁然開朗。弄明白這兩個概念的時候須要瞭解什麼是內存管理,任何一門計算機語言都會有內存管理機制,一樣的js也不例外。js的內存管理機制是:JavaScript建立變量(對象,字符串等)時分配內存,而且在再也不使用它們時「自動」釋放。 後一個過程稱爲垃圾回收。js內存空間分爲棧(stack)、堆(heap)。其中棧存放變量,堆存放複雜對象。
這些值都有固定的大小,每每都保存在棧內存中(閉包除外),由系統自動分配內存空間。咱們能夠直接操做保存內存空間的值,所以基礎數據類型都是按值訪問,數據在棧內存中的存儲與使用方法相似於數據結構中的堆棧數據結構,遵循後進先出的原則。(基礎數據類型:Number、String、Null、Undefined、Boolean、symbol)。
他們值的大小都不是固定的。引用數據類型的值是保存在堆內存中的對象,變量其實是存放在棧內存的指針,這個指針指向堆內存中的地址。
var a1 = 0; // 棧
var a2 = 'this is string'; // 棧
var a3 = null; // 棧
var b = { m: 20 }; // 變量b存在於棧中,{m: 20} 做爲對象存在於堆內存中
var c = [1, 2, 3]; // 變量c存在於棧中,[1, 2, 3] 做爲對象存在於堆內存中
複製代碼
不少人認爲賦值就是淺拷貝,這是錯誤的認識;在咱們進行賦值操做的時候,基本數據類型的賦值(=)是在內存中新開闢一段棧內存,而後再將值賦值到新的棧中。這就是值傳遞。
var a = 10;
var b = a;
a ++ ;
console.log(a); // 11
console.log(b); // 10
複製代碼
引用類型則是地址傳遞,將存放在棧內存中的地址賦值給接收的變量。
var obj1 = {
'name' : 'zhangsan',
'age' : '18',
'language' : [1,[2,3],[4,5]],
};
var obj2 = obj1;
var obj3 = shallowCopy(obj1);
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
obj2.name = "lisi";
obj3.age = "20";
obj2.language[1] = ["二","三"];
obj3.language[2] = ["四","五"];
console.log(obj1);
//obj1 = {
// 'name' : 'lisi',
// 'age' : '18',
// 'language' : [1,["二","三"],["四","五"]],
//};
console.log(obj2);
//obj2 = {
// 'name' : 'lisi',
// 'age' : '18',
// 'language' : [1,["二","三"],["四","五"]],
//};
console.log(obj3);
//obj3 = {
// 'name' : 'zhangsan',
// 'age' : '20',
// 'language' : [1,["二","三"],["四","五"]],
//};
複製代碼
先定義個一個原始的對象 obj1,而後使用賦值獲得第二個對象 obj2,而後經過淺拷貝,將 obj1 裏面的屬性都賦值到 obj3 中。也就是說:
obj1:原始數據
obj2:賦值操做獲得 obj3:淺拷貝獲得
而後咱們改變 obj2 的 name 屬性和 obj3 的 name 屬性,能夠看到,改變賦值獲得的對象 obj2 同時也會改變原始值 obj1,而改變淺拷貝獲得的的 obj3 則不會改變原始對象 obj1。這就能夠說明賦值獲得的對象 obj2 只是將指針改變,其引用的仍然是同一個對象,而淺拷貝獲得的的 obj3 則是從新建立了新對象。 然而,咱們接下來來看一下改變引用類型會是什麼狀況呢,我又改變了賦值獲得的對象 obj2 和淺拷貝獲得的 obj3 中的 language 屬性的第二個值和第三個值(language 是一個數組,也就是引用類型)。結果見輸出,能夠看出來,不管是修改賦值獲得的對象 obj2 和淺拷貝獲得的 obj3 都會改變原始數據。 這是由於淺拷貝只複製一層對象的屬性,並不包括對象裏面的爲引用類型的數據。因此就會出現改變淺拷貝獲得的 obj3 中的引用類型時,會使原始數據獲得改變。
深拷貝:將 B 對象拷貝到 A 對象中,包括 B 裏面的子對象,
淺拷貝:將 B 對象拷貝到 A 對象中,但不包括 B 裏面的子對象
Object.assign
Object.assign:用於對象的合併,將源對象(source)的全部可枚舉屬性,複製到目標對象(target),並返回合併後的target。用法: Object.assign(target, source1, source2); 因此 copyObj = Object.assign({}, obj); 這段代碼將會把obj中的一級屬性都拷貝到 {}中,而後將其返回賦給copyObj。 對於Object.assign()而言, 若是對象的屬性值爲簡單類型(string, number),經過Object.assign({},srcObj);獲得的新對象爲‘深拷貝’;若是屬性值爲對象或其它引用類型,那對於這個對象而言實際上是淺拷貝的。這是Object.assign()特別值得注意的地方。{ ...obj }
$.extend( {}, ...)
使用jq中的$.extend(true, {}, ...)
使用lodash中的_.cloneDeepWith(value, [customizer])
JSON對象的parse和stringify
//例1
var source = { name:"source", child:{ name:"child" } }
var target = JSON.parse(JSON.stringify(source));
target.name = "target"; //改變target的name屬性
console.log(source.name); //source
console.log(target.name); //target
target.child.name = "target child"; //改變target的child
console.log(source.child.name); //child
console.log(target.child.name); //target child
//例2
var source = { name:function(){console.log(1);}, child:{ name:"child" } }
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
//例3
var source = { name:function(){console.log(1);}, child:new RegExp("e") }
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined
console.log(target.child); //Object {}
複製代碼
跨域是指一個域下的文檔或者腳本試圖去請求另外一個域下的資源行爲。 跨域問題是因爲瀏覽器的同源策略形成的,同源策略分爲DOM同源策略和XmlHttpRequest同源策略。其中:
1.DOM同源策略是指禁止對不一樣源頁面DOM進行操做。這裏主要場景是iframe跨域的狀況,不一樣域名下的iframe是限制互相訪問的。
2.XMLHttpRequest同源策略是指禁使用XHR對象向不一樣源的服務器地址發起HTTP請求。
只要協議、域名、端口有任何一個不一樣,都被看成是不一樣的域,之間的請求就是跨域操做。
1.跨域資源共享(CORS)
CORS(Cross-Origin Resource Sharing)
跨域資源共享,定義了必須在訪問跨域資源市,瀏覽器與服務器應該如何溝通。CORS背後的基本思想就是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功仍是失敗。
服務器端對於CORS的支持,主要經過設置Access-Control-Allow-Origin
來進行的。若是瀏覽器檢測到相應的設置,就能夠容許Ajax進行跨域的訪問。
2.經過jsonp跨域
jsonp可以跨域的原理是用了<script>
標籤來實現跨域請求的,除了<script>
能夠跨域的表情還包括<link>、<script>、<img>、<frame>等dom標籤,還有樣式中background:url()、@font-face()等文件外鏈也屬於跨域
。jsonp由回調函數和數據兩部分組成,回調函數是當響應到來時應該在頁面中調用的函數,而數據就是傳入回調函數的json數據。 優勢:簡單兼容性比較好,可用於解決主流瀏覽器的跨域訪問問題。 缺點:僅支持get方法具備侷限性,不安全可能會遭受XSS攻擊。
3.document.domain + iframe跨域 4.location.hash + iframe 5.window.name + iframe跨域 6.postMessage跨域 7.nginx代理跨域 8.nodejs中間件代理跨域 9.WebSocket協議跨域
一句話解釋閉包:閉包就是可以讀取其餘函數內部變量的函數。在下面的代碼中f2就是閉包。
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
複製代碼
閉包的主要有兩大用處,一個是能夠讀取函數內部的變量,另外一個就是讓這些變量的值始終保持在內存中。
因爲JavaScript的語言執行環境是「單線程」,因此若是有一個任務比較長就會形成阻塞,爲了解決任務阻塞這個問題,JavaScript將任務的模式分爲:同步和異步。 同步模式就是後一個任務等待前一個任務結束後再執行,程序的響應是與任務的排列順序是一致的、同步的。異步模式徹底不一樣,每個任務有一個或者多個回調函數(callback),前一個任務結束後,不是執行後一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行,因此程序的順序與任務的執行殊勳是不一致的、異步的。
異步編程的4種方法:
1.回調函數
回調函數是異步編程的基本方法。
假設有兩個函數f1和f2,後者等待前者的執行結果。若是f1是一個很耗時的任務,能夠考慮改寫f1,把f2寫成f1的回調函數。
function f1(callback){
setTimeout(function () {
// f1的任務代碼
callback();
}, 1000);
}
複製代碼
採用這樣的方式,把同步操做改爲了異步操做,f1不會阻塞程序運行,至關於先執行程序的主要邏輯,講耗時的操做推遲執行。 後調函數的優勢是簡單、容易理解和部署,缺點是不利於代碼的閱讀和維護,各個部分之間高度耦合,流程會很混亂,並且每一個任務只能指定一個回調函數。
2.事件監聽
另外一種思路就是採用事件驅動模式。任務執行不取決於代碼的順序,而取決與某個事件是否發生。例如:爲f1綁定一個事件。
f1.on('done', f2);
複製代碼
這樣的優勢是比較容易理解,能夠綁定多個事件,每一個事件能夠指定多個回調函數,並且能夠去耦合,有利於實現模塊化。缺點是整個程序都要變成事件驅動,運行流程會變得不清晰。
3.發佈/訂閱
咱們假設純在一個信號發射函數,當某個任務執行完畢,就像信號中心發佈一個信號,其餘任務能夠向信號中心訂閱這個信號,從而知道何時本身能夠開始執行。這就叫作發佈/訂閱模式,又稱觀察者模式。
這個模式有多種實現方式,下面採用的是Ben Alman的Tiny Pub/Sub,這是jQuery的一個插件。
首先,f2像信號中心的jQuery訂閱done信號。
jQuery.subscribe("done", f2);
複製代碼
而後f1進行以下改寫:
function f1(){
setTimeout(function () {
//f1的任務代碼
jQuery.publish("done");
}, 1000);
}
複製代碼
jQuery.publish("done")的意思是,f1執行完成後,向信號中心jQuery發佈done信號,從而引起f2的執行。 此外,f2完成後,也能夠取消訂閱。
jQuery.unsubscribe("done", f2);
複製代碼
這種方法的性質跟事件監聽相似,可是明顯優於後者,由於咱們能夠經過查看消息中心,瞭解存在多少信號、每一個信號有多少訂閱者,從而監控程序的運行。
4.Promise對象
Promise對象是CommonJS工做組提出的一種規範,目的是爲異步編程提供統一接口。 簡單的說,它的思想就是每個異步任務返回一個Promise對象,該對象有一個then方法,容許指定回調函數。好比,f1的回調函數f2,能夠寫成:
f1().then(f2);
複製代碼
f1要進行以下改寫:
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
// f1的任務代碼
dfd.resolve();
}, 500);
return dfd.promise;
}
複製代碼
這樣寫的優勢在於,回調函數就變成了鏈式寫法,程序的流程能夠看得很清楚,還有其餘的一些很強大的方法可使用,Promise其餘方法。並且,它還有一個前面三種方法都沒有的好處:若是一個任務已經完成,再添加回調函數,該函數就會當即執行。因此不用擔憂是否錯過了摸個事件或信號。這種寫法的缺點是編寫和理解都相對比較困難。
1.Promise對象有三種狀態,他們分別是:
這三種狀態不受外界影響,並且狀態只能從pending改變爲resolved或rejected,而且不可逆。在Promise對象的構造函數中,resolved和rejected就是用來處理Promise的狀態變化。
2.new Promise()裏的函數是馬上執行的
<script>
new Promise(function(resolve,reject){
$.ajax({
type:'post',
dataType: 'jsonp',
url:'http://api.money.126.net/data/feed/0000001,1399001',
data:{
},
success : function(res){
console.log(res) ;
resolve(res) ;
},
error:function(res){
reject(res) ;
}
})
});
</script>
複製代碼
3.Promise.all()與Promise.race()的用法,更多方法ES6入門
Promise.all方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。
<script>
var p1 = function(){
return new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
} ;
var p2 = function(){
return new Promise(function (resolve, reject) {
setTimeout(resolve, 1000, 'P2');
});
} ;
// 同時執行p1和p2,並在它們都完成後執行then
var start = function(){
Promise.all([p1(), p2()]).then(function (results) {
console.log(results); // 得到一個Array: ['P1', 'P2']
}).catch(function(reason){
// ...
});;
}
</script>
複製代碼
<script>
var p1 = function(){
return new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
} ;
var p2 = function(){
return new Promise(function (resolve, reject) {
setTimeout(resolve, 1000, 'P2');
});
} ;
var start = function(){
Promise.race([p1(), p2()]).then(function (results) {
console.log(results); // 'P1'
}).catch(function(reason){
// ...
});;
}
</script>
複製代碼
Promise 的最大問題就是代碼冗餘,原來的任務被Promise保證一下,無論什麼操做,一眼望去都是then,原來的語義變得很不清楚,Generator函數恰好能夠解決這樣的問題,它能夠多個線程互相協做,完成異步任務。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
複製代碼
上面代碼定義了一個 Generator 函數helloWorldGenerator,它內部有兩個yield表達式(hello和world),即該函數有三個狀態:hello,world 和 return 語句(結束執行)。
而後,Generator 函數的調用方法與普通函數同樣,也是在函數名後面加上一對圓括號。不一樣的是,調用 Generator函數後,該函數並不執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象,也就是上一章介紹的遍歷器對象(Iterator Object)。
下一步,必須調用遍歷器對象的next方法,使得指針移向下一個狀態。也就是說,每次調用next方法,內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個yield表達式(或return語句)爲止。換言之,Generator 函數是分段執行的,yield表達式是暫停執行的標記,而next方法能夠恢復執行。 更多內容產考阮一峯老師的ES6入門 Generator 函數的語法
async一句話,它就是 Generator 函數的語法糖。async 函數就是將 Generator 函數的星號(*)替換成 async,將 yield 替換成 await,僅此而已。和Generator函數同樣,async函數返回一個Promise對象,可使用then方法添加回調函數。當函數執行的時候,一旦遇到await就會先返回,等觸發的異步操做完成,再接着執行函數後面的語句。
async function getStockPriceByName(name) {
var symbol = await getStockSymbol(name);
var stockPrice = await getStockPrice(symbol);
return stockPrice;
}
getStockPriceByName('goog').then(function (result){
console.log(result);
});
複製代碼
Tips:await 命令後面的 Promise 對象,運行結果多是 rejected,因此最好把 await 命令放在 try...catch 代碼塊中。 await 命令只能用在 async 函數之中,若是用在普通函數,就會報錯。 若是將 forEach 方法的參數改爲 async 函數,也有問題。正確的寫法是採用for循環。
async function dbFuc(db) {
let docs = [{}, {}, {}];
for (let doc of docs) {
await db.post(doc);
}
}
複製代碼
若是確實但願多個請求併發執行,可使用 Promise.all 方法。
async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));
let results = await Promise.all(promises);
console.log(results);
}
// 或者使用下面的寫法
async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));
let results = [];
for (let promise of promises) {
results.push(await promise);
}
console.log(results);
}
複製代碼
get和post的區別一直以來都是一個老生常談的問題,具體的區別爲:
「1. GET使用URL或Cookie傳參,而POST將數據放在BODY中」,這個是由於HTTP協議用法的約定。並不是它們的自己區別。
「2. GET方式提交的數據有長度限制,則POST的數據則能夠很是大」,這個是由於它們使用的操做系統和瀏覽器設置的不一樣引發的區別。也不是GET和POST自己的區別。
「3. POST比GET安全,由於數據在地址欄上不可見」,這個說法沒毛病,但依然不是GET和POST自己的區別。
GET和POST最大的區別主要是GET請求是冪等性的,POST請求不是。這個是它們本質區別,上面的只是在使用上的區別。 理解冪等性
什麼是冪等性?冪等性是指一次和屢次請求某一個資源應該具備一樣的反作用。簡單來講意味着對同一URL的多個請求應該返回一樣的結果。
原型(prototype):在JavaScript中,每當定義一個對象(函數)的時候,對象中都會包含一些預約義的屬性。其中函數對象的一個屬性的就是原型對象prototype。普通對象沒有prototype,但有proto屬性。
爲何只有函數纔有prototype?由於當建立函數時,js會爲這個函數自動添加prototype屬性,值是一個有constructor屬性的對象,不是空對象。而一旦你把這個函數看成構造函數(constructor)調用即經過new關鍵字調用,那麼js就會幫你建立改構造函數的實例,實例繼承構造函數prototype的全部屬性和方法(實例經過設置本身的__proto__指向構造函數的prototype來實現這種繼承)。
js正是經過__proto__和prototype的合做實現了原型鏈,以及對象的繼承。
原型鏈:JavaScript對象有一個執行一個原型對象的鏈。當試圖訪問一個對象的屬性時,它不只僅在該對象上搜尋,還會搜尋該對象的原型,以及對象的原型的原型,依次向上搜尋,直到找到一個名字匹配的屬性或到達原型的末尾。
首先定義一個父類
// 定義一個動物類
function Animal (name) {
// 屬性
this.name = name || 'Animal';
// 實例方法
this.sleep = function(){
console.log(this.name + '正在睡覺!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
複製代碼
1.原型鏈繼承 核心:將父類的實例做爲子類的原型
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
複製代碼
優勢:
1.很是簡單純粹的繼承關係,實例是子類的實例,也是父類的實例
2.父類新增的原型方法或原型屬性,子類都能訪問到
缺點:
1.要想爲子類新增屬性和方法,必需要在new Animal()這樣的語句以後執行,不能放到構造器中
2.建立子類實例時,沒法向父類構造函數傳參
3.沒法實現多繼承
4.來自原型對象的全部屬性被全部實例共享
2.構造繼承
原理:使用父類的構造函數來加強子類實例,等因而複製父類的實例屬性給子類
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
複製代碼
優勢:
1.解決了1中,子類實例共享父類引用屬性的問題
2.建立子類實例時,能夠向父類傳遞參數
3.能夠實現多繼承(call多個父類對象)
缺點:
1.實例並非父類的實例,只是子類的實例
2.只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法
3.沒法實現函數複用,每一個子類都有父類實例函數的副本,影響性能
3.實例繼承 原理:爲父類實例添加新特性,做爲子類實例返回
function Cat(name){
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
複製代碼
優勢:
4.拷貝繼承
function Cat(name){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
複製代碼
優勢:
1.支持多繼承 缺點:
1.效率較低,內存佔用高(由於要拷貝父類的屬性)
2.沒法獲取父類不可枚舉的方法(不可枚舉方法,不能使用for in 訪問到)
5.組合繼承 原理:經過調用父類構造,繼承父類的屬性並保留傳參的優勢,而後經過將父類實例做爲子類原型,實現函數複用
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
複製代碼
優勢:
1.彌補了方式2的缺陷,能夠繼承實例屬性/方法,也能夠繼承原型屬性/方法 既是子類的實例,也是父類的實例
2.不存在引用屬性共享問題
3.可傳參
4.函數可複用 缺點:
1.調用了兩次父類構造函數,生成了兩份實例(子類實例將子類原型上的那份屏蔽了)
6.寄生組合繼承 原理:經過寄生方式,砍掉父類的實例屬性,這樣,在調用兩次父類的構造的時候,就不會初始化兩次實例方法/屬性,避免的組合繼承的缺點。
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
(function(){
// 建立一個沒有實例方法的類
var Super = function(){};
Super.prototype = Animal.prototype;
//將實例做爲子類的原型
Cat.prototype = new Super();
})();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
複製代碼
MVVM是Model-View-ViewModel的縮寫。
Model 表明數據模型,也能夠在Model中定義數據修改和操做的業務邏輯。
View 表明UI 組件,它負責將數據模型轉化成UI 展示出來。
ViewModel 監聽模型數據的改變和控制視圖行爲、處理用戶交互,簡單理解就是一個同步View 和 Model的對象,鏈接Model和View。
在MVVM框架下View和Model沒有直接的聯繫,而是經過ViewModel進行交互的,Model和ViewModel的交互是雙向的,所以View數據的變化會同步在Model中,而Model 數據的變化也會當即反應到View 上。
ViewModel 經過雙向數據綁定把 View 層和 Model 層鏈接了起來,而View 和 Model 之間的同步工做徹底是自動的,無需人爲干涉,所以開發者只需關注業務邏輯,不須要手動操做DOM,不須要關注數據狀態的同步問題,複雜的數據狀態維護徹底由 MVVM 來統一管理。
vue採用數據劫持組合發佈-訂閱模式的方式,經過Object.defineProperty()來劫持各個屬性的setter、getter,在數據變更時發佈消息給訂閱者,觸發響應的監聽回調。這也是vue不支持IE8以及以更低的瀏覽器的緣由。Vue雙向數據綁定將MVVM作爲數據綁定入口,整合Observer,Compile和Watcher三者,經過Observer來監聽model層的數據變化,而後經過Compile來解析編譯模板指令(vue中是用來解析 {{}})最終利用Watcher搭建Observer,Compile之間的橋樑達到數據變化-->視圖更新,視圖交互-->數據model更新雙向綁定效果。
因爲數組只要不是從新賦值一個新的數組對象,任何對數組內部的修改都不會觸發setter方法的執行。因此vue單獨的從新修改監聽了 push()、pop()、shift()、unshift()、splice()、sort()、reverse() 7 種方法。
beforeCreate(建立前) 在數據觀測和初始化事件還未開始
created(建立後) 完成數據觀測,屬性和方法的運算,初始化事件,$el屬性尚未顯示出來
beforeMount(載入前) 在掛載開始以前被調用,相關的render函數首次被調用。實例已完成如下的配置:編譯模板,把data裏面的數據和模板生成html。注意此時尚未掛載html到頁面上。
mounted(載入後) 在el 被新建立的 vm.$el 替換,並掛載到實例上去以後調用。實例已完成如下的配置:用上面編譯好的html內容替換el屬性指向的DOM對象。完成模板中的html渲染到html頁面中。此過程當中進行ajax交互。
beforeUpdate(更新前) 在數據更新以前調用,發生在虛擬DOM從新渲染和打補丁以前。能夠在該鉤子中進一步地更改狀態,不會觸發附加的重渲染過程。
updated(更新後) 在因爲數據更改致使的虛擬DOM從新渲染和打補丁以後調用。調用時,組件DOM已經更新,因此能夠執行依賴於DOM的操做。然而在大多數狀況下,應該避免在此期間更改狀態,由於這可能會致使更新無限循環。該鉤子在服務器端渲染期間不被調用。
beforeDestroy(銷燬前) 在實例銷燬以前調用。實例仍然徹底可用。
destroyed(銷燬後) 在實例銷燬以後調用。調用後,全部的事件監聽器會被移除,全部的子實例也會被銷燬。該鉤子在服務器端渲染期間不被調用。
答: Vue 實例從建立到銷燬的過程,就是生命週期。從開始建立、初始化數據、編譯模板、掛載Dom→渲染、更新→渲染、銷燬等一系列過程,稱之爲 Vue 的生命週期。
答:它的生命週期中有多個事件鉤子,讓咱們在控制整個Vue實例的過程時更容易造成好的邏輯。
答:它能夠總共分爲8個階段:建立前/後, 載入前/後,更新前/後,銷燬前/銷燬後。
答:會觸發 下面這幾個beforeCreate, created, beforeMount, mounted 。
答:DOM 渲染在 mounted 中就已經完成了。
簡單的說是因爲js的堆和棧決定的,在js中基本數據類型存放在棧中。當vue初始化一個實例時會初始化一個date對象,若是這個實例在不少地方調用就會照成某個實例改變了狀態後影響其餘實例。爲了解決這個問題vue須要返回一個函數從而返回一個新的數據對象。
當一個組件被定義, data 必須聲明爲返回一個初始數據對象的函數,由於組件可能被用來建立多個實例。若是 data 仍然是一個純粹的對象,則全部的實例將共享引用同一個數據對象!經過提供 data 函數,每次建立一個新實例後,咱們可以調用 data 函數,從而返回初始數據的一個全新副本數據對象。
vue路由問題官網介紹的很是詳細,點擊就可查看 vue路由
vue路由的實現原理:
hash模式:在瀏覽器中符號「#」,#以及#後面的字符稱之爲hash,用 window.location.hash 讀取。特色:hash雖然在URL中,但不被包括在HTTP請求中;用來指導瀏覽器動做,對服務端安全無用,hash不會重加載頁面。
history模式:history採用HTML5的新特性;且提供了兩個新方法: pushState(), replaceState()能夠對瀏覽器歷史記錄棧進行修改,以及popState事件的監聽到狀態變動。
一、與AngularJS的區別
相同點:都支持指令:內置指令和自定義指令;都支持過濾器:內置過濾器和自定義過濾器;都支持雙向數據綁定;都不支持低端瀏覽器。
不一樣點:AngularJS的學習成本高,好比增長了Dependency Injection特性,而Vue.js自己提供的API都比較簡單、直觀;在性能上,AngularJS依賴對數據作髒檢查,因此Watcher越多越慢;Vue.js使用基於依賴追蹤的觀察而且使用異步隊列更新,全部的數據都是獨立觸發的。
二、與React的區別
相同點:React採用特殊的JSX語法,Vue.js在組件開發中也推崇編寫.vue特殊文件格式,對文件內容都有一些約定,二者都須要編譯後使用;中心思想相同:一切都是組件,組件實例之間能夠嵌套;都提供合理的鉤子函數,可讓開發者定製化地去處理需求;都不內置列數AJAX,Route等功能到核心包,而是以插件的方式加載;在組件開發中都支持mixins的特性。
不一樣點:React採用的Virtual DOM會對渲染出來的結果作髒檢查;Vue.js在模板中提供了指令,過濾器等,能夠很是方便,快捷地操做Virtual DOM。
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化
在main.js引入store,注入。新建了一個目錄store就可使用vuex了。
state Vuex 使用單一狀態樹,即每一個應用將僅僅包含一個store 實例,但單一狀態樹和模塊化並不衝突。存放的數據狀態,不能夠直接修改裏面的數據。
mutations mutations定義的方法動態修改Vuex 的 store 中的狀態或數據。
getters 相似vue的計算屬性,主要用來過濾一些數據。
action actions能夠理解爲經過將mutations裏面處裏數據的方法變成可異步的處理數據的方法,簡單的說就是異步操做數據。view 層經過 store.dispath 來分發 action。
const store = new Vuex.Store({ //store實例
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
複製代碼
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
})
複製代碼