1.ES6
ES6,是ECMAScript 6 的簡稱,是JavaScript語言的下一代標準,已於2015年6月正式發佈。
1.1. let於const
之前,我們在編寫js定義變量的時候,只有一個關鍵字 var。var有一個問題,就是定義的變量會成爲全局變量。
// var變量的作用域問題檢查
for(var i = 0;i<5;i++){
console.log(i);
}
console.log("循環外:"+i);
可以看出,在循環外部也可以獲取到變量i的值。
let
關鍵字 :可以將i的作用域控制在循環內部。
//let 所聲明的變量,只在let命令所在的代碼塊內有效.
for(let i = 0;i<5;i++){
console.log(i);
}
//index.html:21 Uncaught ReferenceError: i is not defined
//console.log("循環外:"+i);
const
關鍵字:聲明的變量是常量,不能被修改,類似於java中的final關鍵字。
//const 所聲明的變量是常量,不能被修改,類似於java中的final關鍵字
const a = 1;
console.log("a = ",a);
//給a重新賦值;Uncaught TypeError: Assignment to constant variable.
//a = 2;
console.log("a = ",a);
1.2.字符串擴展
ES6中,爲字符串擴展了幾個新的API
-
includes()
:返回布爾值,標識是否找到了參數字符串 -
startWith()
:返回布爾值,標識參數字符串是否在原字符串的尾部 -
endWith()
:返回布爾值,標識參數字符串是否在原字符串的尾部
let str = "hello fechin";
console.log(str,"中是否包含了fechin ==>",str.includes("fechin"));
console.log(str,"中是否包含了fuck ==>",str.includes("fuck"));
1.3.字符串模板
ES6中提供了" ` "來作爲字符串模板標記
let str2 = `你好
哈哈
呵呵`;
console.log("試一試",str2);
//在``之間的部分都會被認爲是字符串的值,可以任意換行;
1.4.解構表達式
ES6中允許按照一定模式從數組和對象中提取值,然後對變量進行賦值,這被稱爲解構。
- 數組解構
let arr = [1,2,3];
const [x,y,z] = arr; //x,y,z將與arr中的每個位置來對應
console.log(x,y,z);
//結果爲[1,2,3]
const a = arr;
console.log("+++++",a);
//結果爲[1,2,3]
const [b] = arr;
console.log("-----",b);
//結果爲1
- 對象解構
const person = {
name : "fechin",
age : "12",
language : ["java","js","html"]
}
let {name,age,language} = person;
console.log(name,age,language);
//如果想要用其他變量接收,那麼需要額外指定別名
//{name:na}:name是person中的屬性名,冒號後面的n是解構後要賦值給的變量
let {name:na,age:ag,language:la} = person;
console.log("+-+-+-+-+-",na,ag,la);
1.5.函數優化
1.5.1.函數參數默認值
在ES6之前,我們無法給一個函數參數設置默認值,只能採用變通寫法
function add(a,b){
//判斷b是否爲空,爲空就給默認值0
if(!b){
b = 0;
}
//判斷b是否爲空,爲空就給默認值0
// b = b || 0;
return a + b;
}
console.log(add(1));
ES6之後,可以這麼寫
function add(a,b = 0){
return a + b;
}
console.log(add(1));
1.5.2.箭頭函數
//箭頭函數
//沒有參數
let sayHello = () => console.log("你好");
sayHello();
//一個參數
let print = a => console.log(a);
print("你好呀");
//多個參數
let sum = (a,b) => {return a+b;}
let result = sum(1,2);
console.log(result);
1.5.3.對象函數的屬性簡寫
let person = {
name : "fechin",
eat : function(food){
console.log(this.name+"在喫"+food);
},
//箭頭函數
drink : food => {
//不能從this.name中獲取到值,目前只能使用 person.name
console.log(person.name+"在喝"+food);
},
//直接寫函數
sleep(time) {
console.log(person.name+" just slepp: " + time +" minutes");
}
}
person.eat("象拔蚌");
person.drink("香蕉油");
person.sleep("60");
1.5.4.箭頭函數結合解構表達式
//傳統方式
function hello(person){
console.log("hello"+person.name);
}
hello(person);
//解構表達式與箭頭函數
const hello = ({age}) => {
console.log("++++"+age); //輸出爲 '++++21'
}
hello(person);
1.6.map和reduce
map()
:接收一個函數,將原數組中的所有元素用這個函數處理後返回。
let arr = ['1','20','30'];
console.log(arr);
let newArr = arr.map( s => parseInt(s));
console.log(newArr);
-
reduce()
:接收一個函數(必須)和一個初始值(可選),該函數接收兩個參數。- 第一個參數是上一次reduce處理的結果;
- 第二個參數是數組中要處理的下一個元素;
reduce()
:會從左到右依次把數組中的元素用reduce處理,並把處理的結果作爲下次reduce的第一個參數。如果是第一次,會把前兩個元素作爲計算參數,或者把用戶指定的初始值作爲起始參數。
const arr = [1,20,-5,3];
let result = arr.reduce((a,b) => {
return a + b;
});
console.log(result);
//19
let result2 = arr.reduce((a,b) => {
return a + b;
}, 1);
console.log(result2);
//20
1.7.擴展運算符
擴展運算符是三個點...
,將一個數組轉爲用逗號分隔的參數序列。
console.log([1,2,3]) //[1,2,3]
console.log(...[1,2,3]) //1,2,3
let add = (x,y) => {
return x+y;
}
let numbers = [1,2];
console.log(add(...numbers)); //3
//...可以用作數組的合併
let arr = [...[1,2,3],...[4,5,6]];
console.log(arr); //[1,2,3,4,5,6];
//與結構表達式結合
const [first,...rest] = [1,2,3,4,5];
console.log(first,rest); //1,[2,3,4,5]
//將字符串轉成數組
console.log([...'hello']);//['h','e','l','l','o']
1.8.Promise
Promise,簡單說是一個容器,裏面保存着某個未來纔會結束的事件(通常是一個異步操作)的結果,從語法上來說Promise是一個對象,從它可以獲取異步操作的消息,Promise提供統一的API,各種異步操作都可以用同樣的方法進行處理。
我們可以通過Promise的構造函數來創建Promise對象,並在內部封裝一個異步執行的結果。
const p = new Promise((resolve,reject) => {
//編寫異步操作,通常寫ajax的操作,(模擬)
setTimeout(()=>{
let num = Math.random();
if(num <0.5){
//認爲成功了
resolve("成功了"+num);//調用resolve,代表promise將返回成功的結果
}else{
//認爲失敗了
reject("失敗了"+num);//調用reject,代表promise將返回失敗的結果
}
});
});
p.then(value => {
console.log(value)
}).catch(value =>{
console.log(value);
});
1.9.Set和Map
ES6中提供了Set和Map的數據結構
- Set本質上與數組類似,不同在於Set中只能保存不同的元素,如果元素相同會被忽略,和java中的Set集合非常相似。
//set構造函數可以接受一個數組或空
let set = new Set();
set.add(1);//[1]添加
set.clear();//清空
set.delete(1);//刪除指定元素,並不是下標
set.has(2);//判斷是否存儲
set.forEach(s => console.log(s+1));//遍歷元素
set.size;//元素個數
let set2 = new Set([2,3,4,4]);//[2,3,4]
- Map本質上與Object類似的結構,不同的在於,Object強制規定key只能是字符串,而Map結構的key可以是任意對象,即:
- Object是
<String,Object>
集合 - map是
<Object,Object>
集合
- Object是
const map = new Map([
['key01','value01'],
['key02','value02']
]);
map.set('key03','value03');//添加
map.clear();//清空
map.delete('key01');//刪除
map.forEach((value,key)=>console.log(key,value));//遍歷元素,第一個拿到是value,第二個纔是key
map.size;//元素個數
map.values();//獲取value的迭代器
map.keys();//獲取key的迭代器
map.entries();//獲取entry的迭代器
for(let key of map.keys()){
console.log(key);
}
console.log(...map.values());
for(let entry of map.entries()){
console.log("+++++++++",entry);
}
1.10.class(類)的基本語法
JavaScript語言的傳統方法是通過構造函數定義並生成新的對象,ES6中引入了class的概念,通過class關鍵字自定義類。
class User {
//構造函數
constructor(name,age=20){
this.name = name;
this.age = age;
}
sayHello(){
return "hello,"+this.name;
}
//靜態函數
static isAdult(age){
if(age>=18){
return "成年人";
}
return "未成年人";
}
}
let user = new User("張三");
console.log(user);
console.log(user.sayHello());
console.log(User.isAdult(20));
class Somebody extends User{
constructor(){
super('李四');
}
test(){
return "test ->" +this.name;
}
}
let somebody = new Somebody();
console.log(somebody.test());
console.log(somebody.sayHello());
console.log(Somebody.isAdult(20));
1.11.Generator函數
Generator函數是ES6提供的一種異步編程解決方案,語法行爲與傳統函數完全不同;
Generator函數有兩個特徵:一是function命令與函數名之間有一個*
號,二是函數內部使用yield
定義不同的狀態。
function* hello(){
yield "hello";
yield "world";
yield "haha";
return "hehe";
}
let h = hello();
console.log(h); //類型是一個Generator對象
console.log(h.next()); //{value: "hello", done: false} done爲false標識並未執行完成
console.log(h.next()); //done:false
console.log(h.next()); //done:false
console.log(h.next()); //{value: "hehe", done: true}
console.log(h.next()); //{value: undefined, done: true}
for(let obj of h){
console.log("++++",obj);
}
/*
結果爲:
++++ hello
++++ world
++++ haha
*/
1.12.修飾器(Decorator)
修飾器是一個函數,用來修改類的行爲,ES2017引入了這項功能,目前Babel轉碼器已經支持。
@T
class User {
constructor(name,age = 20){
this.name = name;
this.age = age;
}
}
function T(target){ //定義一個普通方法
console.log(targer); //target對象爲修飾的目標對象,這裏是User對象
target.country = "中國"; //爲User類添加一個靜態屬性country(通過修飾器添加的屬性是靜態屬性)
}
console.log(User.country);
運行報錯:在ES6中,並沒有支持該用法,在ES2017中才有,需要進行編碼後才能執行,轉碼的意思是將ES6或ES2017轉成ES5執行。
1.13.轉碼器
- BabelBabel (babeljs.io)是一個廣爲使用的ES6轉碼器,可以將ES6代碼轉爲ES5代碼,從而在瀏覽器或其他環境執行。
- Google公司的Traceur轉碼器(github.com/google/traceur-compiler),也可以將ES6代碼轉爲ES5的代碼。
我們使用的阿里的開源企業級react框架:UmiJS.
# 安裝完node之後,開始安裝yarn,其中tyarn使用的是npm.taobao.org的源,速度要快一些,可以把yarn看成優化後的npm
npm i yarn tyarn -g #-g是全局安裝
tyarn -v #進行測試
tyarn global add umi #開始安裝
umi #進行測試
在項目路徑下:
#通過初始化命令生成package.json文件,它是NodeJS約定的用來存放項目的信息和配置等信息的文件
tyarn init -y
#通過umi命令創建index.js文件
umi g pages index #可以看到在pages下創建好了index.js和index.css文件
#1.12修飾器的js代碼拷貝到index.js
#通過執行命令啓動umi的後臺服務,用於本地開發
umi dev
通過查看網頁源代碼可以看到轉碼之後的代碼
1.14.模塊化
模塊化就是把代碼進行拆分,方便重複調用,類似java中的包,要使用一個包,必須先導包。而js中沒有包的概念,換來的是模塊的概念。模塊功能主要兩個命令構成 export
import
。
export
:命令用於規定模塊的對外接口;
class MyUtils{
static sum =(a,b) => a + b;
}
export default MyUtils;
import
:命令用於導入其他模塊提供的功能;
import MyUtils from './MyUtils';
console.log(MyUtils.sum(1,2));
2.ReactJS
2.1.前端開發的演變
到目前爲止,前端的開發經歷了四個階段,目前處在第四個階段
- 階段一:靜態頁面階段
在第一個階段中前端頁面都是靜態的,所有前端代碼和前端數據都是後端生成的。前端只是純粹的展示功能。js腳本的作用只是增加一些特殊效果,比如那時很流行用腳本控制頁面上飛來飛去的廣告。
那時候的網站開發,採用的是後端MVC模式,前端只是後端MVC的V
- 階段二:ajax階段
2004年,AJAX技術誕生,改變了前端開發,Gmail和Google地圖這樣革命性的產品出現,使得開發者發現,前端的作用不僅僅是展示技術,還可以管理數據並與用戶互動。
- 階段三:前端MVC階段
2010年,第一個前端MVC框架Backbone.js誕生,它基本上是把MVC模式搬到了前端,但是隻有M(讀寫數據)和V(展示數據),沒有C(處理數據)。有些框架提出了MVVM代替Controller。Model拿到數據後,VIew Model將數據處理成視圖層需要的格式,在視圖層展示出來。
- 階段四:SPA階段
前端可以做到讀寫數據,切換視圖,用戶交互,這意味着,網頁其實是一個應用程序,而不是信息的純展示,這種單張網頁應用被稱爲SPA(single-page-application)
目前最流行的前端框架 Vue ,Angular,React都屬於SPA開發框架。
2.2.ReactJS簡介
ReactJS就是一個用於構建用戶界面的JavaScript框架,是Facebook開發的一款JS框架。ReactJS把複雜的頁面拆分成一個個的組件,將這些組件一個個的拼裝起來,就會呈現多樣化的頁面
ReactJS圈內的一些框架簡稱:
- Flux:Flux是Facebook用戶建立客戶端Web應用的前端架構,它通過利用一個單向的數據流補充了React的組合視圖組件,這更是一種模式而非框架。
- Redux:Redux是JavaScript狀態容器,提供可預測化的狀態管理。Redux可以讓React組件狀態共享變得簡單。
- Ant Design of React:阿里開源的基於React的企業級後臺產品,其中集成了多種框架,包含了上面提到的Flux,Redux。Ant Design提供了豐富的組件。
2.3.環境搭建
- 第一步:輸入命令進行初始化
tyarn init -y
- 第二步:項目中添加umi的依賴
tyarn add umi --dev
在umi中,約定的目錄結構如下:
3. 第三步,在工程的根目錄下創建config目錄,在config目錄下創建config.js文件。在UmiJS的約定中,config/config.js將作爲UmiJS的全局配置文件。在config.js文件中輸入以下內容,方便後面使用
//導出一個對象,暫時設置爲空對象,後面再填充內容
export default {};
- 第四步,創建HelloWorld.js頁面文件
在umi中,約定存放頁面代碼的文件夾是在src/pages,
export default ()=>{
//這是ReactJS自創的寫法,叫做JSX
return <div>hello world</div>;
//在umi中,可以使用約定式的路由,在pages下面的JS文件都會按照文件名映射到一個路由,比如上面的這個訪問 /HelloWorld 會對應到HelloWorld.js.
}
- 第五步:啓動服務查看效果
umi dev
- 第六步:添加 umi-plugin-react 插件
tyarn add umi-plugin-react --dev
- 第七步:在config.js中引入該插件
export default {
plugins: [
['umi-plugin-react',{
//暫時不開啓任何功能
}]
]
};
- 第八步:構建與部署
umi build
2.4.ReactJS介紹
2.4.1.JSX語法
JSX語法就是,可以在js文件中插入html片段。JSX語法會被Babel轉碼工具進行轉碼,得到正常的js代碼再執行。
使用JSX語法,需要注意2點。
- 所有的html標籤必須是閉合的,如
<div>hello world</div>
- 在JSX語法中只能有一個根標籤,不能有多個。
- 在JSX語法中,如果想要在html標籤中插入js腳本,需要
{}
插入JS腳本。
export default ()=>{
//這是ReactJS自創的寫法,叫做JSX
const t =() => "你好";
return (<div>hello world {t()}</div>);
}
2.4.2.組件
- 自定義一個組件
import React from 'react';
class HelloWorld extends React.Component{
//render渲染
render(){
return (<div>Hello World ,name = {this.props.name},content= {this.props.children}</div>);
}
}
export default HelloWorld;
- 導入自定義組件
import React from 'react';
import HelloWorld from './HelloWorld';
class Show extends React.Component{
render(){
return <HelloWorld name="張三">你好呀</HelloWorld>;
}
}
export default Show;
輸出結果:
2.4.3.組件狀態
每個組件都有一個狀態,其保存在this.state中,當狀態值發生改變時,React框架會自動調用render()
方法,重新渲染頁面。
注意:
- this.state值的設置要在構造函數參數中完成;
- 要修改this.state的值,需要調用
this.setState()
完成,不能直接對this.state進行修改。
import React from 'react';
class List extends React.Component{
constructor(props){
super(props);
this.state = {
dataList : [1,2,3],
maxNum : 3
}
}
render(){
return (
<div>
<ul>
{
this.state.dataList.map((value,index)=>{
return <li key ={index}>{value}</li>
})
}
</ul>
<button onClick={()=>{
let maxNum = this.state.maxNum + 1;
let newArr = [...this.state.dataList,maxNum];
this.setState({
dataList : newArr,
maxNum : maxNum
})
}}>點我試試</button>
</div>
);
}
}
export default List;
2.4.4.生命週期
import React from 'react'; //第一步,導入React
class LifeCycle extends React.Component {
constructor(props) {
super(props);
//構造方法
console.log("constructor()");
}
componentDidMount() {
//組件掛載後調用
console.log("componentDidMount()");
}
componentWillUnmount() {
//在組件從 DOM 中移除之前立刻被調用。
console.log("componentWillUnmount()");
}
componentDidUpdate() {
//在組件完成更新後立即調用。在初始化時不會被調用。
console.log("componentDidUpdate()");
}
shouldComponentUpdate(nextProps, nextState) {
// 每當this.props或this.state有變化,在render方法執行之前,就會調用這個方法。
// 該方法返回一個布爾值,表示是否應該繼續執行render方法,即如果返回false,UI 就不會更新, 默認返回true。
// 組件掛載時,render方法的第一次執行,不會調用這個方法。
console.log("shouldComponentUpdate()");
}
render() {
return (
<div>
<h1>React Life Cycle!</h1>
</div>
);
}
}
export default LifeCycle;