export/import導(dǎo)出/導(dǎo)入模塊
模塊功能主要由兩個命令構(gòu)成:export
和import
。export
命令用于規(guī)定模塊的對外接口,import
命令用于輸入其他模塊提供的功能。
ES6模塊不是對象,而是通過export命令顯式指定輸出的代碼,輸入時也采用靜態(tài)命令的形式。
// ES6模塊
import { stat, exists, readFile } from 'fs';
上面代碼的實質(zhì)是從fs模塊加載3個方法,其他方法不加載。這種加載稱為“編譯時加載”,即ES6可以在編譯時就完成模塊加載,效率要比CommonJS模塊的加載方式高。當(dāng)然,這也導(dǎo)致了沒法引用ES6模塊本身,因為它不是對象。
由于ES6模塊是編譯時加載,使得靜態(tài)分析成為可能。有了它,就能進一步拓寬JavaScript的語法,比如引入宏(macro)和類型檢驗(type system)這些只能靠靜態(tài)分析實現(xiàn)的功能。
除了靜態(tài)加載帶來的各種好處,ES6模塊還有以下好處。
不再需要UMD模塊格式了,將來服務(wù)器和瀏覽器都會支持ES6模塊格式。目前,通過各種工具庫,其實已經(jīng)做到了這一點。
將來瀏覽器的新API就能用模塊格式提供,不再必要做成全局變量或者navigator對象的屬性。
不再需要對象作為命名空間(比如Math對象),未來這些功能可以通過模塊提供。
默認(rèn)情況下,JavaScript中在模塊內(nèi)的所有聲明都是本地的,外部無法訪問。如果需要公開模塊中部分聲明的內(nèi)容,并讓其它模塊加以使用,這個時候就需要導(dǎo)出功能,最簡單的方式是添加export關(guān)鍵字導(dǎo)出模塊。
可以導(dǎo)出的內(nèi)容包括類、函數(shù)以及var、let和const修飾的變量。export命令可以出現(xiàn)在模塊的任何位置,只要處于模塊頂層就可以。如果處于塊級作用域內(nèi),就會報錯,import命令也是如此。
使用export命令定義了模塊的對外接口以后,其他 JS 文件就可以通過import命令加載這個模塊。
import命令具有提升效果,會提升到整個模塊的頭部,首先執(zhí)行。由于import是靜態(tài)執(zhí)行,所以不能使用表達(dá)式和變量,這些只有在運行時才能得到結(jié)果的語法結(jié)構(gòu)。
import后面的from指定模塊文件的位置,可以是相對路徑,也可以是絕對路徑,.js路徑可以省略。如果只是模塊名,不帶有路徑,那么必須有配置文件,告訴 JavaScript 引擎該模塊的位置。
導(dǎo)入單個導(dǎo)出
給定一個名為myExport的對象或值,它已經(jīng)從模塊my-module
導(dǎo)出(因為整個模塊被導(dǎo)出)或顯式地導(dǎo)出(使用export語句),將myExport
插入當(dāng)前作用域。
import {myExport} from '/modules/my-module.js';
導(dǎo)入多個導(dǎo)出
這將foo和bar插入當(dāng)前作用域。
import {foo, bar} from '/modules/my-module.js';
export default 和 export 區(qū)別:
1.export與export default均可用于導(dǎo)出常量、函數(shù)、文件、模塊等
2.你可以在其它文件或模塊中通過import+(常量 | 函數(shù) | 文件 | 模塊)名的方式,將其導(dǎo)入,以便能夠?qū)ζ溥M行使用
3.在一個文件或模塊中,export、import可以有多個,export default僅有一個
4.通過export方式導(dǎo)出,在導(dǎo)入時要加{ },export default則不需要
嚴(yán)格模式
ES6的模塊自動采用嚴(yán)格模式,不管你有沒有在模塊頭部加上"use strict";
。
嚴(yán)格模式主要有以下限制。
-變量必須聲明后再使用
函數(shù)的參數(shù)不能有同名屬性,否則報錯
不能使用
with
語句不能對只讀屬性賦值,否則報錯
不能使用前綴0表示八進制數(shù),否則報錯
不能刪除不可刪除的屬性,否則報錯
不能刪除變量
delete prop
,會報錯,只能刪除屬性delete global[prop]
eval
不會在它的外層作用域引入變量eval
和arguments
不能被重新賦值arguments
不會自動反映函數(shù)參數(shù)的變化不能使用
arguments.callee
不能使用
arguments.caller
禁止
this
指向全局對象不能使用
fn.caller
和fn.arguments
獲取函數(shù)調(diào)用的堆棧增加了保留字(比如
protected
、static
和interface
)
Components and Props
參考資料:https://reactjs.org/docs/components-and-props.html
function formatDate(date) {
return date.toLocaleDateString();
}
function Avatar(props) {
return (
<img
className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">{props.user.name}</div>
</div>
);
}
function Comment(props) {
return (
<div className="Comment">
<UserInfo user={props.author} />
<div className="Comment-text">{props.text}</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
const comment = {
date: new Date(),
text: 'I hope you enjoy learning React!',
author: {
name: 'Hello Kitty',
avatarUrl: 'http://placekitten.com/g/64/64',
},
};
ReactDOM.render(
<Comment
date={comment.date}
text={comment.text}
author={comment.author}
/>,
document.getElementById('root')
);
前面三段較為冗余的寫法:
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img
className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">{props.text}</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
頁面效果:
Hello Kitty
I hope you enjoy learning React!
6/4/2018
React Props
state 和 props 主要的區(qū)別在于 props 是不可變的,而 state 可以根據(jù)與用戶交互來改變。這就是為什么有些容器組件需要定義 state 來更新和修改數(shù)據(jù)。 而子組件只能通過 props 來傳遞數(shù)據(jù)。
Classes
constructor
構(gòu)造函數(shù)**constructor **
是用于創(chuàng)建和初始化類中創(chuàng)建的一個對象的一種特殊方法。
語法
constructor([arguments]) { ... }
描述
-
在一個類中只能有一個名為 “constructor” 的特殊方法。 一個類中出現(xiàn)多次構(gòu)造函數(shù) (
constructor)
方法將會拋出一個SyntaxError
錯誤。 - 在一個構(gòu)造方法中可以使用
super
關(guān)鍵字來調(diào)用一個父類的構(gòu)造方法。 - 如果沒有顯式指定構(gòu)造方法,則會添加默認(rèn)的 constructor 方法。
- 如果不指定一個構(gòu)造函數(shù)(constructor)方法, 則使用一個默認(rèn)的構(gòu)造函數(shù)(constructor)。
ES5的繼承,實質(zhì)是先創(chuàng)造子類的實例對象this,然后再將父類的方法添加到this上面(Parent.apply(this))。ES6的繼承機制完全不同,實質(zhì)是先創(chuàng)造父類的實例對象this(所以必須先調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this。
如果子類沒有定義constructor方法,這個方法會被默認(rèn)添加,代碼如下。也就是說,不管有沒有顯式定義,任何一個子類都有constructor方法。
constructor(...args) {
super(...args);
}
另一個需要注意的地方是,在子類的構(gòu)造函數(shù)中,只有調(diào)用super之后,才可以使用this關(guān)鍵字,否則會報錯。這是因為子類實例的構(gòu)建,是基于對父類實例加工,只有super方法才能返回父類實例。
extends
**extends**
關(guān)鍵字用于類聲明或者類表達(dá)式中,以創(chuàng)建一個類,該類是另一個類的子類。
語法
class ChildClass extends ParentClass { ... }
描述
extends
關(guān)鍵字用來創(chuàng)建一個普通類或者內(nèi)建對象的子類。
繼承的.prototype
必須是一個Object
或者 null
。
類的prototype屬性和proto屬性
大多數(shù)瀏覽器的ES5實現(xiàn)之中,每一個對象都有__proto__
屬性,指向?qū)?yīng)的構(gòu)造函數(shù)的prototype屬性。Class作為構(gòu)造函數(shù)的語法糖,同時有prototype屬性和__proto__
屬性,因此同時存在兩條繼承鏈。
(1)子類的proto屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。
(2)子類prototype屬性的proto屬性,表示方法的繼承,總是指向父類的prototype屬性。
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
上面代碼中,子類B的proto屬性指向父類A,子類B的prototype屬性的proto屬性指向父類A的prototype屬性。
這兩條繼承鏈,可以這樣理解:作為一個對象,子類(B)的原型(proto屬性)是父類(A);作為一個構(gòu)造函數(shù),子類(B)的原型(prototype屬性)是父類的實例。
B.prototype = new A();
// 等同于
B.prototype.__proto__ = A.prototype;
static
static關(guān)鍵字為一個類定義了一個靜態(tài)方法。
類相當(dāng)于實例的原型,所有在類中定義的方法,都會被實例繼承。如果在一個方法前,加上static
關(guān)鍵字,就表示該方法不會被實例繼承,而是直接通過類來調(diào)用,這就稱為“靜態(tài)方法”。
為什么要保存至PACKAGE.JSON?
因為node插件包非常大,版本龐雜,所以不加入package信息,模塊間的依賴變得非常困難,將配置信息寫入package.json并將其加入版本管理,其他開發(fā)者對應(yīng)下載即可(命令提示符執(zhí)行npm install,則會根據(jù)package.json下載所有需要的包)。 每個項目的根目錄下面,一般都有一個package.json文件,定義了這個項目所需要的各種模塊,以及項目的配置信息(比如名稱、版本、許可證等元數(shù)據(jù))。npm install 命令根據(jù)這個配置文件,自動下載所需的模塊,也就是配置項目所需的運行和開發(fā)環(huán)境。
PACKAGE.JSON 屬性說明:
- name - 包名。(不要把node或者js放在名字中)
- version - 包的版本號。
- dependencies - 項目運行所依賴的模塊
- devDependencies - 項目開發(fā)所需要的模塊
- bin - 這需要在你的package.json中提供一個bin字段,它是一個命令名和本地文件名的映射。在安裝時,如果是全局安裝,npm將會使用符號鏈接把這些文件鏈接到prefix/bin,如果是本地安裝,會鏈接到./node_modules/.bin/
使用npm卸載插件:npm uninstall < name > [-g] [--save-dev] PS:不要直接刪除本地插件包
查看當(dāng)前目錄已安裝插件:npm list
CNPM介紹:
官方網(wǎng)址:http://npm.taobao.org
安裝:命令提示符執(zhí)行npm install cnpm -g --registry=https://registry.npm.taobao.org
注意:安裝完后最好查看其版本號cnpm -v或關(guān)閉命令提示符重新打開,安裝完直接使用有可能會出現(xiàn)錯誤
Q:全局安裝和本地安裝的區(qū)別?
A:因為全局模式安裝,包可以供所有的程序使用。本地安裝則不可以。 npm 默認(rèn)會把包安裝到當(dāng)前目錄下。這反映了 npm 不同的設(shè)計哲學(xué)。如 果把包安裝到全局,可以提高程序的重復(fù)利用程度,避免同樣的內(nèi)容的多 份副本,但壞處是難以處理不同的版本依賴。如果把包安裝到當(dāng)前目錄, 或者說本地,則不會有不同程序依賴不同版本的包的沖突問題,同時還減 輕了包作者的 API 兼容性壓力,但缺陷則是同一個包可能會被安裝許多次。
Q:為什么進行了全局安裝還要進行本地安裝
1、在js實例代碼中,默認(rèn)下node.js會在NODE_PATH和目前js所在項目下的node_modules文件夾下去尋找模塊,因此,如果只是全局安裝,不能直接通過require()的方式去引用模塊,需要手動解決包路徑的配置問題,當(dāng)然你也可以復(fù)制全局安裝的node_modules文件夾到項目下,還有辦法可以選擇將環(huán)境變量的NODE_PATH設(shè)置為C:\Program Files\nodejs。
2.對于包的更新不好管理,可能你需要為每個包重新命名,如gulp@3.8.1、gulp@3.9.1...,為了區(qū)別不同項目使用指定的包,保證模塊之間的相互依賴,區(qū)別每個項目正常運行
Q:如何在package.JSON的dependencies和devDependencies寫入信息
npm install --save babel-cli和npm install -dev babel-cli使用這兩個命令安裝后可自動寫入文件
npm install --save-dev babel-cli也可以在一起用
參考文獻:http://www.lxweimin.com/p/f581cf9360a2
React Demo
class Square extends React.Component {
render() {
return (
<button className="square">
{this.props.value}
</button>
);
}
}
class Board extends React.Component {
renderSquare(i) {
return <Square value={i}/>;
}
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
class Game extends React.Component {
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{/* status */}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
}
// ========================================
ReactDOM.render(
<Game />,
document.getElementById('root')
);
Next player: X
012
345
678
參考文獻:https://reactjs.org/tutorial/tutorial.html
常用代碼注釋
改進1:setState
上面的代碼改成這樣:
class Square extends React.Component {
**constructor(props) {**
**super(props);**
**this.state = {**
**value: null,**
**};**
**}**
render() {
return (
<button className="square" **onClick={() => this.setState({value: 'X'})**}>
{this.state.value}
</button>
);
}
}
每當(dāng) this.setState
被調(diào)用時,都會計劃對組件的更新,導(dǎo)致 React 合并傳遞的 state(狀態(tài)) ,更新和渲染組件及其子組件。 當(dāng)組件渲染完成時,this.state.value
的值將是 'X'
,所以你會在網(wǎng)格中看到一個 X 。
如果您點擊任何方格,它里面應(yīng)該會出現(xiàn)一個 X 。
State(狀態(tài)) 提升
當(dāng)重構(gòu) React 組件時,提升 state(狀態(tài)) 是非常常見的. 當(dāng)您要聚合來自多個子節(jié)點的數(shù)據(jù) 或 使兩個子組件之間相互通信時,提升 state(狀態(tài)) ,使其存儲在父組件中。父組件可以通過 props(屬性) 把 state(狀態(tài)) 傳遞回子組件,以使子組件始終與父組件同步。
由于組件的 state(狀態(tài)) 被認(rèn)為是私有的,我們不能從 Square(方格) 組件直接更新 Board(棋盤) 的 state(狀態(tài)) 。
通常的模式是將一個函數(shù)從 Board(棋盤) 組件 傳遞到 Square(方格) 組件上,該函數(shù)在方格被點擊時調(diào)用。 再次修改 Board(棋盤) 組件中 renderSquare
,修改為:
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
我們把 Board(棋盤) 組件中 2 個props(屬性) 傳遞給 Square(方格) 組件:value 和 onClick。后者是一個函數(shù),Square(方格) 組件 可以調(diào)用該函數(shù)。
遇到的問題
1.’create-react-app' is not recognized as an internal or external command.
是環(huán)境變量問題。需要增加npm的環(huán)境變量路徑。
C:\Users\e******\AppData\Roaming\npm;
2. React 中的 registerServiceWorker是干什么的?
用于在生產(chǎn)環(huán)境中為用戶在本地創(chuàng)建一個service worker
來緩存資源到本地,提升應(yīng)用的訪問速度.
service worker是在后臺運行的一個線程,可以用來處理離線緩存、消息推送、后臺自動更新等任務(wù)。registerServiceWorker就是為react項目注冊了一個service worker,用來做資源的緩存,這樣你下次訪問時,就可以更快的獲取資源。而且因為資源被緩存,所以即使在離線的情況下也可以訪問應(yīng)用(此時使用的資源是之前緩存的資源)。注意,registerServiceWorker注冊的service worker 只在生產(chǎn)環(huán)境中生效(process.env.NODE_ENV === 'production')
常用命令
打開命令行 win+R cmd
打開環(huán)境變量:start-〉自己的圖標(biāo)-〉Change 沒有environment variables-〉上面的path。
查找環(huán)境變量path路徑:echo %PATH%