一小時(shí)前端技術(shù)從入門到精通(放棄),前端從入門到精通

前言

最近這些年前端相關(guān)的技術(shù)的發(fā)展速度猶如坐上了火箭一般一日千里,新技術(shù)新框架層出不窮:Node.js、React、Angular、Vue... 端上有React Native、node-webkit,JavaScript竟然隱約有一統(tǒng)前端、后端、移動(dòng)端、PC端之勢...
不過與其說進(jìn)擊的JavaScript,我更覺得不如說天下技術(shù)本一家。愛掏網(wǎng) - it200.com就像“前端開發(fā)”“后端開發(fā)”“客戶端開發(fā)”等各種開發(fā)之間并沒有那么大的區(qū)別、只是對(duì)技術(shù)的細(xì)分,不同的編程語言、工具也都是在朝著高性能、可復(fù)用、開發(fā)友好的方向前進(jìn)。愛掏網(wǎng) - it200.comJavaScript也是在朝著這個(gè)方向前進(jìn),良好的生態(tài)和無數(shù)開發(fā)人員的努力使得它迎來了百花齊放的今天。愛掏網(wǎng) - it200.com

寫這篇文章的原因

這幾年作為“Java后端開發(fā)”的我其實(shí)做Windows C++客戶端開發(fā)的時(shí)間和寫Java后端的時(shí)間幾乎是五五開(對(duì),開掛般的工種...),前端技術(shù)其實(shí)以前也是我的心頭愛,不過這幾年算是荒廢了,只能看著前端同學(xué)的IDE流口水再厚著臉皮問“這幾行代碼是什么意思啊?”,前端GG心情好還會(huì)耐心解釋一番、要是心情不好就只能接收到“說了你也不懂”的眼神了...
最近終于有些時(shí)間,可以系統(tǒng)地學(xué)習(xí)梳理一遍前端知識(shí)了,這篇文章既是學(xué)習(xí)成果的自我總結(jié),也希望能對(duì)有興趣的同學(xué)有所裨益,由于我本身也還只是個(gè)前端菜鳥,文章如果有錯(cuò)誤或不當(dāng)之處還望大家斧正。愛掏網(wǎng) - it200.com

面向的對(duì)象

如前面所說,這篇文章分享給有興趣的、對(duì)前端技術(shù)不太熟悉的同學(xué)。愛掏網(wǎng) - it200.com但你應(yīng)該至少掌握了以下基礎(chǔ)知識(shí)(否則需要先充下電了哦):

  • HTML,至少得能手寫個(gè)html、header、body吧。愛掏網(wǎng) - it200.com
  • CSS,我知道大家都煩這個(gè)、下面我也不會(huì)說它的,但你至少應(yīng)該知道怎么在html中插入/引用css吧,再給body設(shè)置個(gè)背景色試試?
  • JavaScript,我指的是最基礎(chǔ)的,比如知道怎樣在html中插入/引用JavaScript,能看懂"document.getElementById('demo').innerHTML='Hello JavaScript'; "這行代碼。愛掏網(wǎng) - it200.com
  • 表單提交與Ajax,是不是就是一個(gè)刷新一個(gè)不刷新?... 但你至少應(yīng)該能用JavaScript寫出Ajax提交數(shù)據(jù)的Demo來。愛掏網(wǎng) - it200.com

如果你能熟練使用jQuery、Bootstrap,那么恭喜你,作為一個(gè)上古時(shí)代的前端高手,我相信你可以無障礙地閱讀下面的內(nèi)容!

參考資料

下面是相關(guān)的參考資料,本文充其量只是一個(gè)速成教程,真正的精華都在下面:

  • JavaScript 標(biāo)準(zhǔn)參考教程 ,阮一峰老師著。愛掏網(wǎng) - it200.com
  • ECMAScript 6 入門,還是阮一峰老師著,此書有紙質(zhì)版可以支持下哦。愛掏網(wǎng) - it200.com
  • MDN JavaScript 參考文檔,Mozilla的JavaScript參考文檔,信Firefox、得永生。愛掏網(wǎng) - it200.com

下文中還直接使用了很多阮一峰老師著作中的內(nèi)容,有些不成段落的語句可能沒有標(biāo)記成引用還望諒解。愛掏網(wǎng) - it200.com

JavaScript的核心語法部分相當(dāng)精簡,只包括兩個(gè)部分:基本的語法構(gòu)造(比如操作符、控制結(jié)構(gòu)、語句)和標(biāo)準(zhǔn)庫(就是一系列具有各種功能的對(duì)象比如Array、Date、Math等)。愛掏網(wǎng) - it200.com
不同的運(yùn)行環(huán)境(如瀏覽器、Node.js)也會(huì)提供額外的API供JavaScript調(diào)用,以瀏覽器為例,它提供的額外API可以分成三大類:

  • 瀏覽器控制類:操作瀏覽器,如window.open()愛掏網(wǎng) - it200.com
  • DOM 類:操作網(wǎng)頁的各種元素,如getElementById()愛掏網(wǎng) - it200.com
  • Web 類:實(shí)現(xiàn)互聯(lián)網(wǎng)的各種功能,如XMLHttpRequest愛掏網(wǎng) - it200.com

這一部分只介紹JavaScript的核心語法,示例代碼基本上都可以在Chrome或其它瀏覽器的開發(fā)者工具的Console中執(zhí)行。愛掏網(wǎng) - it200.com

ECMAScript與JavaScript

1996 年 11 月,JavaScript 的創(chuàng)造者 Netscape 公司,決定將 JavaScript 提交給國際標(biāo)準(zhǔn)化組織 ECMA,希望這種語言能夠成為國際標(biāo)準(zhǔn)。愛掏網(wǎng) - it200.com次年,ECMA 發(fā)布 262 號(hào)標(biāo)準(zhǔn)文件(ECMA-262)的第一版,規(guī)定了瀏覽器腳本語言的標(biāo)準(zhǔn),并將這種語言稱為 ECMAScript,這個(gè)版本就是 1.0 版。愛掏網(wǎng) - it200.com
阮一峰:《ECMAScript 6 入門》

簡而言之,ECMAScript是標(biāo)準(zhǔn),JavaScript是其實(shí)現(xiàn)(另外的ECMAScript方言還有Jscript和ActionScript)。愛掏網(wǎng) - it200.com
這好比Java標(biāo)準(zhǔn)也由JCP(Java Community Process)在維護(hù),因此既有Oracle JDK,還有OpenJDK、IBM JDK。愛掏網(wǎng) - it200.com

ECMAScript 6(下述簡稱ES6)

由于時(shí)間跨度、瀏覽器兼容性等原因,這篇文章將以2024年正式發(fā)布ECMAScript 6標(biāo)準(zhǔn)(也即ECMAScript 2024)作為基礎(chǔ)。愛掏網(wǎng) - it200.com與“上古時(shí)代”的JavaScript(ECMAScript 5于2009年發(fā)布)相比,ECMAScript 6加入了眾多的新特性,我認(rèn)為這也是這些年JavaScript騰飛的基礎(chǔ)之一。愛掏網(wǎng) - it200.com
自ECMAScript 6開始ECMAScript將每年發(fā)布一個(gè)版本,ECMAScript 2024、2024也已在當(dāng)年發(fā)布,不過其跨度不大、改變也不算多,有興趣的同學(xué)可以自行學(xué)習(xí)。愛掏網(wǎng) - it200.com

這么看來ECMAScript 6的意義相當(dāng)于C++11,同樣是時(shí)隔多年(C++11之前的一個(gè)標(biāo)準(zhǔn)是C++03...),同樣是堪稱大刀闊斧地“重新定義”...

哪里不一樣

let:你還在用"var"嗎?

ES6 新增了let命令,用來聲明變量。愛掏網(wǎng) - it200.com它的用法類似于var,但是所聲明的變量,只在let命令所在的代碼塊內(nèi)有效。愛掏網(wǎng) - it200.com
阮一峰:《ECMAScript 6 入門》

如下所示,"let"只在其所在的大括號(hào)范圍內(nèi)有效,可以視為“局部變量”。愛掏網(wǎng) - it200.com

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

另外不同于在Scala、Swift中"let"用來表示不變量(不要跟ES6記混了哦),ES6還是很常規(guī)地引入了"const"來表示常量:

const PI = 3.1415;

PI = 3;

解構(gòu)賦值:我連賦值都快看不懂了

ES6 允許按照一定模式,從數(shù)組和對(duì)象中提取值,對(duì)變量進(jìn)行賦值,這被稱為解構(gòu)(Destructuring)。愛掏網(wǎng) - it200.com
阮一峰:《ECMAScript 6 入門》

先看數(shù)組的解構(gòu),還是很簡單的:

let [a, b, c] = [1, 2, 3];
a //1
b //2
c //3

再看對(duì)象解構(gòu)并賦值到變量,初看也比較簡單:

let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

但如果變量名與屬性名不一致,必須寫成下面這樣:

let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined

上面代碼中,foo是匹配的模式,baz才是變量。愛掏網(wǎng) - it200.com真正被賦值的是變量baz,而不是模式foo。愛掏網(wǎng) - it200.com你記住了嗎?

Class:終于有正宮對(duì)象了

在ES6之前,生成實(shí)例對(duì)象的方法是通過構(gòu)造函數(shù)。愛掏網(wǎng) - it200.com下面就是這樣一個(gè)反人類的例子。愛掏網(wǎng) - it200.com

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

是的,ES6英雄般地又一次拯救了我們的腦細(xì)胞,請(qǐng)看下面的例子!沒錯(cuò),那個(gè)constructor函數(shù)代表了類的構(gòu)造方法(也可以不顯式定義哦)。愛掏網(wǎng) - it200.com

//定義類
class Point {

  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }

}

var point = new Point(2, 3);
point.toString();

Proxy、Reflect:動(dòng)態(tài)代理和反射不只Java有哦

不多說,直接上代碼,先看Proxy的例子,Proxy支持的攔截操作共13種,這里只展示它攔截get的操作。愛掏網(wǎng) - it200.com

let person = {
  name: "張三"
};

let proxy = new Proxy(person, {
  get: function(target, property) {
    if (property === 'name') {
      return "李四";
    } else {
      return "你猜";
    }
  }
});

person.name // "張三"
proxy.name // "李四"
proxy.age  // "你猜"

再看Reflect的,與Proxy對(duì)應(yīng)、它也有13種方法,這里也只展示對(duì)get的反射。愛掏網(wǎng) - it200.com

var myObject = {
  foo: 1,
  bar: 2,
  get baz() {
    return this.foo + this.bar;
  },
}

Reflect.get(myObject, 'foo') // 1
Reflect.get(myObject, 'bar') // 2
Reflect.get(myObject, 'baz') // 3

lambda:請(qǐng)叫我“箭頭函數(shù)”

作為這幾年的大熱門,lambda不出意外地也被加入到了ES6中,不過它的正式名稱是Arrow Functions即箭頭函數(shù)。愛掏網(wǎng) - it200.com其示例如下。愛掏網(wǎng) - it200.com

//箭頭函數(shù)
var sum = (num1, num2) => num1 + num2;

// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};

有沒有發(fā)現(xiàn)這個(gè)箭頭(=>)是用等號(hào)寫的箭頭,不同于Java里面那個(gè)橫線箭頭(->)?讓我們來復(fù)習(xí)下不同語言中的lambda表達(dá)式吧:

[](int a) -> bool { return a > 0; }  // C++,此例可以省略箭頭和"bool"返回值類型聲明
a -> a > 0  // Java
a => a > 0  // C#
a => a > 0;  //JavaScript
lambda a: a > 0  # Python
(lambda (a) (> a 0))  ;; Lisp

Promise:異步編程你怕不怕

Promise是ES6中提出的異步編程的一個(gè)解決方案,Java中與之接近的概念是Future(你也可以用Future來實(shí)現(xiàn)Promise機(jī)制,在Scala、Netty中也實(shí)現(xiàn)了Promise機(jī)制)。愛掏網(wǎng) - it200.com但也只能是接近,因?yàn)镴avaScript語言本身是單線程的(不討論Web Worker)、永不阻塞的、基于事件循環(huán)模型(Event Loop)的,用單純Java的思想會(huì)很難理解下面這段代碼的執(zhí)行結(jié)果為什么是“2 1”:

setTimeout(function(){console.log(1);}, 0);
console.log(2);

言歸正傳,ES6 規(guī)定,Promise對(duì)象是一個(gè)構(gòu)造函數(shù),用來生成Promise實(shí)例。愛掏網(wǎng) - it200.com下面代碼創(chuàng)造了一個(gè)Promise實(shí)例。愛掏網(wǎng) - it200.com

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

你可能會(huì)問“resolve”、“reject”是什么?可以說它們代表了“當(dāng)異步操作成功時(shí)的回調(diào)函數(shù)”、“當(dāng)異步操作失敗時(shí)的回調(diào)函數(shù)”,它們現(xiàn)在還未定義,它們會(huì)在后面由你在“.then”方法中傳入愛掏網(wǎng) - it200.com

先看一個(gè)簡單的例子,這里在then方法中只傳入了resolve函數(shù),未傳入reject回調(diào)函數(shù)。愛掏網(wǎng) - it200.com

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

再看一個(gè)Ajax的例子,好好理解下哦。愛掏網(wǎng) - it200.com

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出錯(cuò)了', error);
});

Module:官方模塊化,遠(yuǎn)離CommonJs/AMD/CMD保平安!

歷史上,JavaScript 一直沒有模塊(module)體系,無法將一個(gè)大程序拆分成互相依賴的小文件,再用簡單的方法拼裝起來。愛掏網(wǎng) - it200.com
阮一峰:《ECMAScript 6 入門》

簡單地說,Java有import、Python有import、C++有#include,可JavaScript一直沒法“引用”別的js文件。愛掏網(wǎng) - it200.com在此背景下,出現(xiàn)了:

  • CommonJs規(guī)范,用于服務(wù)端,Node.js的require是其實(shí)現(xiàn)。愛掏網(wǎng) - it200.com
  • AMD(Asynchronous Module Definition)規(guī)范,用于瀏覽器環(huán)境,RequireJS是其實(shí)現(xiàn)。愛掏網(wǎng) - it200.com
  • CMD(Common Module Definition)規(guī)范,由玉伯老師提出,用于瀏覽器環(huán)境,Sea.js是其實(shí)現(xiàn)。愛掏網(wǎng) - it200.com

怎么樣,頭暈了沒?還好自從有了ES6,生命里都是奇跡... ES6在語言層面實(shí)現(xiàn)了模塊功能,完全可以一統(tǒng)服務(wù)端和客戶端取代CommonJs/AMD/CMD,我們可以告別那個(gè)八仙過海各顯神通的時(shí)代了,感謝ES6為我們的防脫發(fā)事業(yè)做出的卓越貢獻(xiàn)!

上面純屬玩笑,無論如何,我們都要感謝為了JavaScript模塊化標(biāo)準(zhǔn)做出過貢獻(xiàn)的各位大神,他們的探索無疑為ECMAScript的模塊化標(biāo)準(zhǔn)做出了不可磨滅的貢獻(xiàn)!

言歸正傳,現(xiàn)在最新的主流瀏覽器都已經(jīng)支持ES Module,Node.js也開始支持ES Module標(biāo)準(zhǔn),我們現(xiàn)在可以只學(xué)習(xí)ES6的Module了,不用再關(guān)注CommonJs/AMD/CMD等之前的規(guī)范。愛掏網(wǎng) - it200.com
讓我們先在profile.js中用export來導(dǎo)出一組變量,注意除此之外還可以導(dǎo)出函數(shù)和類:

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};

再在main.js中用import來導(dǎo)入它們:

// main.js
import {firstName, lastName, year} from './profile';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

是不是很簡單呢?

其它:數(shù)組的map、reduce你造嗎?(ECMAScript 5.1)

這兩個(gè)數(shù)組的方法是早就在2011年發(fā)布的ECMAScript 5.1中就發(fā)布的,但我覺得還是有必要提一下的。愛掏網(wǎng) - it200.com它們的作用也相當(dāng)于Java8的Stream API中的map和reduce(及collect),示例如下:

// map示例
let numbers = [1, 5, 10, 15];
let doubles = numbers.map( x => x ** 2);

// doubles is now [1, 25, 100, 225]
// numbers is still [1, 5, 10, 15]


//reduce示例,后面那個(gè)"0"表示給sum的初始值
var total = [0, 1, 2, 3].reduce(function(sum, currentValue) {
  return sum + currentValue;
}, 0);

// total is 6

你應(yīng)該有注意到在上面的map示例中使用了箭頭函數(shù),如果你找茬能力強(qiáng)力的話,應(yīng)該發(fā)現(xiàn)了當(dāng)數(shù)組的map、reduce方法發(fā)布時(shí),那時(shí)還沒有箭頭函數(shù)呢!
那么問題來了,在沒有箭頭函數(shù)的時(shí)候,map、reduce是怎么用的呢? 答案很簡單,當(dāng)年用的是普通的回調(diào)函數(shù):

var numbers = [1, 5, 10, 15];
var doubles = numbers.map(function(value){return value ** 2;});

// doubles is now [1, 25, 100, 225]
// numbers is still [1, 5, 10, 15]

簡介

Node.js是一個(gè)JavaScript運(yùn)行環(huán)境(runtime),發(fā)布于2009年5月,由Ryan Dahl開發(fā),實(shí)質(zhì)是對(duì)Chrome V8引擎進(jìn)行了封裝。愛掏網(wǎng) - it200.com

簡單地說,Node.js是在瀏覽器之外的一個(gè)JavaScript運(yùn)行時(shí),在安裝了Node.js之后,你就可以在命令行中執(zhí)行JS了:

echo "console.log('Hello Node.js!');" > index.js
node index.js

//Hello Node.js!

與瀏覽器一樣,Node.js也為JavaScript提供了大量的額外API,如 fs(文件系統(tǒng))、net(網(wǎng)絡(luò))、os(操作系統(tǒng))等等。愛掏網(wǎng) - it200.com可以說在Node.js的加持下,JavaScript擁有了類似于Python的能力。愛掏網(wǎng) - it200.com

安裝

如何安裝Node.js就不詳述了,Mac下可以使用brew安裝,Windows下也有安裝包。愛掏網(wǎng) - it200.com
注意我安裝的node已經(jīng)是v9.3.0了,此章的Demo是以該版本為基本的。愛掏網(wǎng) - it200.com

npm

如果還是要類比的話,npm類似于Java體系中的Maven,負(fù)責(zé)進(jìn)行包管理。愛掏網(wǎng) - it200.com
有個(gè)不同之處在于Node.js已經(jīng)自帶了npm,不需要再額外安裝了。愛掏網(wǎng) - it200.com

開始之前

在使用之前,可以先做件事情,將npm的切換到淘寶鏡像,可以有效地解決下載包太慢的問題:

npm config set registry " https://registry.npm.taobao.org"

全局安裝和本地安裝

在使用"npm install xxx"命令時(shí)(這里xxx僅為示例),可以有一個(gè)"-g"的參數(shù),它表示將xxx安裝到全局目錄(我這是/usr/local/lib/node_modules)下,同時(shí)用"which xxx"命令可以發(fā)現(xiàn)在"/usr/local/bin"下面已經(jīng)有了一個(gè)xxx的軟鏈接,這樣我們就可以在任何目錄下執(zhí)行tnpm命令了。愛掏網(wǎng) - it200.com

如果不加"-g"呢? 那包就會(huì)被安裝到當(dāng)前目錄的"node_modules"目錄下,記住這一點(diǎn),下面我們的Demo馬上就要用到。愛掏網(wǎng) - it200.com

package.json

如果說npm類似于Maven,那么package.json就是pom.xml了,里面同樣記錄了項(xiàng)目信息及依賴。愛掏網(wǎng) - it200.com

用Node.js寫一個(gè)Web服務(wù)器

有了上面這些知識(shí)之后,我們馬上就可以開始實(shí)現(xiàn)一個(gè)Web服務(wù)器,目前使用Node.js下比較廣泛的Web框架是Express,好比Python里面的Django。愛掏網(wǎng) - it200.com

1.創(chuàng)建一個(gè)項(xiàng)目文件夾

你一定不想把你的home目錄弄亂是吧?

mkdir ExpressStarter
cd ExpressStarter

2.初始化項(xiàng)目

用npm init可以直接創(chuàng)建模塊,生成package.json,npm會(huì)詢問你包名、版本、入口點(diǎn)、Git倉庫之類的,直接回車可以使用默認(rèn)值,但在此Demo中入口點(diǎn)(entry point)請(qǐng)使用"index.mjs",后面我會(huì)說原因的。愛掏網(wǎng) - it200.com

npm init
package name: (expressstarter) com.spirit.test
version: (1.0.0)
description:
entry point: (index.js) index.mjs
test command:
git repository:
keywords:
author:
license: (ISC)

此時(shí)的package.json內(nèi)容如下:

{
  "name": "com.spirit.test",
  "version": "1.0.0",
  "description": "",
  "main": "index.mjs",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

3.安裝express并寫入package.json依賴

用一行命令就可以搞定了:

npm install --save express

沒錯(cuò),這行命令的意思就是在當(dāng)前目錄的"node_modules"下安裝express(及其所有依賴),并將express依賴寫到package.json中去,是不是很方便?

此時(shí)的package.json的內(nèi)容如下,express前面那個(gè)"^"相信你能猜到是什么意思:

{
  "name": "com.spirit.test",
  "version": "1.0.0",
  "description": "",
  "main": "index.mjs",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.2"
  }
}

4.編寫index.mjs

接下來就可以開始搬磚了,請(qǐng)?jiān)贓xpressStarter文件夾下創(chuàng)建index.mjs文件,再掏出你最愛的IDE/編輯器,把下面的代碼放進(jìn)去。愛掏網(wǎng) - it200.comDemo代碼僅僅11行,相信不用解釋你也能看懂。愛掏網(wǎng) - it200.com

import express from 'express'

let app = express();

app.get('/', function (req, res) {
    res.send('Hello World!');
});

app.listen(3000, function(){
    console.log('Example app listening on port 3000!');
});

5.運(yùn)行Demo

使用下述命令即可運(yùn)行我們的Demo:

node --experimental-modules index.mjs

如果你看到了"Example app listening on port 3000!"這行提示,那么馬上打開瀏覽器訪問"http://127.0.0.1:3000/" 看看效果吧!

你應(yīng)該注意到了"--experimental-modules"這個(gè)參數(shù),它跟我們使用".mjs"的文件名后綴的原因一樣:因?yàn)镹ode.js之前使用CommonJs規(guī)范,在引用其它模塊是使用的是"require"關(guān)鍵字,這里我們直接使用了ES6的"import",所以需要開啟這項(xiàng)目前還是實(shí)驗(yàn)性的功能,而為了與以前保持兼容、使用ES6 Module規(guī)范的模塊都需要使用".mjs"作為后綴名。愛掏網(wǎng) - it200.com

6.其它說明

Demo到這里就演示結(jié)束了,你心里可能有些疑惑,但如果想要深入鉆研就要靠你自己了。愛掏網(wǎng) - it200.com

但可以多說一些的是,在常規(guī)項(xiàng)目中,"node_modules"文件夾是要被加入到.gitignore里面去的、不要把它一起提交到git上去,其他同學(xué)在clone該項(xiàng)目后,直接在項(xiàng)目文件夾下執(zhí)行"npm install"就可以把依賴下載到"node_modules"文件夾里面了。愛掏網(wǎng) - it200.com
而且在package.json的"scripts"中可以加入編譯、清理之類的命令,其作用大致相當(dāng)于mvn compile、mvn clean。愛掏網(wǎng) - it200.com

先告訴大家一個(gè)不幸的消息:
上面的內(nèi)容其實(shí)還只介紹了JavaScript語法、Node.js及項(xiàng)目基本結(jié)構(gòu),還有一個(gè)用Node.js開發(fā)Web服務(wù)的Demo,可以說跟“前端開發(fā)”還沒有半毛錢的關(guān)系。愛掏網(wǎng) - it200.com

但是!Node.js、npm、package.json是現(xiàn)代前端工程的基石,我們需要它們來完成對(duì)前端工程的構(gòu)建(包括“編譯”、打包、測試等等)。愛掏網(wǎng) - it200.com

下面我們先來學(xué)習(xí)大名鼎鼎的React,并以此為出發(fā)點(diǎn)來學(xué)習(xí)各種前端構(gòu)建工具。愛掏網(wǎng) - it200.com

簡介

React是起源于Facebook的一個(gè)前端框架,虛擬DOM技術(shù)是其基石。愛掏網(wǎng) - it200.comReact提出了JSX語法,而組件化是其核心思想。愛掏網(wǎng) - it200.com

以“傳統(tǒng)”的方式將React引入頁面

先拋開Node.js那些東西,讓我們以傳統(tǒng)的方式在在頁面中引入React。愛掏網(wǎng) - it200.com你可以將下面的html代碼拷貝下來放到一個(gè)htm文件里面去,再用瀏覽器打開看看效果。愛掏網(wǎng) - it200.com




  
React



來看html中的那段JavaScript, "

Hello, world!

"是什么? 它不是字符串,因?yàn)闆]有引號(hào),很明顯它也不像是一個(gè)“正常的對(duì)象”。愛掏網(wǎng) - it200.com 這就是React獨(dú)有的JSX語法,是React創(chuàng)建虛擬DOM的一種方式,這個(gè)h1標(biāo)簽在稍后會(huì)被“編譯”(或稱翻譯)為一個(gè)真正的JavaScript對(duì)象。愛掏網(wǎng) - it200.com

可以發(fā)生html中的那個(gè)script標(biāo)簽的type是"text/babel"、而常規(guī)的JavaScript的type是"text/javascript",這是為什么? 這是因?yàn)镴SX語法很明顯和JavaScript是不兼容的,所以用到了JSX的地方都聲明為"text/babel"。愛掏網(wǎng) - it200.com

那babel又是什么?Babel是一個(gè)JavaScript“編譯器”,它可以使用了ES6特性的JavaScript代碼編譯為符合ES 5.1標(biāo)準(zhǔn)的代碼,也可以將JSX語法編譯為符合JavaScript語法的代碼,這里我們就是使用它來編譯了含JSX的代碼。愛掏網(wǎng) - it200.com

需要注意的是,在實(shí)際情況下編譯這一步是預(yù)先完成的、而不是像本Demo這樣在客戶端加載babel來完成,在Chrome的控制臺(tái)中你也可以看到Babel輸出的警告,不過這一章我們只講“傳統(tǒng)”方式,先不講構(gòu)建。愛掏網(wǎng) - it200.com

Component-組件

React中的組件是其基本設(shè)計(jì)思想,通過組件與JSX的組合,更是可以發(fā)揮出無窮的威力。愛掏網(wǎng) - it200.com那接下來就把Demo改造成一個(gè)使用組件完成試試,這里只展示JavaScript代碼了:

HelloMessage類中的render()方法就好比各種GUI庫里面的paint方法,在界面需要繪制時(shí)會(huì)被調(diào)用。愛掏網(wǎng) - it200.com
那props怎么來的? 在此例中,React會(huì)將{name:"Spirit"}作為props傳給HelloMessage組件。愛掏網(wǎng) - it200.com

State

React 把組件看成是一個(gè)狀態(tài)機(jī)(State Machines)。愛掏網(wǎng) - it200.com通過與用戶的交互,實(shí)現(xiàn)不同狀態(tài),然后渲染 UI,讓用戶界面和數(shù)據(jù)保持一致。愛掏網(wǎng) - it200.com
簡單地說,每個(gè)組件除開有props屬性外,還有一個(gè)state屬性,當(dāng)state發(fā)生改變時(shí),會(huì)觸發(fā)組件的render()方法。愛掏網(wǎng) - it200.com
所以我們?cè)賮砝^續(xù)修改Demo,實(shí)現(xiàn)在點(diǎn)擊時(shí)切換內(nèi)容顯示。愛掏網(wǎng) - it200.com

在此例中,我們實(shí)現(xiàn)了構(gòu)建方法并顯式地接收了props,還調(diào)用了super方法(與Java一樣,這應(yīng)該是構(gòu)建方法中的第一行代碼),并設(shè)置了state對(duì)象的值,當(dāng)組件被點(diǎn)擊時(shí)、state會(huì)被改變、render方法也會(huì)被再次調(diào)用。愛掏網(wǎng) - it200.com
其中的"onClick"是JSX的語法,與傳統(tǒng)的HTML寫法有所不同,具體的知識(shí)需要詳細(xì)學(xué)習(xí)JSX語法及事件相關(guān)的知識(shí)。愛掏網(wǎng) - it200.com

在上一章我們學(xué)習(xí)了React的基礎(chǔ)知識(shí),但我們都知道現(xiàn)在前端js與我們的html頁面是分離的,而且前端發(fā)布時(shí)一般都需要先進(jìn)行構(gòu)建,那么前端構(gòu)建又是怎么回事呢? 讓我們繼續(xù)用上面的Demo來管窺一番吧。愛掏網(wǎng) - it200.com

Gulp

Gulp是現(xiàn)在流行的前端構(gòu)建工具,其作用類似于Java體系中的Maven...等等,之前不是說npm也相當(dāng)于Maven嗎,為什么要使用Gulp而不直接使用npm scripts? 按我的理解,npm scripts更通用更靈活更底層,而Gulp更適合應(yīng)對(duì)前端資源構(gòu)建。愛掏網(wǎng) - it200.com

接下來我們就一步一步地搭建構(gòu)建環(huán)境,來構(gòu)建上一章的那個(gè)React Demo。愛掏網(wǎng) - it200.com

1.初始化項(xiàng)目

很常規(guī)地,創(chuàng)建文件夾,npm init即可。愛掏網(wǎng) - it200.com

mkdir ReactStarter
cd ReactStarter
npm init

2.安裝react依賴

通過npm安裝react、react-dom的Node.js包

npm install --save react react-dom

3.碼代碼

在項(xiàng)目目錄下創(chuàng)建"index.htm"文件,其內(nèi)容如下:




  
React

  

在項(xiàng)目目錄下創(chuàng)建"src"目錄,在其下新建"index.js"文件,內(nèi)容如下:

import React from 'react';
import ReactDOM from 'react-dom';

class HelloMessage extends React.Component {
    constructor(props) {
      super(props);
  
      /*
      * 如果不寫這行在下面的handleClick方法中獲取到的this指針將是undifined。愛掏網(wǎng) - it200.com
      * 具體原因可以看阮一峰老師的《ECMAScript 6 入門》。愛掏網(wǎng) - it200.com
      */
      this.handleClick = this.handleClick.bind(this);
  
      this.state = {liked: false};
    }
  
    handleClick() {
      this.setState({liked: !this.state.liked});
    }
  
    render() {
      let text = this.state.liked ? 'like' : "don't like"
      return 

Hello, I {text} {this.props.name}

; } } ReactDOM.render( , document.getElementById('root') );

4.配置Babel

前面有提到,JSX語法不是JavaScript標(biāo)準(zhǔn)、ES6也不一定是所有瀏覽器都兼容的,我們需要使用Babel來進(jìn)行“編譯”。愛掏網(wǎng) - it200.com

首先是通過npm安裝Babel及React、ES2024(即ES6)插件,注意指令是"--save-dev",將它們安裝為開發(fā)依賴。愛掏網(wǎng) - it200.com

npm install --save-dev babel-cli babel-preset-react babel-preset-es2024

然后在項(xiàng)目目錄下新建".babelrc"文件,這是Babel的配置文件,其內(nèi)容如下:

{
    "presets": [
        "react",
        "es2024"
    ],
    "plugins": []
}

5.配置Gulp

同樣地,先安裝Gulp及其Babel插件到開發(fā)依賴中去:

npm install --save-dev gulp gulp-babel

然后在項(xiàng)目目錄下新建"gulpfile.js"文件,這是Gulp的配置文件,其內(nèi)容如下所示,注意下這里仍然使用Node.js的"require"而不是"import"。愛掏網(wǎng) - it200.com

const gulp = require('gulp');
const babel = require('gulp-babel');

gulp.task('default', function() {
    // 將你的默認(rèn)的任務(wù)代碼放在這
    gulp.src(['src/*.js'])
    .pipe(babel())
    .pipe(gulp.dest('build'));
});

好了,Gulp和Babel都配置好了,在項(xiàng)目目錄下執(zhí)行下"gulp"命令構(gòu)建一下試試。愛掏網(wǎng) - it200.com
在build目錄下我們找到了"index.js",用編輯器打開其內(nèi)容,可以發(fā)現(xiàn)原來的JSX語法和ES6語法確實(shí)被“編譯”了,但卻是被編譯為了Node.js的語法,如"require",React也還是作為一個(gè)Node.js依賴沒有被編譯到一起,這樣的編譯結(jié)果無法在瀏覽器中正常使用,那要怎么辦呢?

6.配置Webpack

Webpack是一個(gè)前端資源打包工具,它能夠?qū)δK的依賴關(guān)系進(jìn)行分析,并將這些資源都打包成可在瀏覽器上運(yùn)行的形式。愛掏網(wǎng) - it200.com

同樣,先安裝Webpack的依賴:

npm install --save-dev gulp-webpack

再來修改下gulpfile.js,加上Webpack的流程:

const gulp = require('gulp');
const babel = require('gulp-babel');
const webpack = require('gulp-webpack');

gulp.task('default', function() {
    // 將你的默認(rèn)的任務(wù)代碼放在這
    gulp.src(['src/*.js'])
    .pipe(babel())
    .pipe(gulp.dest('build'))
    .pipe(webpack({
        output:{filename:'bundle.js'}
    }))
    .pipe(gulp.dest('build'));
});

再執(zhí)行"gulp"命令,"build"目錄下會(huì)生成"bundle.js",其中的內(nèi)容整合了"index.js"及其所有依賴。愛掏網(wǎng) - it200.com
現(xiàn)在打開項(xiàng)目目錄下的"index.htm",頁面應(yīng)該是運(yùn)行正常的,這下我們實(shí)現(xiàn)了一個(gè)初具雛形的前端構(gòu)建環(huán)境。愛掏網(wǎng) - it200.com

7.善后工作

此時(shí)可以再修改一個(gè)"package.json",去掉里面的"main"這項(xiàng),再往"script"中加入"build"腳本:

"scripts": {
    "build": "gulp"
}

這樣當(dāng)執(zhí)行"npm run build"命令時(shí),實(shí)際上也是啟動(dòng)了gulp進(jìn)行構(gòu)建工作。愛掏網(wǎng) - it200.com

總結(jié)

需要注意的是,這個(gè)構(gòu)建的Demo配置得比較簡單,代碼沒有壓縮、混淆,也沒有去除注釋,如果你在代碼里面寫了什么不夠友善的注釋、在單量之類的數(shù)據(jù)上用了隨機(jī)數(shù),小心被用戶一眼就看出來了哦。愛掏網(wǎng) - it200.com

實(shí)際的前端工程配置會(huì)比這復(fù)雜不少,各個(gè)BU、各個(gè)前端團(tuán)隊(duì)目前應(yīng)該也有不同的構(gòu)建工具及配置,革命尚未成功,同志仍需繼續(xù)學(xué)習(xí)!

這篇文章只是我作為一個(gè)前端菜鳥、淺嘗輒止地學(xué)習(xí)了一下前端相關(guān)的部分知識(shí)后的一個(gè)總結(jié),相信既不全面、也會(huì)有不少錯(cuò)誤之處,發(fā)出來一是希望能給同樣對(duì)前端技術(shù)感興趣的同學(xué)一點(diǎn)參考,也是希望能接受到大家的指導(dǎo)。愛掏網(wǎng) - it200.com
前端技術(shù)仍在飛速發(fā)展,想要真正的做到有些理解和感悟,還得不斷地學(xué)習(xí)與練習(xí),學(xué)而時(shí)習(xí)之,不亦說乎?

聲明:所有內(nèi)容來自互聯(lián)網(wǎng)搜索結(jié)果,不保證100%準(zhǔn)確性,僅供參考。如若本站內(nèi)容侵犯了原著者的合法權(quán)益,可聯(lián)系我們進(jìn)行處理。
發(fā)表評(píng)論
更多 網(wǎng)友評(píng)論0 條評(píng)論)
暫無評(píng)論

返回頂部

主站蜘蛛池模板: 欧美黑人又粗又硬xxxxx喷水| 黄色毛片免费看| 欧美激情xxxx性bbbb| 在线观看中文字幕第一页| 免费午夜扒丝袜www在线看| www天堂在线| 男人肌肌捅女人肌肌视频| 大象传媒在线观看| 亚洲第一页综合图片自拍| 99re5在线精品视频热线| 正在播放国产一区| 国产精品视频免费一区二区| 亚洲国产一区二区三区在线观看| (无码视频)在线观看| 最近最新最好的2018中文字幕| 国产成人a人亚洲精品无码| 久久国产精品99精品国产| 老师我好爽再深一点的视频| 干妞网免费视频| 亚洲黄色在线看| 3344永久在线观看视频免费首页| 欧洲最强rapper网站在线看| 国产午夜一级鲁丝片| 中文字幕无码视频专区| 精品人妻VA出轨中文字幕| 大bbwbbwbbwvideos| 亚洲国产片在线观看| 黄色香蕉视频网站| 无码视频一区二区三区| 免费播放哟哟的网站| 777精品成人影院| 日韩精品无码免费专区午夜不卡 | 股间白浊失禁跪趴老师| 很黄很色裸乳视频网站| 亚洲色国产欧美日韩| 一区二区三区影院| 日本边添边摸边做边爱喷水| 午夜精品久久久久久| 98精品国产综合久久| 最新亚洲人成无码网站| 四虎影院最新域名|