js中sort內置多種排序算法,是根據要排序數的亂序程度來決定使用哪種排序方法。V8 引擎 sort 函數只給出了兩種排序 InsertionSort 和 QuickSort,長度小於20的使用InsertionSort(插入排序),大於20的數組則使用 QuickSort(快速排序)javascript
快速排序css
function quickSort(arr){ if(arr.length<=1){ //若是數組中只有一位數,返回數組 return arr; } var mNumIndex = Math.floor(arr.length/2); //取基準值的下標 var mNum = arr.splice(mNumIndex,1)[0]; //取基準值 var left = []; //左邊數組 var right = []; //右邊數組 for(var i=0;i<arr.length;i++){ if(arr[i]<mNum){ //若是數組小於基準值,放在左邊數組 left.push(arr[i]); }else{ ///不然 right.push(arr[i]); } } return quickSort(left).concat([mNum],quickSort(right)); //返回左邊數組+基準值+右邊數組 }
插入排序html
function insertSort(arr) { let length = arr.length; for(let i = 1; i < length; i++) { let temp = arr[i]; for(let j = i; j > 0; j--) { if(arr[j] >= arr[j-1]) { break; // 當前考察的數大於前一個數,證實有序,退出循環 } arr[j] = arr[j-1]; // 將前一個數複製到後一個數上 } arr[j] = temp; // 找到考察的數應處於的位置 } return arr; }
選擇排序(實現思路跟冒泡排序差很少, 能夠說是冒泡排序的衍生版本)vue
function selectionSort(arr) { var len = arr.length var minIndex, temp for (i = 0; i < len - 1; i++) { minIndex = i for (j = i + 1; j < len; j++) { if (arr[j] < arr[minIndex]) { minIndex = j } } temp = arr[i] arr[i] = arr[minIndex] arr[minIndex] = temp } return arr }
ES6java
function unique(arr) { return Array.from(new Set(arr)) } new Set自己是一個構造函數,用來生成Set數據結構,類數組,成員的值都是惟一的, 沒有重複的值。 Array.from()將一個類數組對象或者可遍歷對象轉換成一個真正的數組。
ES5node
function unique(arr) { var newArr = [] for (var i = 0; i < arr.length; i++) { if (newArr.indexOf(arr[i]) === -1) { newArr.push(arr[i]) } } return newArr } var result = []; var obj = {}; for(var i =0; i<arr.length; i++){ if(!obj[arr[i].key]){ result.push(arr[i]); obj[arr[i].key] = true; } }
ES5webpack
var doms = document.getElementsByTagName('*') var obj = {} var ret = [] for (let i = 0; i < doms.length; i++) { var name = doms[i].nodeName if(!obj[name]){ ret.push(name) obj[name] = true } } console.log(ret.length)
ES6ios
let names = [...document.getElementsByTagName('*')].map(v=>v.nodeName) console.log(new Set(names).size)
function getDom(dom) { var list = [] var domChildren = dom.childNodes for (var i = 0; i < domChildren.length; i++) { // nodeType === 1 是元素節點,2是屬性節點。 if (domChildren[i].nodeType === 1) { list.push(domChildren[i]) var retArr = getDom(domChildren[i]) list = list.concat(retArr) } } return list } getDom(document.querySelector('body'))
實現bind方法:web
Function.prototype.bind= function(obj){ var _self = this, args = arguments; return function() { _self.apply(obj, Array.prototype.slice.call(args, 1)); } }
定義:屢次觸發事件後,事件處理函數只執行一次,而且是在觸發操做結束時執行。 原理:對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。 function debounce(fn) { // 四、建立一個標記用來存放定時器的返回值 let timeout = null; return function() { // 五、每次當用戶點擊/輸入的時候,把前一個定時器清除 clearTimeout(timeout); // 六、而後建立一個新的 setTimeout, // 這樣就能保證點擊按鈕後的 interval 間隔內 // 若是用戶還點擊了的話,就不會執行 fn 函數 var args = arguments; timeout = setTimeout(() => { fn.apply(this, args); }, 1000); }; } sayDebounce(){ console.log("防抖成功!"); } btn.addEventListener("click", debounce(sayDebounce));
定義:觸發函數事件後,短期間隔內沒法連續調用,只有上一次函數執行後,過了規定的時間間隔,才能進行下一次的函數調用。算法
原理:對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。
詳細連接: https://juejin.im/post/5afe64...
特色:一個類只能構造出惟一實例 案例:建立菜單對象或者彈出框 const singleton = function(name) { this.name = name this.instance = null } singleton.prototype.getName = function() { console.log(this.name) } singleton.getInstance = function(name) { if (!this.instance) { // 關鍵語句 this.instance = new singleton(name) } return this.instance } // test const a = singleton.getInstance('a') // 經過 getInstance 來獲取實例 const b = singleton.getInstance('b') console.log(a === b)
建立一個對象經常須要複雜的過程,因此不適合在一個複雜的對象中。建立對象可能會致使大量的重複代碼,也可能提供不了足夠級別的抽象。工廠方法模式經過定義一個單獨的建立對象的方法來解決這些問題,由子類實現這個方法來建立具體類型的對象。
function Animal(opts){ var obj = new Object(); obj.name = opts.name; obj.color = opts.color; obj.getInfo = function(){ return '名稱:'+obj.name +', 顏色:'+ obj.color; } return obj; } var cat = Animal({name: '波斯貓', color: '白色'}); cat.getInfo();
發佈訂閱模式,基於一個主題/事件通道,但願接收通知的對象(稱爲subscriber)經過自定義事件訂閱主題,被激活事件的對象(稱爲publisher)經過發佈主題事件的方式被通知。
就和用戶訂閱微信公衆號道理同樣,一個公衆號能夠被多個用戶同時訂閱,當公衆號有新增內容時候,只要發佈就行了,用戶就能接收到最新的內容
訂閱/發佈者模式和觀察者模式的區別:
在觀察者模式中,觀察者須要直接訂閱目標事件。在目標發出內容改變的事件後,直接接收事件並做出響應。發佈訂閱模式相比觀察者模式多了個事件通道,訂閱者和發佈者不是直接關聯的。
一、Observer模式要求觀察者必須訂閱內容改變的事件,定義了一個一對多的依賴關係;
二、Publish/Subscribe模式使用了一個主題/事件通道,這個通道介於訂閱着與發佈者之間;
三、觀察者模式裏面觀察者「被迫」執行內容改變事件(subject內容事件);發佈/訂閱模式中,訂閱着能夠自定義事件處理程序;
四、觀察者模式兩個對象之間有很強的依賴關係;發佈/訂閱模式兩個對象之間的耦合讀底
function Public(){ //存放訂閱者信息 this.subscribers = []; // 添加訂閱者 this.addSubscriber = function(subscriber) { //保證一個訂閱者只能訂閱一次 let flag = this.subscribers.some(function(item){ return item == subscriber; }) if(!flag){ this.subscribers.push(subscriber); } return this; } // 發佈消息 this.publish = function(data) { let arr = arguments; this.subscribers.forEach(function(fn){ fn(...arr) }) return this; } } let publisher = new Public() //初始化 let fanfan = function(data){ console.log(`訂閱者吳亦凡收到訂閱信息:${[...arguments]}`) } let luhan = function(data){ console.log(`訂閱者鹿晗收到訂閱信息:${[...arguments]}`) } publisher.addSubscriber(fanfan).addSubscriber(luhan); // 添加訂閱者fanfan publisher.publish('NBA頭條快訊', '蔡徐坤簽約掘金');
一個或多個觀察者對目標的狀態感興趣,經過將本身依附在目標對象上以便註冊所感興趣的內容。目標狀態發生改變而且觀察者可能對這些改變感興趣,會發送一個通知消息,調用每一個觀察者的更新方法。當觀察者再也不對目標狀態感興趣時,他們能夠簡單將本身從中分離。
首先是目標的構造函數,他有個數組,用於添加觀察者。還有個廣播方法,遍歷觀察者數組後調用他們的update方法: class Subject{ constructor(){ this.subs = []; } addSub(sub){ this.subs.push(sub); } notify(){ this.subs.forEach(sub=> { sub.update(); }); } } 那麼觀察者就得有個update方法: class Observer{ update(){ console.log('update'); } } let subject = new Subject(); let ob = new Observer(); //目標添加觀察者了 subject.addSub(ob); //目標發佈消息調用觀察者的更新方法了 subject.notify(); //update
4. 策略模式
特徵:根據不一樣參數能夠命中不一樣的策略;
案例:動畫庫裏的算法函數
5. 代理模式
特徵:代理對象和本體對象具備一致的接口;
案例:圖片預加載
5. 迭代器模式
特徵:能獲取聚合對象的順序和元素;
案例:each([1, 2, 3], cb);
5. 命令模式
特徵:不一樣對象間約定好相應的接口;
案例:按鈕和命令的分離;
6. 組合模式
特徵:組合模式在對象間造成一致對待的樹形結構;
案例: 掃描文件夾;
7. 組合模式
特徵:組合模式在對象間造成一致對待的樹形結構;
案例: 掃描文件夾;
6. 組合模式
特徵:組合模式在對象間造成一致對
待的樹形結構;
案例: 掃描文件夾;
Object.prototype.toString.call(arr) === "[object Array]" ; Array.isArray(arr); arr.constructor === Array;
建立一個函數就會爲其建立一個prototype屬性,指向這個函數的原型對象,原型對象會自動得到constructor屬性,指向prototype屬性所在函數。
Function.prototype.a = "a"; Object.prototype.b = "b"; function Person(){} console.log(Person); //function Person() let p = new Person(); console.log(p); //Person {} 對象 console.log(p.a); //undefined console.log(p.b); //b p.__proto__ === Person.prototype;Person.prototype.constructor === Person;
vue實現數據雙向綁定主要是:採用數據劫持結合發佈者-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變更時發佈消息給訂閱者,觸發相應監聽回調。當把一個普通 Javascript 對象傳給 Vue 實例來做爲它的 data 選項時,Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉爲 getter/setter。用戶看不到 getter/setter,可是在內部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。
vue的數據雙向綁定 將MVVM做爲數據綁定的入口,整合Observer,Compile和Watcher三者,經過Observer來監聽本身的model的數據變化,經過Compile來解析編譯模板指令(vue中是用來解析 {{}}),最終利用watcher搭起observer和Compile之間的通訊橋樑,達到數據變化 —>視圖更新;視圖交互變化(input)—>數據model變動雙向綁定效果。
<body> <div id="app"> <input type="text" id="txt"> <p id="show"></p> </div> </body> <script type="text/javascript"> var obj = {} Object.defineProperty(obj, 'txt', { get: function () { return obj }, set: function (newValue) { document.getElementById('txt').value = newValue document.getElementById('show').innerHTML = newValue } }) document.addEventListener('keyup', function (e) { obj.txt = e.target.value }) </script>
keep-alive是 Vue 內置的一個組件,可使被包含的組件保留狀態,或避免從新渲染。
在vue 2.1.0 版本以後,keep-alive新加入了兩個屬性: include(包含的組件緩存) 與 exclude(排除的組件不緩存,優先級大於include) 。
答:簡而言之,就是先轉化成AST樹,再獲得的render函數返回VNode(Vue的虛擬DOM節點)
詳情步驟:
首先,經過compile編譯器把template編譯成AST語法樹(abstract syntax tree 即 源代碼的抽象語法結構的樹狀表現形式),compile是createCompiler的返回值,createCompiler是用以建立編譯器的。另外compile還負責合併option。
而後,AST會通過generate(將AST語法樹轉化成render funtion字符串的過程)獲得render函數,render的返回值是VNode,VNode是Vue的虛擬DOM節點,裏面有(標籤名、子節點、文本等等)
在下次 DOM 更新循環結束以後執行延遲迴調。在修改數據以後當即使用這個方法,獲取更新後的 DOM。
原理:事件循環機制(Event Loop)
如下事件屬於宏任務:
setInterval()
setTimeout()
如下事件屬於微任務
new Promise()
new MutaionObserver()
1.computed計算屬性會依賴於使用它的data屬性,只要是依賴的data屬性值有變更,則自定義從新調用計算屬性執行一次。
2.watch則是在監控的data屬性值發生變更時,其會自動調用watch回調函數。
1.執行異步操做,開銷較大的操做,避免堵塞主線程,使用watch。
2.簡單且串行返回的,使用computed
《JavaScript權威指南》中的概念:有權訪問另外一個做用域中變量的函數
閉包特性:可實現函數外訪問函數內變量,外層變量能夠不被垃圾回收機制回收。
缺點:
function outer() { var a = 2; function inner() { console.log(a); } return inner; } var neal = outer(); neal();//2
基礎類型:Undefined, Null, Boolean, Number, String, Symbol(ES6新增,表示獨一無二的值))一共6種 引用類型:Object
JS中的基礎數據類型,這些值都有固定的大小,每每都保存在棧內存中(閉包除外),由系統自動分配存儲空間。咱們能夠直接操做保存在棧內存空間的值,所以基礎數據類型都是按值訪問 數據在棧內存中的存儲與使用方式相似於數據結構中的堆棧數據結構,遵循後進先出的原則。
JS的引用數據類型,好比數組Array,它們值的大小是不固定的。引用數據類型的值是保存在堆內存中的對象。JS不容許直接訪問堆內存中的位置,所以咱們不能直接操做對象的堆內存空間。在操做對象時,其實是在操做對象的引用而不是實際的對象。所以,引用類型的值都是按引用訪問的。這裏的引用,咱們能夠粗淺地理解爲保存在棧內存中的一個地址,該地址與堆內存的實際值相關聯。
數據結構就是關係,沒錯,就是數據元素相互之間存在的一種或多種特定關係的集合。
邏輯結構:是指數據對象中數據元素之間的相互關係,也是咱們從此最須要關注和討論的問題。
物理結構:是指數據的邏輯結構在計算機中的存儲形式。
常見的數據結構:數組,隊列(queue),堆(heap),棧(stack),鏈表(linked list ),樹(tree),圖(graph)和散列表(hash)
參照:https://www.cnblogs.com/slly/...
一種遵循後進先出(LIFO)原則的有序集合。新添加的或待刪除的元素都保存在棧的同一端,稱做棧頂,另外一端就叫棧底。在棧裏,新元素都接近棧頂,舊元素都接近棧底。
是隻容許在一端進行插入操做,而在另外一端進行刪除操做的線性表。與棧相反,隊列是一種先進先出(First In First Out, FIFO)的線性表。與棧相同的是,隊列也是一種重要的線性結構,實現一個隊列一樣須要順序表或鏈表做爲基礎。
鏈表存儲有序的元素集合,但不一樣於數組,鏈表中的元素在內存中並非連續放置的。每一個元素由一個存儲元素本事的節點和一個指向下一個元素的引用組成。相對於傳統的數組,鏈表的一個好處在於,添加或者刪除元素的時候不須要移動其餘元素。 使用鏈表結構能夠克服數組須要預先知道數據大小的缺點(C語言的數組須要預先定義長度),鏈表結構能夠充分利用計算機內存空間,實現靈活的內存動態管理。 數組和鏈表的一個不一樣在於數組能夠直接訪問任何位置的元素,而想要訪問鏈表中的一個元素,須要從起點開始迭代列表。
<meta name="viewport" content="width=device-width, user-scalable=no">
檢測到touchend事件後,馬上出發模擬click事件,而且把瀏覽器300毫秒以後真正出發的事件給阻斷掉
1.IE盒子模型(怪異盒子)box-sizing :border-box;
寬度=margin+width
2.W3C標準盒模型box-sizing : content-box;
寬度=margin+border+padding+width
!important > 行內樣式>ID選擇器 > 類選擇器 > 標籤 > 通配符* > 繼承 > 瀏覽器默認屬性
1. 父元素 overflow: hidden; 2.浮動元素後面的元素: clear: both; 3.僞元素選擇器:.clear::after{ content:’’;display:block; clear:both;}; 4.父元素設置高度; 5.父級元素:display: table;
方案一:已知寬高,設置position: absolute;,而後left和top都設置爲50%,再根據margin的負值來調正
方案二:相似方案一,最後一步用transform:translate(-50%,-50%);
方案三:絕對定位,top、bottom、left、right都設置爲0,設置好寬高,而後margin: auto;
方案四:display:table-cell; + vertical-align:middle;
方案五:使用flex彈性盒模型
<div class=「box」> <div class=「item」></div> </div> box{ display:flex; justifly-content:center; Align-item:center; } Box{ Position:relative; } Item{ Position:absolute; Top:50%; Transform:translateY(-50%); }
!important > 行內樣式>ID選擇器 > 類選擇器 > 標籤 > 通配符* > 繼承 > 瀏覽器默認屬性
webpack:把全部依賴打包成一個 bundle.js 文件,經過代碼分割成單元片斷並按需加載。
AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出(不過 RequireJS 從 2.0 開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不一樣))。
CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出。
父子類 function Animal(name) { this.name = name || "Mike";//實例屬性 this.love = function () { console.log(this.name + "愛吃骨頭")//實例方法 } this.other = [];//實例引用屬性 } Animal.prototype.sleep = function (place) { console.log(this.name + "在" + place + "睡覺") }
function Dog() {} Dog.prototype = new Animal(); Dog.prototype.name = "Jack"; var dog1 = new Dog("twoHa"); var dog2 = new Dog("keJi"); console.log(dog1.name);//Jack console.log(dog2.name);//Jack dog1.love();//Jack愛吃骨頭 dog2.love();//Jack愛吃骨頭 dog1.sleep("牀上");//Jack在牀上睡覺 dog2.sleep("客廳");//Jack在客廳睡覺 優勢: 1. 實例是子類的實例,也是父類的實例 2. 父類新增原型方法/原型屬性,子類都能訪問到 3. 簡單,易於實現 缺點: 1. 要想爲子類新增屬性和方法,必需要在new Animal()這樣的語句以後執行,不能放到構造器中 2. 沒法實現多繼承 3. 來自原型對象的引用屬性是全部實例共享的,改變實例會污染父類 4. 建立子類實例時,沒法向父類構造函數傳參
XSS跨站腳本攻擊:
不須要你作任何的登陸認證,它會經過合法的操做(好比在url中輸入、在評論框中輸入),向你的頁面注入腳本(多是js、hmtl代碼塊等)。
檢測 callback 裏面的字符。通常 callback 裏面都是字母和數字,別的符號都不能有。
要完成一次CSRF攻擊,受害者必須知足兩個必要的條件:
舒適提示一下,cookie保證了用戶能夠處於登陸狀態,但網站B其實拿不到 cookie。
預防
(1)服務器發送給客戶端一個token;
(2)客戶端提交的表單中帶着這個token。
(3)若是這個 token 不合法,那麼服務器拒絕這個請求。
把 token 隱藏在 http 的 head頭中。
方法二和方法一有點像,本質上沒有太大區別,只是使用方式上有區別。
HTTP是用於傳輸如HTML文件,圖片文件,查詢結果的應用層協議。它被設計於用於服務端和客戶端之間的通訊。
當前Web應用中較常見的一種持續通訊方式,一般採起 setInterval 或者 setTimeout 實現。例如若是咱們想要定時獲取並刷新頁面上的數據,能夠結合Ajax寫出以下實現:
setInterval(function() { $.get("/path/to/server", function(data, status) { console.log(data); }); }, 10000); 缺陷: 程序在每次請求時都會新建一個HTTP請求,然而並非每次都能返回所需的新數據。 當同時發起的請求達到必定數目時,會對服務器形成較大負擔。
客戶端發送一個request後,服務器拿到這個鏈接,若是有消息,才返回response給客戶端。沒有消息,就一直不返回response。以後客戶端再次發送request, 重複上次的動做。
http協議的特色是服務器不能主動聯繫客戶端,只能由客戶端發起。它的被動性預示了在完成雙向通訊時須要不停的鏈接或鏈接一直打開,這就須要服務器快速的處理速度或高併發的能力,是很是消耗資源的。
相同點:
不一樣點:
注意:迴流必將引發重繪,而重繪不必定會引發迴流。
總共分爲8個階段建立前/後,載入前/後,更新前/後,銷燬前/後
beforeCreate 建立前執行(vue實例的掛載元素$el和數據對象data都爲undefined,還未初始化)