原文:https://www.cnblogs.com/li-li/p/10022288.html
一、es6的語法
1、let與var的區別
ES6 新增了let命令,用來聲明變量。它的用法類似於var(ES5),但是所聲明的變量,只在let命令所在的代碼塊內有效。如下代碼:
{ let a = 10; var b = 1; } a // ReferenceError: a is not defined. b // 1
上面代碼在代碼塊之中,分別用let和var聲明了兩個變量。然后在代碼塊之外調用這兩個變量,結果let聲明的變量報錯,var聲明的變量返回了正確的值。這表明,let聲明的變量只在它所在的代碼塊有效。
for循環的計數器,就很合適使用let命令,如下代碼:
for (let i = 0; i < 10; i++) { // ... } console.log(i); // ReferenceError: i is not defined
上面代碼中,計數器i只在for循環體內有效,在循環體外引用就會報錯。
2、var變量提升現象,如下代碼:
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10
上面代碼中,變量i是var命令聲明的,在全局范圍內都有效,所以全局只有一個變量i。每一次循環,變量i的值都會發生改變,而循環內被賦給數組a的函數內部的console.log(i),里面的i指向的就是全局的i。也就是說,所有數組a的成員里面的i,指向的都是同一個i,導致運行時輸出的是最后一輪的i的值,也就是 10。如果使用let,聲明的變量僅在塊級作用域內有效,最后輸出的是 6。
3、另外,for循環還有一個特別之處,就是設置循環變量的那部分是一個父作用域,而循環體內部是一個單獨的子作用域。
for (let i = 0; i < 3; i++) { let i = 'abc'; console.log(i); } // abc// abc// abc
上面代碼正確運行,輸出了 3 次abc。這表明函數內部的變量i與循環變量i不在同一個作用域,有各自單獨的作用域。
4、let不存在變量提升
var命令會發生”變量提升“現象,即變量可以在聲明之前使用,值為undefined。而let命令改變了語法行為,它所聲明的變量一定要在聲明后使用,否則報錯。如下代碼:
// var 的情況 console.log(foo); // 輸出undefined var foo = 2; // let 的情況 console.log(bar); // 報錯ReferenceError let bar = 2;
上面代碼中,變量foo用var命令聲明,會發生變量提升,即腳本開始運行時,變量foo已經存在了,但是沒有值,所以會輸出undefined。變量bar用let命令聲明,不會發生變量提升。這表示在聲明它之前,變量bar是不存在的,這時如果用到它,就會拋出一個錯誤。
5、let不允許在相同作用域內重復聲明同一個變量,如下代碼:
// 報錯 function func() { let a = 10; var a = 1; } // 報錯 function func() { let a = 10; let a = 1; }
6、ES6還添加了const命令,const聲明一個只讀的常量,一旦聲明,常量的值就不能改變,如下:
const PI = 3.1415; PI // 3.1415 PI = 3; // TypeError: Assignment to constant variable.
const聲明的變量不得改變值,這意味着,const一旦聲明變量,就必須立即初始化,不能留到以后賦值。也就是說,const只聲明不賦值,就會報錯。
const的作用域與let命令相同,即只在聲明所在的塊級作用域內生效,不能重復聲明,並且不存在變量提升。
7、ES6模板字符串
模板字符串(template string)是增強版的字符串,用反引號(`)標識。它可以當作普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量。模板字符串中嵌入變量,需要將變量名寫在${}之中。
let name = 'tom';
let str = `我是 ${name}.`
8、變量的解構賦值
ES6 允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱為解構(Destructuring)。
ES6 允許寫成下面這樣:
let [a, b, c] = [1, 2, 3];
上面代碼表示,可以從數組中提取值,按照對應位置,對變量賦值。
本質上,這種寫法屬於“模式匹配”,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。如果解構不成功,變量的值就等於undefined。
9、函數
(1)es5的普通函數,function聲明函數,如下:
function add(x) { return x; }; add(10); // 10
(2)函數對象的寫法,如下:
let add = function (x) { return x; }; add(10); // 10
(3)es6箭頭函數,如下:
let add = (x) => { return x; }; add(10) // 10
(4)上面的箭頭函數可簡寫成如下形式:
let add = x => x; add(10); // 10 // 如果箭頭函數的代碼塊部分多於一條語句,就要使用大括號將它們括起來,並且使用return語句返回。如下: var sum = (num1, num2) => { return num1 + num2; } // 如果箭頭函數直接返回一個對象,必須在對象外面加上括號,否則會報錯。如下: let getTempItem = id => { id: id, name: "Temp" }; // 報錯 let getTempItem = id => ({ id: id, name: "Temp" }); // 不報錯
10、es6的對象(this指向問題)
(1)匿名函數中this指向
// 字面量方式聲明一個對象person let person = { name: "tom", age: 30, fav: function () { console.log(this); // this指向 當前的調用者person對象 console.log(this.name); } }; person.fav() // {name: "tom", age: 30, fav: ƒ} // tom
(2)對象的單體模式,本質與上個示例一樣:
let person = { name: "tom", age: 30, fav(){ console.log(this); // this指向 當前的調用者person對象 console.log(this.name); } }; person.fav() // {name: "tom", age: 30, fav: ƒ} // tom
(3)箭頭函數中this指向
let person = { name: "tom", age: 30, fav: () => { console.log(this); // this指向 person的父級對象(上下文),即window console.log(this.name); } }; person.fav() // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
11、es6的類
(1)es5
function Person(name, age) { this.name = name; this.age = age; } // 基於原型給對象聲明方法,原型prototype是當前類的父類(繼承性) Person.prototype.showName = function () { console.log(this.name); }; let p1 = new Person('alex', 29); p1.showName() // alex
(2)es6
class Person{ constructor(name='alex', age=29){ // 單體模式 this.name = name; this.age = age; } showname(){ // 單體模式 console.log(this.name); // this指向當前對象Person } showage(){ console.log(this.age); } } let p1 = new Person(); p1.showname(); // alex
二、vue的基本語法
1、vue的介紹
(1)前端三大框架(可以去github查看三個框架的 star星):
vue 尤雨溪,漸進式的JavaScript框架
react Facebook公司,里面的(高階函數 es6)非常多,對初學者不友好
angular 谷歌公司,目前更新到6.0,學習angular得需要玩一下typescript
(2)cdn方式引用
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
(3)下載到本地引用
<script src='./vue.js'></script>
(4)庫和框架
上面vue.js文件是一個庫,小而精;
框架是功能比較齊全,像Django,大而全,功能比較多;
(5)實例化對象

示例代碼:
<script src="./vue.js"></script>
<script>
// 實例化對象
new Vue({
el:"#app",
// 這里data是一個對象,在后續學習中發現data中一般是一個函數
data:{
// 數據屬性
msg1:"黃瓜",
person:{
name:"alex"
},
msg2:'hello Vue',
isShow:'True'
},
methods:{
// 該組件中聲明的方法
},
watch:{
// 該組件中監聽的數據屬性
}
});
</script>
注意:如果是我們自己定義的屬性和方法,則全部暴露在外面,如果是vue實例對象自己屬性和方法,會在前邊加一個”$”進行區分。另外,data中有一個觀察者Observer,在觀察着一些數據是否發生了改變,若改變,則將改變后的值立馬渲染到DOM中對應的地方,控制台查看data效果如下圖:

2、vue的模板語法
<div id="app">
<!--模板語法-->
<h2>{{ msg1 }}</h2>
<h3>{{ 'haha' }}</h3>
<h3>{{ 1+1 }}</h3>
<h4>{{ {'name':'alex'} }}</h4>
<h5>{{ person.name }}</h5>
<h2>{{ 1>2?'真的':'假的' }}</h2>
<p>{{ msg2.split('').reverse().join('') }}</p>
</div>
3、vue的思想:數據驅動視圖,設計模式MVVM(model view viewmodel)
4、vue的基本指令(使用指令系統后邊一定是字符串,且字符串中的變量一定是數據屬性中已有的變量)
(1)vue的指令系統之v-text和v-html(***),如下:
<div id="content"> {{ msg }} <div v-text="msg"></div> <!-- v-text相當於innerText --> <div v-html="msg"></div> <!-- v-html相當於innerHTML --> </div> <script src="./vue.js"></script> <script> // 實例化對象 new Vue({ el:"#content", // data中是一個函數 函數中return一個對象,可以是空對象,但不能不return data(){ // 函數的單體模式 return{ msg:"<h2>alex</h2>" } } }); </script>
效果如下圖:

(2)條件渲染v-if和v-show,如下:效果如下圖:
<div class="box1" v-show="isShow">hello</div>
<div class="box2" v-if="isShow">hello</div>
分析:isShow為真則顯示div,為假則不顯示;
區別:v-show為假時相當於display:none;v-if為假時相當於移除該div,但是有一個占位的注釋”<!-- -->”;
官網對v-if和v-show的區別:
1)v-if 是“真正”的條件渲染,因為它會確保在切換過程中條件塊內的事件監聽器和子組件適當地被銷毀和重建。
2)v-if 也是惰性的:如果在初始渲染時條件為假,則什么也不做——直到條件第一次變為真時,才會開始渲染條件塊。
3)相比之下,v-show 就簡單得多——不管初始條件是什么,元素總是會被渲染,並且只是簡單地基於 CSS 進行切換。
4)一般來說,v-if 有更高的切換開銷,而 v-show 有更高的初始渲染開銷。因此,如果需要非常頻繁地切換,則使用 v-show 較好;如果在運行時條件很少改變,則使用 v-if 較好。
v-if與v-else:可以使用 v-else 指令來表示 v-if 的“else 塊”:
<div v-if="Math.random() > 0.5"> Now you see me </div> <div v-else> Now you don't </div> // 注意:v-else 元素必須緊跟在帶 v-if 或者 v-else-if 的元素的后面,否則它將不會被識別。
(3)v-bind和v-on
v-bind:標簽中所有屬性,如img標簽的src alt,a標簽的href title id class等,如下:
<img v-bind:src="imgSrc" v-bind:alt="msg">
v-bind:class='{active:isActive}'表示若isActive(數據屬性中定義的變量)為真,則對應div增加active類,否則不增加,如下:
<div class="box" v-bind:class='{active:isActive}'></div>
v-on:監聽js中的所有事件,如click,mouseover,mouseout等,如下:
<button v-on:click="clickHandler">切換顏色</button>
v-bind的簡便寫法是":",如:<div class="box" :class='{active:isActive}'></div>
v-on的簡便寫法是"@",如:<button @click="clickHandler">切換顏色</button>
(4)列表渲染v-for(不僅可以遍歷數組,還可以遍歷對象),如下:
<div id="app">
<ul v-if="res.status === 'ok'">
<!-- v-for的優先級是最高的 diff算法 -->
<li v-for='(item,index) in res.users' :key="item.id">
<h3>{{ item.id }} -- {{ item.name }} -- {{ item.age }}</h3>
</li>
</ul>
<div v-for='(value,key) in person'>
{{ key }}-----{{ value }}
</div>
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el:"#app",
data(){
return {
res: {
status: 'ok',
users: [
{id: 1, name: 'alex', age: 18},
{id: 2, name: 'wusir', age: 30},
{id: 3, name: 'yuan', age: 48}
]
},
person: {
name: 'tom'
}
}
},
methods:{
// 該組件中聲明的方法
},
watch:{
// 該組件中監聽的數據屬性
}
});
</script>
總結:遍歷數組時,一個參數是值,兩個參數是(值,索引);遍歷對象時,一個參數是值,兩個參數是(值,鍵)。
注意:一定要綁定一個標識(有id就綁定id,沒有id綁定index),則值改變會直接通過key查找,而不用再去遍歷查找,提升效率。
三、Vue應用示例
1、實現輪播圖,代碼如下:
<div id="app">
<img :src="images[currentIndex].imgSrc" @click="imgHandler" alt="">
<br />
<button @click="prevHandler">上一張</button>
<button @click="nextHandler">下一張</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
// Vue實例對象,可以有返回值vm,官網中就是用vm代表Vue實例對象
let vm = new Vue({
el: '#app',
data() {
return {
// 實際項目中images這個數據以及圖片是后端返回過來的
images:[
{id:1, imgSrc:'./images/1.jpg'},
{id:2, imgSrc:'./images/2.jpg'},
{id:3, imgSrc:'./images/3.jpg'},
{id:4, imgSrc:'./images/4.jpg'}
],
currentIndex:0
}
},
methods:{
nextHandler(){
this.currentIndex++;
if(this.currentIndex == 4){
this.currentIndex = 0;
}
},
prevHandler(){
this.currentIndex--;
if(this.currentIndex == -1){
this.currentIndex = 3;
}
},
imgHandler(e){
console.log(e); // e是當前事件對象
console.log(e.target); // 當前事件對象的目標對象
console.log(this); // this指當前Vue實例對象
}
},
// 組件創建完成時調用created函數,可發送ajax
created(){
// 注意:開定時器就要清定時器,后面會介紹在destroyed函數中清掉
setInterval(()=>{
// 定時器中若不用箭頭函數則this指則定時器對象
console.log(this); // 這時this指當前Vue實例對象
this.currentIndex++;
if(this.currentIndex == 4){
this.currentIndex = 0;
}
},2000);
// 若定時器中不用箭頭函數,也可以用下面方式
let _this = this;
setInterval(function () {
console.log(_this); // _this指當前Vue實例對象
},2000)
}
})
</script>
2、Vue中使用ajax(created是組件創建完成時執行),代碼如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
span.active{color:red}
</style>
</head>
<body>
<div id="app">
<span @click="clickHandler(index, category.id)"
v-for="(category,index) in categoryList"
:key="category.id"
:class="{active:index==currentIndex}">
{{ category.name }}
</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="jquery.min.js"></script>
<script>
let vm = new Vue({
el: '#app',
data() {
return {
categoryList:[],
currentIndex:0
}
},
methods:{
clickHandler(i, id){
this.currentIndex = i;
// 發起請求
$.ajax({
url:`https://www.luffycity.com/api/v1/courses/?sub_category=${id}`,
type:'get',
success:function (res) {
console.log(res);
}
})
}
},
// 組件創建完成時調用created函數,可發送ajax
created(){
$.ajax({
url:'https://www.luffycity.com/api/v1/course_sub/category/list/',
type:'get',
success:(res) => { // 若不用箭頭函數,則this指當前ajax對象
console.log(res); // res是請求接口收到的數據
// 根據響應數據的狀態字段判斷是否成功
if(res.error_no === 0){
var data = res.data;
this.categoryList = data; // this指當前Vue實例對象
let obj = {
id:0,
name:'全部',
category:0
};
// unshift方法表示在數組前插入一個元素
this.categoryList.unshift(obj)
}
},
error:function (err) {
console.log(err);
}
})
}
})
</script>
</body>
</html>
頁面運行效果如下圖:

依次點擊每一項,控制台效果如下圖:

3、實現音樂播放器,代碼如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.active{color:blue}
</style>
</head>
<body>
<div id="music">
<!-- audio 是HTML5的新標簽 -->
<!-- @ended 播放完成會自動調用該方法 -->
<audio @ended="nextHandler" :src="musicList[currentIndex].songSrc" controls autoplay></audio>
<ul>
<li @click="songHandler(index)"
v-for="(item,index) in musicList" :key="item.id"
:class="{active:index==currentIndex}">
<h5>歌名:{{ item.name}}</h5>
<p>歌手:{{ item.author}}</p>
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let musicList = [
{
id:1,
name:'於榮光 - 少林英雄',
author:'於榮光',
songSrc:'./static/於榮光 - 少林英雄.mp3'
},
{
id:2,
name:'Joel Adams - Please Dont Go',
author:'Joel Adams',
songSrc:'./static/Joel Adams - Please Dont Go.mp3'
},
{
id:3,
name:'MKJ - Time',
author:'MKJ',
songSrc:'./static/MKJ - Time.mp3'
},
{
id:4,
name:'Russ - Psycho (Pt. 2)',
author:'Russ',
songSrc:'./static/Russ - Psycho (Pt. 2).mp3'
}
];
new Vue({
el: '#music',
data() {
return {
musicList:[],
currentIndex:0
}
},
methods:{
songHandler(i){
this.currentIndex = i
},
nextHandler(){
this.currentIndex++;
if(this.currentIndex == 4){
this.currentIndex = 0;
}
}
},
created(){
// 實際項目中往往向后台要數據,賦值給數據屬性
this.musicList = musicList
}
})
</script>
</body>
</html>
四、Vue基礎知識
1、計算屬性(主要產生緩存的數據屬性,防止DOM性能消耗)
模板內的表達式非常便利,但是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板過重且難以維護。例如:
<div id="example"> {{ message.split('').reverse().join('') }} </div>
在這個地方,模板不再是簡單的聲明式邏輯。你必須看一段時間才能意識到,這里是想要顯示變量 message 的翻轉字符串。當你想要在模板中多次引用此處的翻轉字符串時,就會更加難以處理。所以,對於任何復雜邏輯,你都應當使用計算屬性。例如:
<div id="example"> <p>原數據: "{{ message }}"</p> <p>翻轉后的數據: "{{ reversedMessage }}"</p> </div> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // 計算屬性的 getter(計算屬性默認只有getter方法),計算屬性要有返回值 reversedMessage: function () { return this.message.split('').reverse().join('') // `this`指向vm實例 } } })
2、偵聽器(watch)
雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的偵聽器。這就是為什么 Vue 通過 watch 選項提供了一個更通用的方法,來響應數據的變化。當需要在數據變化時執行異步或開銷較大的操作時,這個方式是最有用的。
watch可以監聽單個屬性,如果想監聽多個屬性,則聲明多個屬性的監聽,如下:
<div id="app"> <p>{{ msg }}</p> <button @click='clickHandler'>修改</button> </div> <script src="vue.js"></script> <script> new Vue({ el:'#app', data(){ return { msg:"alex", age:18 } }, methods:{ clickHandler(){ this.msg = "wusir" } }, watch:{ // 監聽屬性'msg' 'msg':function (value) { console.log(value); if (value === 'wusir'){ this.msg = '大武sir'; } }, // 監聽屬性'age' 'age':function (value) { } } }) </script>
注意:計算屬性即可以監聽單個屬性,又可以監聽多個屬性,如下示例:
<div id="app"> <p>{{ myMsg }}</p> <button @click='clickHandler'>修改</button> </div> <script src="vue.js"></script> <script> new Vue({ el:'#app', data(){ return { msg:"alex", age:18 } }, methods:{ clickHandler(){ this.msg = "wusir"; this.age = 20; } }, computed:{ myMsg: function () { // 即監聽msg屬性,又監聽age屬性 return `我的名字叫${this.msg},年齡是${this.age}`; } } }) </script>
3、計算屬性的應用(上例中音樂播放器改為計算屬性實現)
修改audio標簽的src屬性值,如下:
<audio @ended="nextHandler" :src="currentSong" controls autoplay></audio>
Vue實例中增加計算屬性computed,如下:
computed:{ currentSong(){ // 既監聽了musicList,又監聽了currentIndex return this.musicList[this.currentIndex].songSrc } }
總結:計算屬性的方法即可以在模板語法中使用,又可以在指令系統中使用。
4、關於函數中this指向的問題
Vue實例對象中,一般methods和computed中定義的函數中的this是指當前Vue實例對象,而created中的ajax和定時器中定義的函數中的this是指ajax或者定時器對象,這時,ajax和定時器中的函數改為箭頭函數,就可以改變this的指向,即this指向當前Vue實例對象。
五、補充知識點
1、查看接口,如下圖:

2、json在線格式化工具:http://www.bejson.com/
3、自己查閱資料了解js中閉包。

