閉包我的理解 函數內部還有一個函數,其做用就是能夠訪問上一層函數中的變量 下面的案例中函數內部有函數,this的指向就變爲window了 結果閉包中this指向的兩種方法 1.call對象冒充能夠改變this的指向 obj.say().call(obj) 這裏把this的指向換成了obj 閉包中的this指向的是window對象,this.name=window.name 2.在方法內部改變this指向 既然對象中的say方法中this是指向obj的,那麼咱們就使用that代替this,在閉包函數中寫成that.name 那麼結果就是obj
自定義函數參數傳遞爲 字符串格式 ,傳遞方式 1:用this傳遞 2:引號缺省 3:轉義字符(html中 " 表明"雙引號,'表明單引號,javascript中直接\\" 和Java通用轉義字符集) <html> <head> <script language="LiveScript"> function print(arg){ alert("你好!"+arg); } </script> </head> <body> <form> <input type="button" name="Button1" value="first" onclick="print(this.str)" str="你好one"> <br><br> <input type="button" name="button2" value="second" onclick=print("你好two")> <br><br> <input type="button" name="button3" value="Third" onclick="print ("你好three")"> </form> </body> </html> 總結 以上是腳本之家爲你收集整理的javascript自定義函數參數傳遞爲字符串格式所有內容,但願文章可以幫你解決javascript自定義函數參數傳遞爲字符串格式所遇到的程序開發問題。
https://blog.csdn.net/Web_J/article/details/83900073javascript
這是一個很是常見的面試題,出題方式多樣,但考察點相同,下面咱們來看看這幾種方法: 方法一: var itemli = document.getElementsByTagName("li"); for(var i = 0; i<itemli.length; i++){ itemli\[i\].index = i; //給每一個li定義一個屬性索引值 itemli\[i\].onclick = function(){ alert(this.index+this.innerHTML); } } 方法二: var itemli = document.getElementsByTagName("li"); for(var i = 0; i<itemli.length; i++){ (function(n){ itemli\[i\].onclick = function(){ alert(n+itemli\[n\].innerHTML); } })(i) } 方法三: var itemli = document.getElementsByTagName("li"); for(var i = 0; i<itemli.length; i++){ itemli\[i\].onclick = function(n){ return function(){ alert(n+itemli\[n\].innerHTML); } }(i) } 方法四: $("ul li").click(function(){ var item = $(this).index(); //獲取索引下標 也從0開始 var textword = $(this).text(); //文本內容 alert(item+textword); }) 上面這四種方法均可以實現循環綁定,可是咱們知道,頻繁的操做DOM是很是消耗性能的,若是有1000個li,怎麼辦呢?咱們還有另外一種思路,事件代理,又稱事件委託。簡單的來說就是利用JS中事件的冒泡屬性,把本來須要綁定的事件委託給父元素,讓父元素擔當事件監聽的職務。下面咱們來看看。 方法五(JS事件代理): var ul = document.querySelector("ul"); ulItem.onclick = function (e) { e = e || window.event; //這一行及下一行是爲兼容IE8及如下版本 var target = e.target || e.srcElement; if (target.tagName.toLowerCase() === "li") { var li = this.querySelectorAll("li"); index = Array.prototype.indexOf.call(li, target); alert(target.innerHTML + index); } } 上述代碼中,爲何須要 「index = Array.prototype.indexOf.call(li,target);」 這樣使用數組的indexOf方法呢,這是由於querySelectorAll方法獲取到的元素列表不是數組,和函數的arguments同樣是一種類數組類型,不能夠直接使用數組的方法。 方法六(jQuery事件代理): $(document).ready(function () { $("ul").on("click", function (event) { var target = $(event.target); alert(target.html() + target.index()) }); });
https://www.jianshu.com/p/83a...html
foreach底層利用迭代器Iterator來實現的vue
map底層是利用hashMap來實現的java
forEach比map快node
定義 foreEach()方法: 針對每個元素執行提供的函數。 map()方法: 建立一個新的數組,其中每個元素由調用數組中的每個元素執行提供的函數得來。 區別 forEach()方法不會返回執行結果,而是undefined。也就是說,forEach()會修改原來的數組。而map()方法會獲得一個新的數組並返回。 例子 製做一個數組的平方 有以下一個數組 let arr =\[1,2,3,4,5,6\] 下面分別用forEach()和Map() forEach() 注意,forEach是不會返回有意義的值的。 咱們在回調函數中直接修改arr的值。 arr.forEach((value, key) => { return arr\[key\] = value \* value; }); 執行結果以下: 執行結果 Map() let list = arr.map(value => { return value \* value; }); 執行結果以下: 執行結果 執行速度對比 forEach()的執行速度 < map()的執行速度 速度比試 image.png 如何使用 forEach適合於你並不打算改變數據的時候,而只是想用數據作一些事情 – 好比存入數據庫或則打印出來。 let arr = \['a', 'b', 'c', 'd'\]; arr.forEach((letter) => { console.log(letter); }); // a // b // c // d map()適用於你要改變數據值的時候。不只僅在於它更快,並且返回一個新的數組。這樣的優勢在於你可使用複合(composition)(map(), filter(), reduce()等組合使用)來玩出更多的花樣。 let arr = \[1, 2, 3, 4, 5\]; let arr2 = arr.map(value => value \* value).filter(value => value > 10); // arr2 = \[16, 25\] 咱們首先使用map將每個元素乘以它們自身,而後緊接着篩選出那些大於10的元素。最終結果賦值給arr2。 總結 forEach()能夠作到的東西,map()也一樣能夠。反過來也是如此。 map()會分配內存空間存儲新數組並返回,forEach()不會返回數據。 forEach()容許callback更改原始數組的元素。map()返回新的數組。
https://blog.csdn.net/Beijiya...ios
思路 map 迭代方法接收兩個參數: 對每一項執行的函數 該函數接收三個參數: 數組項的值 數組項的下標 數組對象自己 指定 this 的做用域對象 map 方法返回每次函數調用結果組成的數組。 代碼表示: arr.map(function(item, index, arr) {}, this); 1 實現 由此,實現 fakeMap 方法以下 代碼: Array.prototype.fakeMap = function fakeMap(fn, context) { if (typeof fn !== "function") { throw new TypeError(\`${fn} is not a function\`); } let arr = this; let temp = \[\]; for (let i = 0; i < arr.length; i++) { // 迭代執行 let result = fn.call(context, arr\[i\], i, arr); temp.push(result); } return temp; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 檢測: let arr = \["x", "y", "z"\]; arr.fakeMap((item, index, arr) => console.log(item, index, arr)); 1 2 3 輸出: x 0 \[ ‘x’, ‘y’, ‘z’ \] y 1 \[ ‘x’, ‘y’, ‘z’ \] z 2 \[ ‘x’, ‘y’, ‘z’ \] this 指向: let arr = \["x", "y", "z"\]; let obj = { a: 1 }; arr.fakeMap(function() { console.log(this.a); }, obj); 1 2 3 4 5 6 7 輸出 1 1 1 更新 Array.prototype.myMap = function (fn, context) { const array = this context = Object(context) || global // 嚴格模式下 const resultArr = \[\] for (let i = 0; i < array.length; i++) { let item = array\[i\] result = fn.call(context, item, i, array) resultArr.push(result) } return resultArr }; 1 2 3 4 5 6 7 8 9 10 11 12 注: 嚴格模式下,context 爲 null 或 undefined 時 Object(context) 返回空對象,不會被賦值爲global
\- 父組件向子組件傳值 --Props傳遞數據 在父組件中使用兒子組件 <template> <div> 父組件:{{money}} <Son1 :money="money"><Son1> </div> </template> <script> import Son1 from ''./Son1"; export default{ components:{ Son1 }, data(){ return { money: 100}; } }; </script> 子組件接受數據 props:{ value:{ type:Number, default:1 } } 若是是數組 props:{ value:{ type:Array, default: ()=>\[\] } } \- 子組件通訊父組件 $emit使用 <template> <div> 父組件:{{money}} <Son1 :money="money" @input="change"><Son1> </div> </template> <script> import Son1 from ''./Son1"; export default{ methods:{ change(data){ this.money = data } }, components:{ Son1 }, data(){ return { money: 100}; } }; </script> 子組件觸發綁定本身身上的方法 <template> <div> 子組件1:{{money}} <button @click="$emit('input',200)">修改父組件的值<Son1> </div> </template> <script> export default{ props:{ money:{ type:Number } } }; </script> \- $parent、$children(多層級傳遞) <Grandson1 :value="value"></Grandson1> <template> <div> 孫子1:{{value}} <---調用父組件的input事件--> <button @click="$parent.$emit('input',200)">更改<Son1> </div> </template> <script> export default{ props:{ value:{ type:Number } } }; </script> \- $attrs、 $listeners: $attrs批量向下傳入屬性: <Son2 name="小明" age="18"></Son2> <--能夠在son2組件中使用$attrs,能夠將屬性繼續向下傳遞--> <div> 兒子2:{{ $attrs.name }} <Grandson2 v-bind="$attrs"></Grandson2> </div> <tempalte> <div>孫子:{{$attrs}}</div> </template> $listeners批量向下傳入方法: <Son2 name="小明" age="18" @click=「()=>{this.money =500}」></Son2> <--能夠在son2組件中使用$attrs,能夠將屬性繼續向下傳遞--> <Grandson2 v-bind="$attrs" v-on="$listeners"></Grandson2> <button @click="$listeners.click()">更改<Son1> \- Provide&Inject Provide 在父級中注入數據 provide(){ return {parentMsg:'父親'}; } Inject 在任意子組件中能夠注入父級數據 inject:\['parentMsg'\]//會將數據掛載在當前實例上 \- ref使用 <Grandson2 name="花花" ref="grand2"></Grandson2> mounted(){ console.log(this.$refs.grand2.name); } \- EventBus:用於跨組件通知 Vue.prototype.$bus = new Vue(); Son2組件和Grandson1互相通訊 mounted() { //父親組件註冊 this.$bus.$on('my',data=>{ console.log(data) }) } mounted(){ //侄子組件調用 this.$nextTick(()=>{ this.$bus.$emit('my',"我是小紅」); }) }
http://dongfanker.coding.me/2...git
爲何須要Bus 通常來講,都是利用父組件給子組件使用query或者params傳遞參數來實現子組件的數據顯示 不過,當出現子組件須要向父組件傳遞數據的時候,就須要用到bus,bus能夠本身建立,也能夠經過裝包來實現 直接建立Bus 在此處直接將Bus注入Vue對象中,成爲全局的組件。 在子組件中經過this.$root.Bus.$on(key,method),this.$root.Bus.$emit(key,data)來調用 將$on放在mounted,created這些鉤子函數中,相應的函數使用(e)=>{function}比較便捷 1 2 3 4 5 6 7 8 9 10 import Vue from 'vue' const Bus = new Vue() var app= new Vue({ el:'#app', data:{ Bus } }) 使用vue-bus 使用yarn或者npm安裝vue-bus以後,在main.js中引用它 1 2 import VueBus from 'vue-bus'; Vue.use(VueBus); 因而調用直接能夠寫爲 this.$bus.on(key, this.method),this.$bus.emit(key, { text: …… } 其中第一個字符串參數表明key,每一個key都可以實現本身的獨立傳輸,this.method爲事先定義好的method,用於對傳入的數據進行處理 爲何使用vuex 當咱們的應用遇到多個組件共享狀態時,會須要: 多個組件依賴於同一狀態。 來自不一樣組件的行爲須要變動同一狀態。 通過個人觀察,vuex在其中的做用就是組件與狀態的捆綁剝離開來,使得組件狀態的改變依賴於某個行爲,這使得代碼變得易於調試。 Vuex採用集中式存儲管理應用的全部組件的狀態,這裏的關鍵在於集中式存儲管理。這意味着原本須要共享狀態的更新是須要組件之間通信的,而如今有了vuex,就組件就都和store通信了。 使用vuex 使用yarn或者npm安裝vuex以後,在main.js中引用它 1 2 3 4 5 6 7 import Vuex from 'vuex' import store from './vuex/store' Vue.use(Vuex) new Vue({ el: '#app', store }) 隨後建立vuex目錄,將store.js放在目錄下,定義state和mutation 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { author: 'Wise Wrong' }, mutations:{ newAuthor(state,msg){ state.author = msg } } }) export default store 在使用的時候,不直接修改this.$store.state.author,而是使用this.$store.commit()來提交,可讓咱們更好的跟蹤每個狀態的變化,在大型項目中更爲適用
https://www.cnblogs.com/18252...es6
1.爲何須要路由攔截器 爲了防止用戶在知道組件名稱的狀況下,沒有登陸而直接進入相應的頁面下,因此要爲路由設置一個攔截器,來判斷用戶是否登陸過。 2.怎樣設置路由攔截器: 分析:當咱們第一次登陸的時候,向服務器發送請求,服務器會給咱們一個token標記符(這個token時先後臺約定好的一個值),客戶端拿到這個token後將它保存到本地localstorage或vueX中,當咱們再次訪問時,將這個token在攜帶給服務器。服務器會經過算法校驗這個token的合法性(這個token會有一個有效期),若是合法,則不干涉,不合法則強制跳轉到登陸界面。 import axios from 'axios' const baseURL = 'http://localhost:8888/api/private/v1/' axios.defaults.baseURL = baseURL // 添加請求攔截器 axios.interceptors.request.use(function (config) { // 將token給到一個先後臺約定好的key中,做爲請求發送 // mytoken是咱們第一次登陸成功後,服務器會返回給我一個token值,咱們將它保存在localstorage中 let token = localStorage.getItem('mytoken') // 獲取本地存儲的token值 if (token) { // 判斷token值是否存在 // 我的認爲在此期間能夠再次判斷 token是否還在有效期內,若是在,就將token放在請求頭中;若是不在,就將token= '',並返回錯誤信息 config.headers\['Authorization'\] = token // 若是token值存在,就將token值放在請求頭中,發送給服務器 } return config }, function (error) { // 若是不存在,就返回一個錯誤信息 // Do something with request error return Promise.reject(error) }) 3.當我咱們設置了攔截器後,咱們能夠註冊一個全局守衛(在main.js入口文件中註冊),防止未登陸的用戶跳轉到其餘頁面 // 註冊一個全局守衛。做用是在路由跳轉前對路由判斷,防止未登陸的用戶跳轉到其餘頁面 router.beforeEach((to, from, next) => { let token = localStorage.getItem('mytoken') // 若是已經登陸,那我不干涉你,讓你隨便訪問 if (token) { next() } else { if (to.path !== '/login') { // 若是沒有登陸,但你訪問其餘須要登陸的頁面,那我就讓你跳到登陸頁面去 next({path: '/login'}) } else { // 若是沒有登陸,但你訪問的login,那就不干涉你,讓你訪問 next() } } })
進入你要操做的目錄,跟Linux環境同樣 git status ./ 查看這個文件夾下的文件狀態,會列出有哪些沒有加入追蹤,哪些沒有commit git add ./\* 把這個文件下的全部應該加入追蹤的,加入到暫存區 git commit -m "日誌描述" ./ 把這個文件夾下能夠commit的,都commit到本地庫 git push push到遠程庫
https://blog.csdn.net/xinzhif...面試
Git回滾代碼到某個commit 回退命令: git reset --hard HEAD^ 回退到上個版本 git reset --hard HEAD~3 回退到前3次提交以前,以此類推,回退到n次提交以前 git reset --hard commit\_id 退到/進到,指定commit的哈希碼(此次提交以前或以後的提交都會回滾) 回滾後提交可能會失敗,必須強制提交 強推到遠程:(可能須要解決對應分支的保護狀態) git push origin HEAD --force
https://www.cnblogs.com/ztfjs...算法
寫在前面 一個好的架構須要通過血與火的歷練,一個好的工程師須要通過無數項目的摧殘。 昨天博主分析了一下在vue中,最爲基礎核心的api,parse函數,它的做用是將vue的模板字符串轉換成ast,從而構建vnode,構建指令,實現virtual dom,而後在這基礎之上實現雙向綁定等。【vuejs深刻二】vue源碼解析之一,基礎源碼結構和htmlParse解析器 今天博主就來詳細的實現一個擁有核心功能的htmlParse函數,看看它內部的實現邏輯,瞭解它是怎麼樣去解析一個vue模板的。 小目標 咱們最終的目標是將html轉換成ast對象,那麼首先咱們定一個小目標: <div id="div1"></div> 我但願將上面的html解析成ast格式,相似於下面: 複製代碼 { "tag":"div", "attrs":\[ { "id":"div1" } \], "children":\[\], "type":1 } 複製代碼 最終想要達成的第一個小目標是能夠將div標籤字符串輸出成這樣一個object格式,tag表示標籤名稱,attrs表示屬性,children表示這個div全部的子節點,type的話表示節點的類型,咱們今天只三個類型: 1.元素類型,也就是標籤類型,全部用<tag attr=""></tag>這樣的標籤。2.變量text,如今咱們實現一個{{text}}的變量轉換,它實際上是一個節點。3.普通文本,普通文本包括普通文字和空格、換行。 基本結構 基本結構的設計決定的代碼能擴展多遠,若是一開始結構設計錯誤,最後在新加入的功能沒法嵌入的時候,那就只有重構一條路能夠走了。 首先理清楚咱們的思路。 匹配單個字符》匹配標籤》匹配屬性》匹配文本》匹配結束標籤 而後,你想啊,html標籤都是有開始,有結束的。那麼這裏問題就來了,能夠想到的方式,解析一個標籤的開始與結束吧,例如咱們使用正則匹配開始標籤<div id='div1'> 而後找到結束標籤</div>,這樣是否是就能夠解析div裏面的內容了? 難。 開始標籤比較好找,結束標籤就噁心了,例如 <div><div></div></div> ,,完了,怎麼區分嵌套關係?第一個<div>到底匹配哪個結束標籤? 這個思路是錯的,很難。 那麼咱們換個思路,若是咱們單個字符匹配呢, 例如咱們匹配一個 <div><div></div></div>, ok 腦補步驟 1。匹配到 < 匹配到這個字符我就能夠認爲,後面的要麼是開始標籤,要麼是結束標籤。 2。用正則匹配從<到後面的字符,若是是開始標籤,如今記錄一下,啊,我遇到了一個開始標籤<div> 順便用正則記錄attrs 3. 如今咱們匹配走走走。。。走到<div></div></div> 4.又匹配到一個 < 老步驟啊。 5.發現是開始標籤,再次記錄,啊,我又遇到一個開始標籤 <div> 順便用正則記錄attrs 6. 如今咱們匹配走走走。。。走到</div></div> 7. 又匹配到一個 < 老步驟啊。 8.發現是一個結束標籤</div> ,嗯?結束標籤!它是誰的結束標籤?想想。。。。。。應該是最後一個遇到的開始標籤吧。 第一個遇到的結束標籤不就是最後一個開始標籤的結束麼? 9.啊,結束了一個。 10.再匹配,再完成。 恩。。。思路清晰了有沒有,來實現走一個: 複製代碼 //轉化HTML至AST對象 function parse(template){ var currentParent; //當前父節點 var root; //最終生成的AST對象 var stack = \[\]; //插入棧 var startStack = \[\]; //開始標籤棧 var endStack = \[\]; //結束標籤棧 //console.log(template); parseHTML(template,{ start:function start(targetName,attrs,unary,start,end,type,text){//標籤名 ,attrs,是否結束標籤,文本開始位置,文本結束位置,type,文本, var element = { //咱們想要的對象 tag:targetName, attrsList:attrs, parent:currentParent, //須要記錄父對象吧 type:type, children:\[\] } if(!root){ //根節點哈 root = element; } if(currentParent && !unary){ //有父節點而且不是結束標籤? currentParent.children.push(element); //插入到父節點去 element.parent = currentParent; //記錄父節點 } if (!unary) { //不是結束標籤? if(type == 1){ currentParent = element;//不是結束標籤,當前父節點就要切換到如今匹配到的這個開始標籤哈,後面再匹配到 startStack.push(element); //推入開始標籤棧 } stack.push(element); //推入總棧 }else{ endStack.push(element); //推入結束標籤棧 currentParent = startStack\[endStack.length-1\].parent; //結束啦吧當前父節點切到上一個開始標籤,這能理解吧,當前這個已經結束啦 } //console.log(stack,"currentstack") }, end:function end(){ }, chars:function chars(){ } }); console.log(root,"root"); return root; }; /\*\* \* Not type-checking this file because it's mostly vendor code. \*/ /\*! \* HTML Parser By John Resig (ejohn.org) \* Modified by Juriy "kangax" Zaytsev \* Original code by Erik Arvidsson, Mozilla Public License \* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js \*/ // Regular Expressions for parsing tags and attributes var singleAttrIdentifier = /(\[^\\s"'<>/=\]+)/; var singleAttrAssign = /(?:=)/; var singleAttrValues = \[ // attr value double quotes /"(\[^"\]\*)"+/.source, // attr value, single quotes /'(\[^'\]\*)'+/.source, // attr value, no quotes /(\[^\\s"'=<>\`\]+)/.source \]; var attribute = new RegExp( '^\\\\s\*' + singleAttrIdentifier.source + '(?:\\\\s\*(' + singleAttrAssign.source + ')' + '\\\\s\*(?:' + singleAttrValues.join('|') + '))?' ); // could use https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-QName // but for Vue templates we can enforce a simple charset var ncname = '\[a-zA-Z\_\]\[\\\\w\\\\-\\\\.\]\*'; var qnameCapture = '((?:' + ncname + '\\\\:)?' + ncname + ')'; var startTagOpen = new RegExp('^<' + qnameCapture); var startTagClose = /^\\s\*(\\/?)>/; var endTag = new RegExp('^<\\\\/' + qnameCapture + '\[^>\]\*>'); var doctype = /^<!DOCTYPE \[^>\]+>/i; var comment = /^<!--/; var conditionalComment = /^<!\\\[/; //偷懶哈 上面的正則是我在vue上拿下來的,這個後期能夠研究,下面的話簡單的寫兩個用用,和vue原版的是有一些差異的 //{{變量}} var varText = new RegExp('{{' + ncname + '}}'); //空格與換行符 var space = /^\\s/; var checline = /^\[\\r\\n\]/; /\*\* type 1普通標籤 type 2代碼 type 3普通文本 \*/ function parseHTML(html,options){ var stack = \[\]; //內部也要有一個棧 var index = 0; //記錄的是html當前找到那個索引啦 var last; //用來比對,當這些條件都走完後,若是last==html 說明匹配不到啦,結束while循環 var isUnaryTag = false; while(html){ last = html; var textEnd = html.indexOf('<'); if(textEnd === 0){ //這一步若是第一個字符是<那麼就只有兩種狀況,1開始標籤 2結束標籤 //結束標籤 var endTagMatch = html.match(endTag); //匹配 if(endTagMatch){ console.log(endTagMatch,"endTagMatch"); isUnaryTag = true; var start = index; advance(endTagMatch\[0\].length); //匹配完要刪除匹配到的,而且更新index,給下一次匹配作工做 options.start(null,null,isUnaryTag,start,index,1); continue; } //初始標籤 var startMatch = parseStartTag(); if(startMatch){ parseStartHandler(startMatch);//封裝處理下 console.log(stack,"startMatch"); continue; } } if(html === last){ console.log(html,"html"); break; } } function advance (n) { index += n; html = html.substring(n); } //處理起始標籤 主要的做用是生成一個match 包含初始的attr標籤 function parseStartTag(){ var start = html.match(startTagOpen); if(start){ var match = { tagName: start\[1\], // 標籤名(div) attrs: \[\], // 屬性 start: index // 遊標索引(初始爲0) }; advance(start\[0\].length); var end, attr; while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {//在endClose以前尋找attribute advance(attr\[0\].length); match.attrs.push(attr); } if (end) { advance(end\[0\].length); // 標記結束位置 match.end = index; //這裏的index 是在 parseHTML就定義 在advance裏面相加 return match // 返回匹配對象 起始位置 結束位置 tagName attrs } } } //對match進行二次處理,生成對象推入棧 function parseStartHandler(match){ var \_attrs = new Array(match.attrs.length); for(var i=0,len=\_attrs.length;i<len;i++){ //這兒就是找attrs的代碼哈 var args = match.attrs\[i\]; var value = args\[3\] || args\[4\] || args\[5\] || ''; \_attrs\[i\] = { name:args\[1\], value:value } } stack.push({tag: match.tagName,type:1, lowerCasedTag: match.tagName.toLowerCase(), attrs: \_attrs}); //推棧 options.start(match.tagName, \_attrs,false, match.start, match.end,1); //匹配開始標籤結束啦。 } } 複製代碼 咱們執行 parse("<div id='test1'><div></div></div>"); 大功告成哈哈哈哈哈 呃。
\[1,2,3,4,5\].concat(\[1,2,3,4,5\].reduce((prev,cur)=>\[...prev, cur\*cur\], \[\]))
function groupBy(objectArray, property) { return objectArray.reduce(function (acc, obj) { var key = obj\[property\]; if (!acc\[key\]) { acc\[key\] = \[\]; } acc\[key\].push(obj); return acc; }, {}); }
https://www.cnblogs.com/cheny...
首先咱們要明白一個前提,CommonJS模塊規範和ES6模塊規範徹底是兩種不一樣的概念。 require: node 和 es6 都支持的引入 export / import : 只有es6 支持的導出引入 module.exports / exports: 只有 node 支持的導出 CommonJS模塊規範 Node應用由模塊組成,採用CommonJS模塊規範。 根據這個規範,每一個文件就是一個模塊,有本身的做用域。在一個文件裏面定義的變量、函數、類,都是私有的,對其餘文件不可見。 CommonJS規範規定,每一個模塊內部,module變量表明當前模塊。這個變量是一個對象,它的exports屬性(即module.exports)是對外的接口。加載某個模塊,實際上是加載該模塊的module.exports屬性。 CommonJS規範,http://javascript.ruanyifeng.com/nodejs/module.html ES6模塊規範 不一樣於CommonJS,ES6使用 export 和 import 來導出、導入模塊。 ES6 Module 的語法,http://es6.ruanyifeng.com/#docs/module node模塊 Node裏面的模塊系統遵循的是CommonJS規範。 那問題又來了,什麼是CommonJS規範呢? 因爲js之前比較混亂,各寫各的代碼,沒有一個模塊的概念,而這個規範出來其實就是對模塊的一個定義。 CommonJS定義的模塊分爲: 模塊標識(module)、模塊定義(exports) 、模塊引用(require) 先解釋 exports 和 module.exports 在一個node執行一個文件時,會給這個文件內生成一個 exports和module對象, 而module又有一個exports屬性。他們之間的關係以下圖,都指向一塊{}內存區域。 1 exports = module.exports = {}; 那下面咱們來看看代碼的吧。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 //utils.js let a = 100; console.log(module.exports); //能打印出結果爲:{} console.log(exports); //能打印出結果爲:{} exports.a = 200; //這裏辛苦勞做幫 module.exports 的內容給改爲 {a : 200} exports = '指向其餘內存區'; //這裏把exports的指向指走 //test.js var a = require('/utils'); console.log(a) // 打印爲 {a : 200} 從上面能夠看出,其實require導出的內容是module.exports的指向的內存塊內容,並非exports的。 簡而言之,區分他們之間的區別就是 exports 只是 module.exports的引用,輔助後者添加內容用的。 用白話講就是,exports只輔助module.exports操做內存中的數據,辛辛苦苦各類操做數據完,累得要死,結果到最後真正被require出去的內容仍是module.exports的,真是好苦逼啊。 其實你們用內存塊的概念去理解,就會很清楚了。 而後呢,爲了不糊塗,儘可能都用 module.exports 導出,而後用require導入。 ES中的模塊導出導入 說實話,在es中的模塊,就很是清晰了。不過也有一些細節的東西須要搞清楚。 好比 export 和 export default,還有 導入的時候,import a from ..,import {a} from ..,總之也有點亂,那麼下面咱們就開始把它們捋清楚吧。 export 和 export default 首先咱們講這兩個導出,下面咱們講講它們的區別 一、export與export default都可用於導出常量、函數、文件、模塊等 二、在一個文件或模塊中,export、import能夠有多個,export default僅有一個 三、經過export方式導出,在導入時要加{ },export default則不須要 四、export能直接導出變量表達式,export default不行。 下面我們看看代碼去驗證一下 testEs6Export.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 'use strict' //導出變量 export const a = '100'; //導出方法 export const dogSay = function(){ console.log('wang wang'); } //導出方法第二種 function catSay(){ console.log('miao miao'); } export { catSay }; //export default導出 const m = 100; export default m; //export defult const m = 100;// 這裏不能寫這種格式。 index.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 //index.js 'use strict' var express = require('express'); var router = express.Router(); import { dogSay, catSay } from './testEs6Export'; //導出了 export 方法 import m from './testEs6Export'; //導出了 export default import \* as testModule from './testEs6Export'; //as 集合成對象導出 /\* GET home page. \*/ router.get('/', function(req, res, next) { dogSay(); catSay(); console.log(m); testModule.dogSay(); console.log(testModule.m); // undefined , 由於 as 導出是 把 零散的 export 彙集在一塊兒做爲一個對象,而export default 是導出爲 default屬性。 console.log(testModule.default); // 100 res.send('恭喜你,成功驗證'); }); module.exports = router; 從上面能夠看出,確實感受 ES6的模塊系統很是靈活的。
https://www.cnblogs.com/yangd...
class People{ constructor(){ this.name='張三' } sayHi(){ console.log('hi') } } function People(){ this.name='張三' } People.prototype.sayHi=function(){ console.log('hi') }