大廠面試-百度

 百度

 原生js

 閉包如何改變this指向?

閉包我的理解   函數內部還有一個函數,其做用就是能夠訪問上一層函數中的變量

  

下面的案例中函數內部有函數,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自定義函數參數傳遞爲字符串格式所遇到的程序開發問題。

 如何實現ul下的li事件綁定?

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())

        });

    });

 map和forEach的區別是什麼?

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()返回新的數組。

 如何實現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

 框架

 vue的數據傳遞有哪些?

\- 父組件向子組件傳值 --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',"我是小紅」);

  })

}

 vuex和eventbus的區別是什麼?

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()

    }

  }

})

 工程化

 git如何只上傳選定的文件?

進入你要操做的目錄,跟Linux環境同樣

git status ./           查看這個文件夾下的文件狀態,會列出有哪些沒有加入追蹤,哪些沒有commit

git add ./\*             把這個文件下的全部應該加入追蹤的,加入到暫存區

git commit -m "日誌描述" ./           把這個文件夾下能夠commit的,都commit到本地庫

git push                push到遠程庫

 git如何回滾?

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

 面試官出題

 將str=`<div><p>內容</p></div>`轉換成虛擬dom,考慮不符合html標籤的狀況

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>");  大功告成哈哈哈哈哈  呃。

 使用reduce將數組[1,2,3,4,5]變成[1,2,3,4,5,1,4,9,16,25]

\[1,2,3,4,5\].concat(\[1,2,3,4,5\].reduce((prev,cur)=>\[...prev, cur\*cur\], \[\]))

 使用reduce將[{name:'張三',class:21},...]中class爲'2年級1班'的學生選出來

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;

  }, {});

}

 module.exports,exports,export default,export const a的區別

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的模塊系統很是靈活的。

 分別用構造函數和class實現一個類,其中有屬性name='張三',方法sayHi()

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')

}
相關文章
相關標籤/搜索