Zeno Tian


  • 首页

  • 归档

  • 标签

Class

发表于 2016-11-11

阅读阮一峰老师的ES6入门的学习笔记。

Class 基本语法

基本概念

class关键字,可以看做语法糖。大部分功能ES5通过构造函数生成新对象都可以完成。class写法让对象原型的写法更清晰。

1
2
3
4
5
6
7
8
9
10
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);
1
2
3
4
5
6
7
8
9
10
11
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}

与ES5构造函数比较

定义

  • class Point等价于function Point

  • constructor是构造方法,等价于ES5中构造函数内定义的内容

  • this与ES5一样,代表实例对象

  • 定义“类”的方法不需要加上function关键字,直接写函数名以及函数体。与ES5在构造函数的 原型对象 上(Point.prototype)上定义方法

  • “类”的方法之间不需要逗号分隔

  • 可以使用Object.assign方法,一次向类添加多个方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Point {
    constructor(){
    // ...
    }
    }
    Object.assign(Point.prototype, {
    toString(){},
    toValue(){}
    });

    ​

使用

  • 与ES5构造函数一样,通过new命令创造实例对象

  • 与ES5 不同 类内部定义的方法是不可枚举的 (non-enumerable)

  • 类的构造函数,不使用new无法调用。ES5中构造函数可以不通过new调用

  • ES6 不存在变量提升所以需要先声明父类再使用

  • “类”的属性名,可以采用表达式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let methodName = "getArea";
    class Square{
    constructor(length) {
    // ...
    }
    [methodName]() {
    // ...
    }
    }

属性

  • 与构造函数相同typeof为function
  • Point.prototype.constructor也为自身

constructor

  • 类的默认方法,通过new生成对象实例时自动调用。
  • 没有定义时,会默认添加空的constructor方法
  • 默认返回对象实例(this)也可以返回别的对象
  • 类的构造函数,不使用new无法调用。

类的实例对象

  • 与ES5相同,实例的属性除非显示的定义在this上,否则都是定义在原型上class上
  • 与ES5相同,类的所有实例共享同一个原型对象

Class表达式

  • 和函数一样可以使用表达式形式定义

    1
    2
    3
    4
    5
    const MyClass = class Me {
    getClassName() {
    return Me.name;
    }
    }
    • 类的名字是MyClass
    • Me只能在Class内部可用
    • Me和函数名一样,可以省略
  • ​

gitignore配置规则

发表于 2016-11-09

.gitignore配置文件

.gitignore忽视规则

  • #号开始代表注释

  • /号代表当前目录(最开始)

  • !号后面的已被前面忽视规则忽视的文件或目录被排除出忽视

  • 后缀

    1
    2
    3
    4
    *.a
    #忽视已a为后缀的文件
    *.[ab]
    #忽视已.a以及.b为后缀的文件
  • 文件及目录

    1
    2
    3
    4
    5
    abc
    #忽视abc文件以及acb目录
    abc/
    #忽视abc目录
    /abc/忽视配置不生效的问题

忽视配置不生效的问题

在开发过程中经常会有需要将已经追踪过的文件添加为忽略文件,但是直接配置.gitignore文件是不会生效的。这时候需要先把本地缓存删除然后再提交

1
git rm -r --cached .

强制添加已被忽略文件

想要添加文件到Git但是已经被忽略的,可以通过-f强制添加到Git

1
$ git add -f filename

或者想修改.gitignore规则,可以使用git check-ignore命令检查当前文件是被.gitingore哪里的配置忽略掉的

1
$ git check-ignore -v filename

redux基础学习笔记

发表于 2016-11-09

Redux

Redux可预测的JavaScript应用程序的状态容器

帮助你写的应用行为一致,在不同的环境(client, server,native),更容易测试,提供更好的开发体验。

Start—React-Redux

安装依赖

1
2
npm install --save redux react-redux
npm install --save-dev redux-devtools

要点

  • 应用程序的整个状态存储在单个存储中的对象树中。(Redux状态容器中)
  • 改变状态树的唯一方法是发出一个动作action,一个描述发生了什么的对象。
  • 要指定动作action如何操作了状态树,需要自己编写reducer

redux

reducer一个纯函数用于(state, action) => state

描述了一个action如何将state转换为下一个state

状态的类型(形式)取决与你自己:它可以是基本类型,一个数组,一个对象,一个Immutable.js数据结构。

重要的一点是,你不应该改变状态对象(修改state),如何state改变了,将会返回一个新的对象。

三原则

  • 单一来源

整个应用程序的状态存储在单个存储中的对象树中。

  • state只读

改变状态的唯一方法是发出一个action,一个描述发生了什么的对象

  • 使用纯函数进行更改

要指定如何通过操作转换状态树,可以编写纯reducer。

编写纯函数reducer

基础

Actions

Actions

Actions是将数据从应用程序发送到store的行为。他们是store的唯一信息来源。您可以使用store.dispatch()将它们发送到store。

action是纯JavaScript对象。action必须具有指示要执行的操作类型的type属性。类型通常应定义为字符串常量。一旦应用程序足够大,可以将它们移动到一个单独的模块。

每个action尽量减少数据

Action Creators

Action Creators创建actiuon的函数,返回action。更容易测试

传统fulx中,dispatch通常在action Creators函数调用时触发。

1
2
3
4
5
6
7
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
}
dispatch(action)
}

在Redux中,进行分发,需要将Action Creators函数返回的结果传入dispatch()中

例如dispath(actionCreators(arg))

Reducers

Reducers

操作描述了事情发生的事实,但不指定应用程序的状态如何变化。

Designing the State Shape/设计state

应用的状态全部存储在单一的对象中,那么响应UI的状态如何做到最小?

state的状态应该使用ID进行存储,区分。更方便使用。

处理 Actions

reduce接收action和先前的state和动作,并返回下一个状态。

Reduce中不能进行的操作

  • 修改参数
  • 执行次要操作,例如:API调用,路由转换
  • 调用非纯函数:Date.now()或Math.random()

reduce应该是一个纯函数,输入相同返回应该相同

NOTE 不要修改旧的state,

Splitting Reducers 分割Reducers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
case ADD_TODO:
return Object.assign({}, state, {
todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
})
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: state.todos.map((todo, index) => {
if(index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
})
default:
return state
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
complate: !todo.complate
})
}
return todo
})
default:
return state
}
}
function visibilityFilyer (state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}
function todoApp (state = initialState, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
}
}

将state切片化。reduce组合是构建Redux应用程序的基本模式。

每个reduce只管理state的一部分。

Redux提供combineReducers()方法,可以拆分Reducer

Store

Store的职责

  • 管理 app state
  • 通过 getstate() 访问state
  • 通过 dispath(action) 更新state
  • 注册监听器 subscrive(listener)
  • 通过subscribe(listener)返回的函数处理监听器的注销。

一个app只能有一个store

Date Flow 数据流

Redux应用程序中的数据生命周期都遵循以下4个步骤

  • 调用 store.dispatch(action).

动作是描述发生了什么的简单对象,可以在任何地方调用

  • Store调用传入的reduce
  • 根reduce可以将多个reduce组合成一个状态树
  • store将根reduce返回的对象作为状态存储

    subscribe订阅取消订阅问题??

  • 创建store:let store = createStore(todoApp) 传入reduce
  • 执行订阅:返回值为取消订阅函数,执行reduce后触发回调?
1
2
3
let unsubscribe = store.subscribe(() =>
console.log(store.getState())
)
  • 触发dispatch
1
store.dispatch(addTodo('Learn about actions'))

接收action

异步操作

Actions

异步最重要的两个时间点:发送异步请求和接受到响应

两个时间点都需要改变应用状态,调用reducer。通常需要三种不同的操作

  • An action informing the reducers that the request began通知reducers异步操作开始

reducers修改状态为isFetching,UI显示微调框

  • An action informing the reducers that the request finished successfully.通知reducers请求完成

reducers可以通过将新数据合并到它们管理的状态并重置isFetching来处理此操作。 UI将隐藏微调框,并显示提取的数据。

  • An action informing the reducers that the request failed.通知reducers请求失败。

reducer可以通过重置isFetching来处理此操作。此外,一些reducer可能希望存储错误消息,以便UI可以显示它。

创建同步Action Synchronous Action Creators

Generator学习

发表于 2016-11-07

Generator

基本概念

  • Generator可以理解为一个状态机,封装了多个内部状态

  • 执行Genertaor函数会返回一个遍历器对象。

  • 特征

    • function关键字和函数名之间有一个*
    • 函数内部使用yield语句,用来定义不同状态。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function* helloWorldGenerator() {
    yield 'hello';
    yield 'world';
    return 'ending';
    }
    var hw = helloWorldGenerator();
    hw.next()
    // { value: 'hello', done: false }
    hw.next()
    // { value: 'world', done: false }
    hw.next()
    // { value: 'ending', done: true }
    hw.next()
    // { value: undefined, done: true }

    Generator函数调用不会执行,返回的是指向内部状态的指针对象。

    调用遍历器对象的next方法,使指针移向下移状态。

    每次调用next内部指针(执行流)从函数头部或者上次停止地方开始执行,直到下一个yield语句(或return)。

yield语句

  • next调用时
    • 执行到yield语句,暂停执行后面操作yield后表达之,作为返回的对象和的value
    • 再次调用yield继续向下执行,直到下一个yield语句
    • 执行到return语句,将return语句后表达式的值,作为返回对象的value
    • 函数没有return,返回value为undefined
    • yield语句后的表达式,调用时才会执行(惰性求值Lazy Evaluation)
  • yield与return
    • 都返回之后表达式的值
    • 一个函数只能有一个return,可以多个yield
    • yield不能在普通函数中使用

学习笔记——网络架构与七层参考模式

发表于 2016-10-28

计算机网络概论——网络基础

网络概览

Applications应用

通常人们如何通过什么途径认识网络?

  • 浏览器
  • 在线游戏
  • Email
  • 社交网络
  • 网络串流
  • 文件分享
  • 即时通讯

应用层协议

  • URL(Uniform resource locater)
  • HTTP(Hyper Text Transfer Protocol)
  • TCP(Transmission Control Protocol)

一次URL请求大概需要17次message?

  • 6个找到IP地址
  • 3次握手 TCP
  • 4次 HTTP
  • 4次 tearing down(取消)TCP

网络链接Network Connectivity

重要名词 Important terminologies

  • Link(设备连接 有线/无线)
  • Nodes(设备 电/手机)
  • Point-to-point(点对点)
  • Multiple access(两个以上的连接)
  • Switched Network(交换网络)
    • Circult Switched(线路交换)
    • Packet Switched(数据包交换)
  • Packet,message
  • Store-and-foward

Terminologies

  • Host(主机)
  • Switches(交换机)
  • Spanning tree(生成树协议)
  • internetwork(互联网)
  • Router/gateway(路由器)
  • Host-to-host connectivity(终端对终端连接)
  • Address
  • Routing(路由)
  • Unicats/broadcats/multicast(特定对象/广播/多个)
    • broadcats通常会被Router拦截
  • LAN(Local Area Networks 局域网)
  • MAN(Metropolitan Area Networks 城域网)
  • WAN(Wide Area Networks 广域网)

数据元是如何在互联网上被传输的?How datagrams are delivered in an Internet?

路由器之间会交换彼此网络状态,数据元会根据状态自动调整传输路线。

路由器可以将fragment(封包切分),当封包超过大小上限值的时候会被fragment。

每一个小的封包都具备完整的地址信息,可以被独立传送。

每一个小的封包都是独立的,所以每个小封包的路径可能会不一样,这样造成封包未必会按照顺序到达接受的Nodes

当封包过多次被Routing没有送达会被Router丢弃,就会存在丢包

合理的资源分配Cost-Effective Resource Sharing

  • resource资源:links and nodes
  • How to share a link?
    • Multiolexing(多个input共用一个links进行output)
    • De-multiplexing
FDM: Frequency Division Multiplexing 频道分割
TDM:Time-division Multiplexing 时间分割
Statistical Multiplexing 统计多工
  • Data is transmitted based on demand of each flow
  • FIFO先进先出, Round-Robin轮流,Priorities(Quality-of-Service(Qos)重要优先)

Logical Channels 逻辑频道

两个Host的连接,就叫做Logical Channel

Network Reliability 网络可靠性

  • 网络应该隐藏错误
  • Bits 丢失/错误
    • Bits error收到电场电磁波干扰,会出错(1,0错误)
    • 大量Bits错误,Burst errors。
    • 无法纠错会丢包
  • Packets are lost (Congestion)网络阻塞
  • Links and Node failures
  • Messages are delayed 延迟
  • Messages are delivered out-of-order 封包顺序错乱
  • Third parties eaves drop 第三次篡改

Network Architecture 网络体系结构

Protocols 协议

  • 定义横向通信规范
    • peer system
  • 上层协议需要下层提供服务
  • Building blocks of a network arch architecture
  • 每个协议有两个 interfaces
    • Service interface 为上层提供服务
    • Peer-to-Peer interface 对等网络

Protocols interface 协议接口

  • 横向
    • 格式
    • 流程
  • 纵向
    • 提供不同服务

Protocols 特点

  • Protocols Specification 协议规格
  • Interoperable 可以互通
  • IETF 制定协议

Protocol Architecture 协议结构

下层服务加值提供给上层协议服务

开放系统互连架构 OSA(Open Systems Interconnection) Architecture

结构分层

  • Application 应用层
  • Presentation 表现层/呈现层
  • Session 会话层
  • Transport 传输层
    • 负责分类不同服务
    • TCP/UTP
    • 只有两端host有
  • Network 网络层
    • 如何送给对方host
    • IP
  • Data Link 数据链路层
    • 如何传输数据给下一个Router(下一步)
  • Physical 物理层
    • 电缆,光纤,无线网络
    • 如何传输信号

Host如何和Router链接

Host => LAN(交换机) => Router

交换机只解析到Data Link链路层

链路层传输依靠物理层网卡位置信息

设备可以处理第几层,就是第几层的设备。

网络分层描述 Description of Layers

  • Physical Layer 物理层 如何在Link上传输

    • Coaxial cable 同轴电缆
      • Twisted pair 双绞线(搅在一起降低电磁干扰,8条线)
      • Optical Fiber 光纤 (不受电磁波干扰, 传输距离远)
      • Air space 电磁波 (wireless radio channel)
    • Different Signal Coding schems 不同编码
      • 发送和接受要求速率相同
      • 不同材料不同coding
  • Data Link Layer 链路层 (如何将frame传给直接相连的主机或者设备)

    • Collects a streame of bits into a frame
    • How to transmit a frame to a directly connected host (destination)?
    • MAC(Media Access Control Protocol) 媒体访问控制
      • CSMA/CD(IEEE 802.3 Ethernet) 监听是否有正在传输
      • CSMA/CA(IEEE 802.11 Wireless LAN)
    • Layer 2 devlces 2层设备
    • Switches 交换机
    • Bridges
  • Network Layer 网络层 (如何将封包送到目的地主机)

    • IP to IP
    • How to transmit frames to a host via the Internet?
    • Handle routing among nodes within a packet-switched network
    • Data exchanged between
    • IP protocol不可靠服务
    • Router之间互通状态,
    • Routing protocols 为了动态选择路径,依靠的protocol。网络层最重要的内容
      • RIP 第一代协议,每30秒交换一次状态
      • OSPF 会寻找最短路径
      • BGP
    • Routing Tables 路由状态信息会存入Routing Tables
      • Routing Tables 自身是动态维护的,所以Table的信息是会变的
      • 收到封包,获得header,根据ip查询Routing Tables,传递给下一个Router
  • Transport Layer(提供不同主机processes之间的数据传输)

    • Implements a process-to-process channer
    • Unit of data exchanges in this layer is called a message
    • TCP(Transmission Control Protocol) - Reliable service 可靠服务
    • UCP(User Datagram Protocol) - Unreliable service 不可靠服务
  • Session Layer 会话层

    • Provides a name space that is used to tie together the potentially different transport streamsthat are part of a single application
    • 将不同的streames汇合为一起
  • Presentation Layer 表现层/呈现层

    • Concerned about the format of data exchanged between peers
    • 双方数据的格式标准
  • Application Layer 应用层

    • Standardize common type of exchanges
    • FTP/E-mail/DNS/HTTP/Browsers..

Host有7层,Router只有传输层以下三层,交换机只有物理层和链路层

实际上使用中并不严格按照7层来,可以跳过中间的层。

网络性能Network Performance

  • 频宽 Bandwidth
    • `Number of bits per second
  • 1Mbps: 1 * 10^6 bits/second
  • 速度越快,bit宽度越窄
  • 信号传递时间 + 传输资料的时间 + queuing time
    • 距离/速度
    • size大小/bandwidth频宽
  • 问题
    • 传输完,前导资料未到()
    • 传输为完后才能,前导资料已到(transmission time)

Delay X Bandwidth

  • Delay X Bandwidth = pipe full 的资料量
  • Bandwidth 和 latency 哪个重要
    • 大档案传输Bandwidth重要
    • 小资料latency更重要
    • latency的动态 jitter jitter越大越不稳定
  • 在停下来等对方回应之前能够传输最多的资料量

Throughput

  • RTT(Round Trip Time) dominates
  • Throughput = TransferSize/TransferTime

学习笔记——gulp-util

发表于 2016-10-27

gulp-util

gulp的实用功能插件

使用

1
2
3
4
5
6
7
8
9
10
11
12
var gutil = require('gulp-util');
gutil.log('stuff happened', 'Really it did', gutil.colors.magenta('123'));
gutil.beep();
gutil.replaceExtension('file.coffee', '.js'); // file.js
var opt = {
name: 'todd',
file: someGulpFile
};
gutil.template('test <%= name %> <%= file.path %>', opt) // test todd /js/hi.js

log(msg…)

color

chalk的实例

replaceExtension(path, newExtension)

替换路径中文件的后缀名,返回一个新的路径。

isStream(obj)

判断一个对象是不是一个stream,返回布尔值。

isBuffer(obj)

判断一个对象是不是一个Buffer,返回布尔值。

template(string[,data])

这是一个封装的lodash.template函数。你不洗在一个

这是一个lodash.template函数包装。你必须传入有效的gulp文件对象,才能提供给给用户,否则会报错。您不能配置任何分隔符。看lodash文档的获得更多信息。

new File(obj)

参见 vinyl

1
2
3
4
5
var file = new gutil.File({
base: path.join(__dirname, './fixtures/'),
cwd: __dirname,
path: path.join(__dirname, './fixtures/test.coffee')
});

noop()

返回一个数据流,直接传输数据但是不进行任何操作

1
2
3
4
5
6
7
8
// gulp should be called like this :
// $ gulp --type production
gulp.task('scripts', function() {
gulp.src('src/**/*.js')
.pipe(concat('script.js'))
.pipe(gutil.env.type === 'production' ? uglify() : gutil.noop())
.pipe(gulp.dest('dist/'));
});

buffer(cb)

这类似于es.wait但不是缓冲文到string,而是缓冲区任何东西到一个数组(所以对于文件对象是非常有用的)。

返回一个可以供pipe的数据流

Stream竟会触发一个数据事件,将stream通过管道输送直到传输完毕。数据会像一个数组一样被传输到callback

Callback是可选的,接收两个参数:错误和数据

1
2
3
4
gulp.src('stuff/*.js')
.pipe(gutil.buffer(function(err, files) {
}));

new PluginError(pluginName, message[,options])

  • pluginName应该是你的插件的模块名称
  • message可以是string或者现有error
  • 默认情况下,栈将不会显示。如果你认为堆栈为你的错误很重要设置options.showStack为true。
  • 如果你在为堆栈将从被拉消息传递一个错误,否则将创建一个。
  • 需要注意的是,如果你在一个自定义堆栈字符串传递需要包括沿消息。
  • 错误属性将被包括在err.toString()。可以通过包括省略{showProperties: false}在选项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var err = new gutil.PluginError('test', {
message: 'something broke'
});
var err = new gutil.PluginError({
plugin: 'test',
message: 'something broke'
});
var err = new gutil.PluginError('test', 'something broke');
var err = new gutil.PluginError('test', 'something broke', {showStack: true});
var existingError = new Error('OMG');
var err = new gutil.PluginError('test', existingError, {showStack: true});

JS学习笔记——函数

发表于 2016-10-26

JavaScript学习笔记——函数

函数的概念

通过函数可以封装任意多条语句,而且可以在任何地方,任何时候调用执行。

函数对象

JavaScript中的函数就是对象。函数对象连接到Function.prototype该原型对象本身连接到Object.prototpye)。

每个函数在创建时会附加两个隐藏属性:函数的上下文和实现函数行为的代码(当JavaScript创建一个函数对象的时候,会给该对象设置一个”调用“属性。详见ECMAScript规范的”13.2 Creating Function Objects“)

函数的定义

函数声明语句

1
2
3
function sayHi () {
console.log('Hi!')
}

函数定义表达式

1
2
3
4
5
6
var sayYes = function () {
console.log('Yse!')
}
var sayHello = function foo() {
console.log('Hello!')
}

两种定义方式的区别

  • 函数名:以声明式方式定义的函数,实际上声明了一个变量并把函数对象赋值给它。 而以表达式方式定义的函数,函数名是可选的。如果一个函数定义表达式包含名称,函数的名称将成为函数内部的一个局部变量。
  • 声明提前:以声明式方式定义的函数,函数声明语句”被提前“到外部脚本或者外部函数作用域的顶部,所以可以被在它定义之前的代码调用。而函数定义表达式,会先声明一个变量,被声明的变量也会提前。但是在代码未执行完将函数赋值个这个变量的操作之前。这个函数是无法被调用的。

函数的参数

JavasScript中函数定义并不需要指定函数形参的类型,函数调用也不会对实参进行任何类型检查,甚至实参和形参个数不同也不会出现问题。原因是ECMAScript中的参数在内部是使用一个类数组的arguments对象来表示的。

形参

当调用函数时传入的实参比函数声明时指定的形参个数要少的时候,剩下的形参都会被设置为undefined。

可以通过判断if语句或者||运算符来实现参数的可选。

实参、实参对象

当调用函数时传入实参个数超过形参,没有办法直接获得未命名值的引用。而使用实参对象arguments可以解决这个问题。在函数体内arguments是指向实参对象的引用

arguments是一个类数组对象,可以通过数字下标获得传入函数的实参值。

在严格模式下和ECMAScript 5标准中,arguments是只读的。

函数的返回值

函数的4种调用模式

未命名

发表于 2016-09-29

教程

我们将构建一个简单但好用的评论框,一个类似于Disqus,LiveFyre或Facebook评论的实时评论基本版本。

我们将提供:

  • 展示所有评论的视图
  • 提交评论的表单
  • 为你提供服务的自定义后端
  • Hooks for you to provide a custom backend

将要实现的简单功能

  • 开放评论:评论在保存到服务器之前会出现在评论列表中,所以会感觉速度很快。
  • 实时更新:其他用户的评论将会被实时更新到评论列表中。
  • 支持MakeDown:用户可以使用MakeDown编辑文本

想要跳过这一切,只看源码?

一切都在Github上

运行服务器

为了开始教程,我们需要一个运行的服务器。这个服务器只会为我们提供用于获取和保存数据的API。为了让这一切更容易,我们已经通过一些脚本语言创建了我们需要的一个简单的服务器,您可以[查看源代码]或者[下载一个压缩文件],里面包含开成教程的一切代码。

为了简单起见,我们将在服务器上使用一个JSON文件作为模拟数据库。你不会在工作中用到这一点(以JSON作为数据库),但是他能很容易的模拟一个API让你使用。一旦你启动服务器,它将为我们的静态页面提供API。

入门

在本教程中,我们会尽量让一切变得容易。上面提到的服务器软件包包含了一个HTML文件,我们将要在这个文件中进行我们的工作。用你喜欢的编辑器打开public/index.html文件。它应该是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>React Tutorial</title>
<script src="https://npmcdn.com/react@15.3.1/dist/react.js"></script>
<script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.js"></script>
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/babel" src="scripts/example.js"></script>
<script type="text/babel">
// To get started with this tutorial running your own code, simply remove
// the script tag loading scripts/example.js and start writing code here.
</script>
</body>
</html>

对于本教程的其余部分,我们将在这个脚本标签来写我们的JsvaScript代码。我们没有使用任何先进的实时重载,所以你需要在保存后刷新浏览器才能看到更新。打开浏览器后地址栏输入http://localhost:3000(启动服务后)。当你第一次加载这个页面是看不到任何变化的,之后你将会看到我们构建结束后的效果。当你准好了要开始工作的时候,只要删除前面的<script>标签,然后就可以继续了。

注意

我们这里引入了jQuery,因为我们希望能够简化我们调用AJAX的代码,但它并不是React运行必须的。

你的第一个组件

React通过可组合的组件进行模块化的。对于我们评论框的列子,组成结构如下

1
2
3
4
- CommentBox
- CommentList
- Comment
- CommentForm

让我们创建CommentBox组件,它仅仅是一个简单的<div>:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// tutorial1.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
Hello, world! I am a CommentBox.
</div>
);
}
});
ReactDOM.render(
<CommentBox />,
document.getElementById('content')
);

需要注意的是HTML原生的元素名称以小写字母开头,而自定义的React组件标签以大写字母开头。

JSX语法

你会注意到的第一件事是在你的JavaScript中有XML的语法。我们有一个简单的预编译器会将这样的语法糖编译成普通的JavaScript:(这段代码展示是如何编译JSX的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// tutorial1-raw.js
var CommentBox = React.createClass({displayName: 'CommentBox',
render: function() {
return (
React.createElement('div', {className: "commentBox"},
"Hello, world! I am a CommentBox."
)
);
}
});
ReactDOM.render(
React.createElement(CommentBox, null),
document.getElementById('content')
);

它的使用是可选的,但是我们发现比起普通JavaScript,使用JSX语法会更简单。了解更多关于JSX语法文章。

这是怎么回事

我们通过JavaScript对象的一些方法React.createClass()创建一个新的React组件。最重要的,会通过render方法将React组件返回到HTML中渲染。

该<div>不是实际的DOM节点;they are instantiations of React components.他们是React的实例组件。You can think of these as markers or !pieces! of data that React knows how to handle.你可以认为这是一种标记,React知道如何处理的数据。我们生成的不是HTML字符串,所以是可以防止XSS攻击的。

你不用返回基本的HTML。You can return a tree of components that you (or someone else) built.你可以返回你(或者其他人)构建的组件。This is what makes React composable : a key tenet of maintainable frontends.这就是为什么React可以组件化,一种方便维护的前端的关键原则。ReactDOM.render()方法第二个参数,实例根组件,启动框架,同时将组件注入原生DOM元素中。

ReactDOM模块暴露出特定的DOM相关的方法, while has the core tools shared by React on different platforms (e.g., React Native).同时React拥有不同的核心工具 || React对于不同的平台(例如:[ReactNative]),React共享同样的核心工具。

It is important that remain at the bottom of the script for this tutorial. should only be called after the composite components have been defined.很重要的一点,ReactDOM.render要放在script中的底部。ReactDOM.render方法必须在确定组件组合完毕后才能调用。

撰写组件

Let’s build skeletons for and which will, again, be simple s.让我们再次通过简单的<div>来构建CommentList和CommentForm的骨架。将这两个组件添加到您的文件中,保留CommentBox的声明和ReactDOM.render的调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// tutorial2.js
var CommentList = React.createClass({
render: function() {
return (
<div className="commentList">
Hello, world! I am a CommentList.
</div>
);
}
});
var CommentForm = React.createClass({
render: function() {
return (
<div className="commentForm">
Hello, world! I am a CommentForm.
</div>
);
}
});

下一步,在CommentBox组件中使用这些新组件:

1
2
3
4
5
6
7
8
9
10
11
12
// tutorial3.js
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList />
<CommentForm />
</div>
);
}
});

请注意,我们如何是将HTML标签和我们自己构建的组件一起使用的。HTML组件是常规的React组件,就像你平时使用的HTML一样,但是有一点不同。The JSX compiler will automatically rewrite HTML tags to expressions and leave everything else alone.JSX编译器会自动重写HTML标记,通过React.createElement(tagName)方法生成,并且是独一无二的。这是为了防止全局命名空间污染。

使用props

通过父组件传递来的数据将会影响我们创建的Comment组件。Data passed in from a parent component is available as a ‘property’ on the child component.从父组件传递的数据对于子组件是可用的财产?These ‘properties’ are accessed through .这些”特性”通过访问this.props。使用props,我们能够从CommentList读取数据,传递给Comment, and render some markup:并渲染一些makeup,样式?标记?

1
2
3
4
5
6
7
8
9
10
11
12
13
// tutorial4.js
var Comment = React.createClass({
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{this.props.children}
</div>
);
}
});

By surrounding a JavaScript expression in braces inside JSX (as either an attribute or child), you can drop text or React components into the tree.

在JSX中,可以通过括号中的JavaScript表达式(作为一个标签,属性或者子元素),你可以将文本或React组件插入到DOM树。

1…34
Zeno Tian

Zeno Tian

38 日志
17 标签
GitHub
© 2017 Zeno Tian
由 Hexo 强力驱动
主题 - NexT.Mist