Refs to Components

The DOM returned from render() is virtual, so called Virtual DOM, and we can get any factual input(value) from a virtual object, such as access to value from a component.

The ref returned from ReactDOM.render

ReactDOM.render() will return a reference to your component’s backing instance(or null for stateless components)

var myComponent = ReactDOM.render(<MyComponent />, myContainer)

However, that the JSX doesn’t return a component. It’s just a ReactElement: a lightweight representation that tells React what the mounted component should look like.

var myComponentElement = <MyComponent title = 'title'/>; //This is just a ReactElement
`</pre>

<pre>`var myComponentInstance = ReactDOM.render(myComponent, myContainer); //a Virtual DOM
`</pre>

### The ref Callback Attribute

React supports a special attribute that you can attach to any component. The 'ref' attribute ca be a callback function, and this callback will be executed **immediately after the component is mounted**. The referenced component will be passed in as a parameter, and the callback function may use the component immediately, or save the reference for future use.

It's as simple as adding a `ref` attribute to anything returned from render:

<pre>`render: function(){
  return (
    &lt;TextInput ref={function(input){
      if(input != nill){
        input.focus();
      }
    }} /&gt;
  );
},
`</pre>

or use ES6 arrow funciton:

<pre>`render: function(){
  return &lt;TextInput ref={(c) =&gt; this._input = c} /&gt;;
},
componentDidMount: function{
  this._input.focus();
}
`</pre>

### The ref String Attribute

React also supports using a string as a ref prop on any component.
Add `ref` attribute to component so you can access to them via `this.refs`
  1. Assign a ref attribute to anything returned from render such as:

    `<input ref='myInput'>
    `
  2. In some other code, access the backing instance via this.refs as in

    `var input = this.refs.myInput;
    var inputValue = input.value;
    `

    A Complete Example

    `var MyComponent = React.createClass({
    handleClick: function(){

    if(this.myTextInput != null){
      this.myTextInput.focus()
    }
    

    },
    render: function(){

    return(
      &lt;div&gt;
        &lt;input type='text' ref={(ref) =&gt; this.myTextInput = ref} /&gt;
        &lt;input type='button' value='Focus the text input' onClick = {this.handleClick} /&gt;
      &lt;/div&gt;
    );
    

    }
    });

    ReactDOM.render(<MyComponent />, document.getElementById(‘example’));

Note: ref will be destroyed as component unmounted.

Component API

setState(nextState(obj)[, callback(function)])

设置 nextState 的某个键值, 然后下一次 EventLoop 的时候 this.state 会被更新
注意, setState 方法中的回调函数在组件重新渲染后才被调用

replaceState(nextState(obj)[, callback(function)])

类似于 setState(), 但是会删除已存在的 state 键, 相当于重新初始化State

forceUpdate([callback(function)])

强制渲染组件
注意该方法的回调函数也是在组件重新渲染完成后调用

getDOMNode()

返回组件所处的 DOM 元素

isMounted()

返回一个 Boolean 值, 如果组件加载到了 DOM, isMount() 返回 true.

React 顶层 API

React.createClass(obj)

创建一个 ReactClass(组件类), 参数是一个对象且必须有 render 属性. 该方法必须返回一个封闭的容器或 null/false(表示不渲染)

在该方法中, 所有的 this 都会在最终调用的时候绑定到创建的组件的构造器上.

React.createElement(TYPE(string|ReactClass)[, PROPS[, CHILDREN(ReactElement)]])

创建一个指定类型的 React 元素(要区分 ReactClass(通性) 和 ReactElement( 个性) 和 Virtual DOM(实例), 通过 ReactClass 创建 ReactElement, 然后实例化成 Virtual DOM: 比如 ButtonComponent 是 Class, 而<ButtonCompoennt />则是 Element, 最后通过 ReactDOM.render() 生成Virtual DOM)
第三个参数 Children 可以是人一个书的 React 元素

React.createElement('div', null, 
  React.createElement('p', null, 
    React.createElement(Component, {a:1})
  )
)
`</pre>

### React.cloneElement(TYPE(ReactElement)[, PROPS(object)[, CHILDREN(ReactElement)]])

克隆并返回一个新的 ReactElement(内部子元素也会随之克隆), 新返回的元素会保留就元素的 props, ref, key, 也会集成新的 props( 如果第二个参数不为 null)

<pre>`var Hello = React.createClass({
  render: function(){
    var span = &lt;span a = '1'&gt;Span&lt;/span&gt;;
    var newSpan = React.cloneElement(span,{b:'2'}, &lt;em&gt;EM&lt;/em&gt;);
    console.log(newSpan.props);
    return &lt;div&gt;Hello {span},{newSpan}&lt;/div&gt;;
  }
});
`</pre>

注意 createElement的第一个参数必须是字符串或者 ReactClass, 而 cloneElement 的第一个参数只能是 ReactClass

### React.createFactory(TYPE(string|ReactElement))

返回一个某种类型的 ReactElement 工厂函数, 可以利用返回的函数来创建一个 ReactElement( 配置 props 和 children)

<pre>`var Component = React.createClass({
  render:function(){
    return this.props.a == 1? &lt;p&gt;123&lt;/p&gt; : null;
  }
});

var p = React.createFactory(Component),
    ReactElementP = p{{a:1}},
    div = React.createFactory('div'),
    ReactElementDiv = div(null, ReactElementP);

React.render(
  ReactElementDiv, document.body
);
`</pre>

### React.render(REACTELEMENT(ReactElement), CONTAINER(DOMElement)[, CALLBACK(function)])

渲染一个 ReactElement 到 container 指定的 DOM 中, 并返回一个到该组件的引用. 如果提供了可选的回调函数, 则该函数会在组件渲染或更新之后调用

如果我们希望在组件外部可以获得组件内部(能通过 this 访问)的东西, 可以将 React.render 的返回值赋予一个变量, 在后续的调用中访问变量即可.

### React.unmountComponentAtNode(CONTAINER(DOMElement)

从 container 指定的 DOM 中移除已经加载的 ReactElement, 清楚相应的事件处理器和 state, 如果在 container 中没有存在的组件, 则不作处理
如果组件清除成功, 则返回 true

### React.renderToString(REACTELEMENT(ReactElement))

React 为服务端提供的一个方法, 可以直接输出 ReactElement 为 HTML 字符串, 将这些标记发送(比如 res.write(HTMLString))给客户端, 可以获得更快的页面加载速度, 并有利于搜索引擎的抓取

<pre>`var com = &lt;Component /&gt;
comHTML = React.renderToString(com) //HTMLString
`</pre>

### React.renderToStaticMarkup

类似于 React.renderToString, 但只生成纯粹的 HTML 标记字符串, 不会包含类似 dta-reactid 之类的 React 属性, 从而节约字节数

### React.initializeTouchs(ShouldUserTouch(boolean))

开启或关闭 React 的触摸事件机制, 传入参数 true 使 React 响应 Touch 事件

### React.Chilren

#### React.Children.map(obj children, function[, object context])

遍历子元素, 映射为一个新的子元素集合

<pre>`var Component = React.createClass({
  render: function(){
    return (
      &lt;ul&gt;
        {React.Children.map{
          this.props.children, function(){
            return &lt;li&gt;{child}&lt;/li&gt;
            }
          }
        }
      &lt;/ul&gt;
    )
  }
})

React.Children.forEach(obj children, function[, obj context])

遍历子元素, 对每个子元素执行回调, 但不会返回一个新的集合

React.Children.count(obj children)

返回子元素总个数

Updating With React.render

What does React.render do

  1. First, validate the inputs
  2. If there was no previous component, render as a new component
  3. Otherwise, compare the next component to the previous component using “shouldCUpdateComponent”
  4. If “shouldUpdateComponent” is true, update the component using ReactComponent.updateComponent. Otherwise, unmount and continue to render as a new component

React.render gives you a declarative way to use React’s update flow at the top level, similar to how re-rendering works inside a component. Many times, however, you can create a wrapper component so that you only have a single React.render call. This allows you to keep the logic inside components, which may be cleaner.

React 组件生命周期

Mounting/组件初始化相关

componentWillMount
componentDidMount

Updating/组件更新相关

componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
componentDidUpdate

Unmounting/组件移除相关

componentWillUnmount

Initial 相关

getDefaultProps
getInitialState

componentWillMount

在组件初始化前执行, 但仅执行一次, 即使多次重复渲染该组件,或者改变组件的 state
如果希望该回调能执行多次, 可以使用 React.unmountComponentAtNode 移除已有的组件, 然后重新 render

componentDidMount

在组件初始化完成时触发, 同样只能触发一次

componentWillReceiveProps

在组件接收到新的 props 的时间点之前调用, 注意初始化的时候不会触发(此时初始化 props, 而不是获得新的 props), 但是如果组件重复渲染(没有移除), 则会触发此事件

shouldComponentUpdate

组件接收到新的 props 或 state 的时候(此时还没进行下一次 render) 会立即调用, 然后通过返回布尔值决定是否要重新渲染当前组件
该接口接收两个参数, 第一个参数表示新的props, 第二个表示新的 state

shouldComponentUpdate:function(){return true} //重新渲染组件

componentWillUpdate

shouldComponentUpdate 返回 true 的时候调用, 此时 props 和 state 都是更新后的值, 而组件尚未重新渲染

componentDidUpdate

重新渲染后才会触发

componentWillUnmount

组件被移除之前触发, 用于做一些必要的清理, 比如无效的定时器等

getDefaultProps

该方法是最先触发的, 可以在该方法中 return 一个对象作为组件的默认 Props(当然如果有从父组件传来的 props, 则以传进来的为主)
只在组件初始化的时候执行一次

getInitialState

Webpack

Webpack 是一款模块加载兼打包工具, 能把各种资源, 例如 JS(X), coffee, css(sass/less), 图片等都作为模块来使用和处理

可以直接使用 require 的形式来引入各模块, 即时他们可能需要经过编译, webpack 上有各种健全的加载器(loader)会处理这些事情.

Webpack 优势

  1. webpack 是一 commonJS 的形式来书写脚本的, 但对 AMD/CMD 的支持也很全面, 方便就项目进行代码迁移
  2. 能被模块化的不仅是 JS 了
  3. 开发便捷, 能替代部分 grunt/gulp 工作, 比如打包, 压缩混淆, 图片转 base64等
  4. 扩展性强, 插件机制完善, 特别支持 React 热拔插(react-hot-loader).

安装与配置

常规使用 npm 安装
$npm install -g webpack
如果是常规项目, 还是把依赖写入 package.json 更好

$npm init
$npm install --save-dev webpack
`</pre>

### 配置

每个项目下都必须配置一个 webpack.config.js, 他的作用如同常规的 gulpfile.js, 就是一个配置项, 告诉 webpack 需要做什么

比如:

<pre>`var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');

module.exports = {
  //插件项
  plugins: [commonsPlugin],

  //页面入口文件配置
  entry:{
    index: './src/js/page/entry1.js'
  },

  //文件输出配置
  output:{
    path: 'dist/js/page',
    filename: '[name].js'
  },

  module:{
    //加载器配置
    loaders:[
      {test: /\.css$/, loader: 'style-loader!css-loader'},
      {test: /\.js$/, loader: 'jsx-loader?harmony'},
      {test: /\.scss$/, loader: 'style!css!sass?sourceMap'},
      {test: /\.(png|jpg)$/, loader: 'url-loader?limit-8192'}
    ]
  },
};
`</pre>

#### plugins 插件项

这里使用了一个 CommonsChunkPlugin 的插件, 用于提取多个入口文件的公共部分, 然后生成一个 common.js 来访方便多页面之间的复用

#### entry 是页面入口文件配置, output 是输出配置

决定入口文件要生成什么名字的文件, 存放到哪里

<pre>`{
  entry: {
    page1: './page1',
    //支持数组, 将加载数组中的所有模块, 但一最后一个模块为输出
    page2: ['./entry1','./entry2']
  },
  output:{
    path:'dist/js/page',
    filename: '[name].bundle.js'
  }
}
`</pre>

这段代码最终会生成一个page1.bundle.js, 和一个page2.bundle.js, 并存放到./dist/page下

#### module.loaders 是最关键的配置

告诉 webpack 每一种文件都要用什么加载器来处理
多个 loader 之间用'!'连接
所有加载器都要通过 npm 来加载
配置信息的参数'?limit=8192'表示将所有小于8kb的图片都转为 base64格式, 超过8kb 的图片用 url-loader 来处理

### 运行 webpack

`$webpack --display-error-details`
后面的参数'--display-error-details' 是推荐加上的, 方便出错的时候能查阅更详细的信息
其他主要参数有

<pre>`$webpack --config XXX.js //使用另一份配置文件
$webpack --watch //监听变动并自动打包
$webpack -p //压缩混淆脚本, 这个很重要
$webpack -d //生成 map 隐射文件, 告知哪些模块被最终打包到哪里
`</pre>

### 模块引入

#### HTML

直接在页面&lt;body&gt;中引入 webpack 最终生成的页面脚本即可

<pre>`&lt;body&gt;
  &lt;script scr = 'dist/js/page/common.js'&gt;&lt;/script&gt;
  &lt;script scr = 'dist/js/page/index.js'&gt;&lt;/script&gt;
&lt;/body&gt;
`</pre>

可以看到连样式都不需要, 脚本执行的时候会动态生成&lt;style&gt;并注入 head

#### JS

各脚本模块可以直接用 commonJS 来书写, 并可以直接引入未经编译的模块, 比如 JSX, Sass, coffee 等(只要在 webpack.config.js 中配置好加载器)
看一下编译前的页面入口文件(index.js)

<pre>`require('../../css/reset.scss'); //加载 Reset 模块
require('../../css/allComponent.scss'); //加载组件模块
var React = require('react');
var AppWrap = require('redux').createRedux;
var Provider = require('redux/react').Provider;
var stores = require('AppStore');

var redux = createRedux(stores);
var App = React.createClass({
  render: function(){
    return (
      &lt;Provider redux = {redux}&gt;
        {function() {return &lt;AppWrap /&gt;;}}
      &lt;/Provider&gt;
    );
  }
});

ReactDOM.render(
  &lt;App /&gt;,document.body
);

后续的都由 webpack 处理

Array.from()

Array.from() 方法可以将一个类数组对象或可遍历对象转化为真正的数组.
在 ES6 中, Class 语法允许我们为内置类型(比如 Array) 和自定义类新建子类(比如叫 subArray), 这些子类也会继承父类的静态方法, 比如 subArray.from(), 调用该方法后会返回子类 subArray 一个实例, 而不是 Array 的实例.

语法

Array.from(arrayLike[, mapFn[, thisArg]])
`</pre>

### 参数

#### arrayLike

想要转换成真实数组的类数组对象或可遍历对象

#### manFn

可选参数, 如果制定了该参数, 则最后生成的数组会经过 map 操作

#### this.Arg

可选参数, 执行 mapFn 时的 this 的值

### 描述

可以使用 Array.from()将下面的两种对象转换成数组
- 类数组对象(拥有 length 属性和若干索引属性的任意对象)
- 可遍历对象(可以迭代出其他对象, 比如有 Map 和 Set)

Array.from(obj,mapFn,thisArg) 相当于 Array.from(obj).map(mapFn,thisArg)

### 应用

<pre>`var obj = {length:5}; // return {length:5}
var arr =Array.from(obj); // namely Array.from({length:5}), return [undefined * 5]
Array.isArray(arr); //return true
var arr1 = Array.from(obj,(v,k) =&gt; k); //return [0,1,2,3,4]

package.json 属性

name

package.json 中最重要的属性是 name 和 version. 这两个属性是必须要有的, 否则模块无法被安装. 这两个属性一起形成了一个 npm 模块的唯一标识符.
模块中内容变化的同时, 模块版本也应该一起变化.
name 属性就是你的模块名称, 下面是一些命名规则:

  • name 必须小于等于214字节, 包括前缀名称在内(如../..module)
  • name 不能以’_’或’.’开头
  • 不能有大写字母
  • name 会成为 url 的一部分, 不能有 url 非法字符
  • 不要使用和 node 核心模块一样的名称
  • name 中不要有 ‘js’ 和 ‘node’

version

version 必须可以被 npm 依赖的一个 node-server 模块解析

description

一个描述, 方便别人了解你的模块的作用, 搜索的时候也有用

keywords

一个字符串数组, 方便别人搜到本模块

homepage

项目主页 url
注意: 这个项目主页 url 和 url 属性不同, npm 注册工具会认为你把项目发布到其他地方了, 获取模块的时候不是从官方仓库后去, 而是去 url 配置的地址

bugs

填写一个提交 bug 的地址或邮箱

{
 'url': 'https://www.ezcook.de/project/issue',
 'email': 'project@ezcook.de'
}
`</pre>

如果只填写一个, 可以返回字符串而不是对象

### license

为模块制定一个协议, 通知用户可以使用的权限, 最常见的是 BSD-3-Clause 或 MIT

<pre>`{'license': 'MIT'}
`</pre>

### author, contributors

### files

files 属性的值是一个数组, 内容是模块下文件名或文件夹名, 如果是文件夹名, 则文件夹下所有文件也会被包含.
可以在模块根目录下创建一个 '.npmignore' 文件, 写在这个文件里的文件会被排除在 file 属性

### main

main 属性指定程序的主入口文件, 比如这个模块(文件夹)命名为'foo', package.json中' main' 属性指定为'test.js', 则通过 require(foo)来使用模块的时候会滴啊用 test.js 脚本.
他应该指向模块根目录下得一个文件, 默认为 index.js

### bin

很多模块有一个或多个需要配置到 PATH 路径下的可执行模块...

### man

制定一个或通过数组指定一些文件夹让 linux 下的 man 指令查找文档地址

### directories

### repository

指定一个代码存放的地址

<pre>`'repository':
{
  'type':'git',
  'url':'https://github.com/...'
}

如果是 Github, 可以用缩写完成
‘repository’:’gist:…’`

scripts

scripts 属性是一个对象, 里面制定了项目的生命周期各个环节需要执行的命令, key 是生命周期中的时间, value 是要执行的命令
具体内容有 install, start, stop 等, 详情见npm/scripts

config

用来设置一些项目不怎么变化的项目配置, 如 port 等

dependencies

dependencies 属性是一个对象, 配置依赖模块的模块列表, key 是模块名称, vlaue 是版本范围, 版本范围是一个字符, 可以被一个或多个空格分隔.
比如
`
‘dependencies’:
{
‘foo’:’1.0.0 - 2.0.0’
‘foo1’:’>=1.0.0’
}

devDependencies

如果有人想下载并使用你的模块, 也许他们并不希望或需要下载一些你在开发过程中额外的测试或文档框架
这种情况下最好把这些依赖添加到 devDependencies 中, 这些模块会在 npm link 或者 npm install 的时候被安装, 也可以像其他 npm 配置一样被管理

使用 Npm 创建新工程

创建一个工程目录, 并 cd 到目录中, 运行
$npm init
这个工具将引导你创建一个 package.json 文件, 他只覆盖了大多数一般的项目, 并尽量让默认内容全面.
运行npm help json 获取 package.json 中的各个字段的文档及其定义
后面可以用
npm install &lt;pkg&gt; --save
来安装一个包并将其存储为 package.json 文件中的一个依赖模块
任何时间按下^C 退出.
简单来说:
npm init 创建或修改一个项目中的 package.json 文件
默认名称(显示在括号中)是当前文件夹的名字, 如果对于提示不输入任何字符并按下 Enter 键, npm 会将默认名称当做项目名称.
在完成提示内容后, npm init 将会给你一个即将创建的 package.json 文件的预览, 对于我们来说, 他看起来是这样的

{
"name":"project-name",
"version":"0.0.0",
"description":"...",
"main":"index.js",
"scripts":{
  "test":"echo \"Error:no test specified\" &amp;&amp; exit 1"
},
"keywords":["npm","example"],
"author":"YourName","license":"MIT"
}
`</pre>

按下 Enter 进行确认, 你可以在后面随时修改, 通过编辑 package.json 或再次运行 npm init.
npm init 永远也不会移除你放在 package.json 中的信息, 仅仅根据需求进行调整.

### package.json

一个项目的 package.json 文件担任下列角色
- 他为 npm 提供一切信息
- 他告诉 Node 怎样处理一个包
- 他为人们查看项目提供一个进入点

### 创建一个包进入点

现在创建一个非常简单的脚本并将它存为 index.js

<pre>`//index.js
console.log("Hello, npm");
`</pre>

我们可以直接运行脚本

<pre>`$node index.js
Hello, npm
`</pre>

我们可以通过使用 require, 在其他的 Node 应用中应用这段脚本. 首先进入 Node REPL, 一个交互的命令行环境:

<pre>`$node
&gt; require('./index.js')
Hello, npm
{}
`</pre>

({}是 require 的返回值, 在这个例子中, 他是 index.js 的 exports 对象)
Node 允许我们省略.js 扩展名, 因此我们可以简写为 require(',/index').
如果我们在同一个 REPL 会话中再次运行 require, 我们将得到相同的返回值, 但是不会得到 console.log 输出, 因为 require 不会在同一个脚本中运行两次.
./在./index 中很重要, 因为他告诉 Node 这个路径是当前文件夹的相对路径. 如果我们不显示给出绝对路径或相对路径, 而是直接给 index, Node 会在一系列文件夹中寻找匹配的模块.

回顾一下, 在 package.json 文件夹中, 'main':'index.js' 的作用是什么?
当你 require 一个包含指向 main 脚本('main':'index.js')的 package.json 文件的文件夹时, Node 会认为你是在 require 这个脚本('index.js'), 所以前面的代码可以简写为

<pre>`require(./)
`</pre>

现在我们可以使用 package.json 来完成上面的工作, 因为我们的脚本命名为 index.js, 他是一个文件夹的默认脚本

### 第一个依赖模块

使用下面的命令来快速搜索 npm registry
`$npm search color`
如果想要获得更多的信息, 可以跳转到 npmjs.org, 在"最多依赖"的列表中可以查看流行的库
安装依赖模块
`$npm install --save colors`
这条指令会在本地文件夹中创建一个名为 node_modules 的文件夹并将 colors 下载到其中. `--save`将依赖模块自动加入到 package.json 文件中.

<pre>`"dependencies"{
  "colors":"~0.6.0-1"
}
`</pre>

现在我们来重写 index.js 来使用我们的新库. colors 扩展了 String 的原型因此我们可以非常简洁的表达带有颜色的文本:

<pre>`var colors = require('colors');
console.log('Hello, '.red,'npm'.green);

运行 index.js 文件, 你将在原来的输出中获得一个彩色字符串

node_modules 的层级

当不显示指定相对路径或绝对路径时, Node 首先查找本地的 ndoe_modules 文件夹, 当你使用 npm install 指令的时候这个文件夹被自动创建. 当 Node 发现 node_modules 下有一个叫做 colors 子目录时, Node 将他当做 require 的目标.
查看 node_modules/colors/package.json, 可以找到’main’:’colors’ , 因此 require colors这个文件夹时 Node 会认为 require 了 colors.js 这个脚本
然后从 require 函数中返回脚本中的 exports 对象.
如果找不到 colors 目录, 则会一直搜索到系统的根目录.

Display:table-Cell

display:table-cell 属性简述

display:table-cell 属性让标签元素鞥一表格单元格的形式呈现, 类似于 td 标签.
table-cellfloat, position:absolute 不兼容.
table-cell元素可以设置 width, height, padding, 但是不能设置 margin, 和 td 标签一致.

display:table-cell 与大小不固定元素的垂直居中

display:table-cell 与两栏自适应布局

display:table-cell 等高布局

table 表格中的单元格最大的特点之一就是同一行列表元素都是登高的, 所以等高布局可以借助 table-cell 实现.
匿名表格元素创建规则:CSS2中创建表格元素, 其依赖元素(比如 tr 之于 td, table 之于 tr) 会被模拟出来, 从而使得表格模型能够正常工作. 所有的表格元素都会自动在自身周围生成需要的匿名 table 对象, 使其符合 table/inline-table, table-row, table-cell 的三层嵌套关系.
要实现等高布局, 所有的 table-cell 元素一定要留一个用来包裹的标签, CSS 代码如下:
`
.list_row{display:table-row}
.list_cell{display:table-cell;width:30%,padding:1.6%; background-color:#F5F5F5;}
.list_center{background-color:#F0F3F9;}//用于和旁边的 cell 区分

JavaScript 的闭包

通常情况下, 求和函数的定义是这样的

function sum(arr){
  return arr.reduce(function(x,y){
    return x+y;
  });
}
sum([1,2,3,4,5]); //15
`</pre>

但是, 如果不需要立刻求和, 而是在后面的代码中根据需要进行计算, 可以选择返回一个保存了参数的求和函数

<pre>`function lazy_sum(arr){
  var sum = function(){
    return arr.reduce(function(x,y){
      return x+y;
    });
  }
  return sum;
}
`</pre>

当我们调用`f = lazy_sum()`时会返回保存了参数 arr 的 sum 函数, 直到通过 f()调用 sum 函数前都不会进行求和运算, 可以节约资源.

**需要注意的一点**是每一次调用 lazy_sum() 都会返回一个新的函数, 彼此相互独立, 各自占用内存空间
同时要注意, 尽管每次生成并返回的都是新的 sum 函数, 但是 lazy_sum() 的局部变量是通用的, 可参考**类方法**与**实例**的关系, 这是使用闭包的目的之一

**更要注意**:

<pre>`function count(){
  var arr = [];
  for(var i = 1; i&lt;=3; i++){
    arr.push(function(){
        return i*i;
      });
  }
  return arr;
}

var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];

在这个例子中, f1(), f2(), f3()的返回值都是16, 原因在于:
每一次循环都向 arr 推入一个(function(){})(i), 但都没有计算, 三次循环后 i 变成了4, 所以f1, f2, f3的函数接受的局部变量的值都是4.
由此可知闭包保留的是变量, 而不是变量的值.
如果一定要引用循环变量, 记得创建一个变量用于保存现场

闭包可以用于实现装饰器

前端工作流

主要操作包含:

CSS 前缀补全, LESS/SASS 编译, CSS 压缩, JS 合并压缩 ,图片压缩, 部署发布

流程分解

主要分为

开发过程

部署过程

开发过程

要求每一次编辑都能在页面上即时相应

部署过程

  • CSS Autoprefixer
  • Less/Sass => CSS
  • CSS 压缩合并
  • CSS Sprite
  • Retina @2x & @3x 自动生成适配
  • imagemin 图片压缩
  • JS 合并压缩

项目目录结构

project //项目目录
|dev //开发目录
| |
html
| |images
| |
scripts
| |slice //合成的雪碧图
| |
styles
|dist //生产目录
| |
html
| |images
| |
scripts
| |sprite //仅从 src 复制
| |
styles
|gulpfile.js
|
src //源文件目录
| |html
| |
images
| |scripts
| |
slice //雪碧图素材
| |____styles

Mac OS 下 实现 Tree 指令

先安装 zsh
进入~/.zshrc, 添加
alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'"
回到目录, 执行
source .zshrc 令修改立即生效
可以使用tree指令生成文档树

RegExp in JS

Literal

/patter/attributes

new RegExp

new RegExp(pattern, attribtues)

pattern

RegExp Attribtues

  • g: global
  • i: ignoreCase
  • m: multi-lines
  • source: literal text
  • lastIndex: mark the index where to start next match

Example

var re = new RegExp('^[0-9]+$','g');
console.log(re.source); //^[0-9]+$
`</pre>

<pre>`var re = new RegExp('\\d{3}','g');
var str = '123a456b';
console.log(re.lastIndex); // 0
re.exec(str); //return ['123']
console.log(re.lastIndex); // 3
re.exec(str); // ['456']
console.log(re.lastIndex); //7
re.exec(str);
console.log(re.lastIndex) // 0, reset to 0 if exceed.
re.lastIndex = 3; //Set Start Index
re.exec(str); // ['456']

RegExp Methods

re.compile(re) //execute RegExp in scripts
re.exec(str) //return an Array including String, or null.
re.test(str) => true/false

String Methods

str.search(re,subStr)
str.match(re) => Array including String
str.replace(re,str) => new String
str.split(re)

Shell 指令

Shell 在计算机科学中是指”提供用户使用界面”的软件, 通常指的是命令行界面的解析器, 一般来说, 这个词指的是操作系统中提供访问内核所提供服务的程序. Shell 也用于泛指为所有用户提供操作界面的程序, 也就是程序和用户交互的层面. 因此与之相对的是程序内核(Core), 内核不提供和用户的交互功能.

bash (Bourne Again Shell) 是 Linux 标准的默认 shell, 支持 POSIX 标准, 完全兼容 sh.

进入 shell: 一般 Linux 系统中, 桌面(GUI)状态下使用快捷键 Ctrl+Alt+T 能打开一个虚拟终端, 输入 shell 命令并执行.
退出 shell: 在 shell 中输入 exit 然后回车
默认提示符: 普通用户$, 根用户#
查看 shell 版本: echo $SHELL
查看命令的辅助信息:
--help, --version

目录文件指令

pwd: 查看当前目录
echo $HOME 或者 echo ~: 查看主目录

ls: 列出文件或目录下的文件名

  • -a(all): 显示所有文件, 包括隐藏文件
  • -l(long): 显示详细信息(long 表示长格式显示)
  • -d(detail): 显示目录属性
  • -h(human): 人性化显示文件大小
  • -i(inode): 显示 inode
  • -ll(ls -l): 显示目录下文件的长信息

cd: 改变目录

  • ~ 进入当前用户的根目录
  • 同上
  • -进入上次目录
  • .. 进入上一级目录
  • . 进入当前目录

mkdir: 创建目录(文件夹)

  • -p 递归创建
    e.g. mkdir b/a =>fail, mkdir不能创建多级目录
    mkdir -p b/a 同时创建 b 和 a

rmdir: 删除空目录

rm: 删除目录及文件

  • -r强制删除目录
  • -f强制
  • 一般用 rm -rf ..

touch: 修改文件时间或者创建文件

chmod: 设置目录或文件的访问权限

  • chmod[选项][操作对象][操作符][权限][文件名]
  • 操作符号
      • 添加某个权限
    • -取消某个权限
    • =赋予给定权限并取消其他权限
  • 数字设定法
    • chmod abc 文件名
    • 其中 abc 各为一个数字, 分别表示 user, group, other 的权限
    • r为4, w为2, x为1, -为0(二进制位)
    • rwx = 7; rw- = 6; r-x = 5
  • 访问权限组(每一个文件或目录的访问权限都有三组)
    在 Linux 中是按照用户和组来设定权限的
    • 所有者权限: 就是文件或者目录的创建者, 一般来说和 root 用户权限相当. 文件被创建时, 文件所有者自动拥有对该文件的读写和可执行权限.
    • 同组权限: 就是所有者所在的用户组的其他成员的权限
    • 其他用户权限
  • 访问权限(读取, 写入, 执行)
    • r: 读取文件内容的权限, 或者浏览目录的权限
    • w: 新增,修改文件内容的权限, 或者删除, 移动目录内文件的权限
    • x: 执行文件的权限, 或者进入目录的权限
  • 用 -ll 也就是 -ls l显示文件或目录的详细信息, 最左的一列为文件的访问权限, 例如:
    -rw-r--r-- 1 root root 483997 Jul 15 18:31 sobsrc.tgz
    这里有10个位置, 第一个制定文件的类型, 通常意义上, 一个目录也是一个文件, 如果第一个字符是-, 表示是一个非目录文件, 如果是 d, 表示是一个目录























- rw- r– r–
非目录的文件 所有者权限 组用户 其他用户
普通文件 可读写 只读 只读

chown: 改变目录的所有者
cp: 复制目录或文件

  • -r 复制目录
  • -p 连带文件属性复制
  • -d 若源文件是链接文件, 则复制链接属性
  • -a 相当于 -pdr
  • cp[现象][原文件或目录][目标目录]

mv: 剪切或改名(move)

  • mv a ../a 将当前目录下的 a 复制剪切到上一级的 a 目录中
  • mv abc.txt de.txt 如果原文件和目标文件在同一目录下, 则为改名, 否则是剪切

文件内容命令

diff: 比较两个文件的差异
patch: 修补文件(给文件打补丁)
cat: 输出文件内容
more: 逐屏显示文件内容
less: 逐页显示文件内容
head: 显示文件开头若干行内容
tail: 显示文件最后若干行内容
od: 查看特殊格式的文件内容

常见目录

/ 根目录
/bin 存放必要的命令
/boot 存放内核以及启动所需要的文件
/dev 存放设备文件
/etc 存放系统的配置文件
/home 用户文件的主目录
/lib 存放必要的运行库
/mnt 存放临时的映射文件系统
/proc 存放存储进程和系统信息
/root 超级用户的主目录
/sbin 存放系统管理程序
/tmp 存放临时文件
/usr 包含了一般不需要修改的应用程序, 命令程序文件, 程序库,手册等
/usr/bin 系统命令(普通用户 home)
/usr/sbin 系统命令(超级用户 root)
/var 包含系统产生的经常变化的文件

Mac OS 下前端开发环境配置

安装 homebrew

终端下执行
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

配置 iterm2

下载后下载配色 solarized, 然后下载 zsh 和 oh-my-zsh, 添加插件 git, osx, ruby, autojump

安装 Nginx

终端下执行
brew install nginx
安装完成后用浏览器打卡 http://localhost:8080, 如果页面显示正常,则表示安装完成
nginx 有一下几个操作

  #打开 nginx
  nginx
  #nginx -s 重新加载配置|重启|停止|退出
  nginx -s reload|reopen|stop|quit
  #测试配置是否有语法错误
  nginx -t
`</pre>

Note: 如果执行不成功, 请使用 sudo 提权

默认访问目录是
`/usr/local/Cellar/nginx/1.10.0/html`

nginx 的配置文件位置为:
`/usr/local/etc/nginx/nginx.conf`

#### 配置 nginx

首先备份一下 nginx.conf ==> nginx.conf.default
修改server 部分为:

<pre>`server
  {
    listen    8080;
    server_name localhost;

    location /{
      root /Users/YourId/Documents; //项目目录
      #index index.html index.htm;
    }
  }
`</pre>

配置完成后启动 nginx 即可访问

### 安装 mySQL

终端执行
`brew install mysql`
 安装完成后默认没有密码, 修改密码
 ```
 mysql -uroot -p
 Enter password:
 mysql>use mysql;
 mysql> UPDATE user SET password=password("修改的密码") WHERE user='root';

mysql 的操作命令

<pre>`  #开启
  mysql.server start
  #结束
  mysql.server stop

配置文件位于
/usr/local/Cellar/mysql/5.6.28/my.cnf

Component Children

this.props.children

Children allow you to pass components as data to other components, just like any other prop you use. The special thing about children is that React provides support through its ReactElement API and JSX. XML children translate perfectly to React children.

var MyDiv = React.createClass({
  render: function(){
      return &lt;div&gt;{this.props.children}&lt;/div&gt;
}
});

ReactDOM.render(
  &lt;MyDiv&gt;
      &lt;span&gt;Hello&lt;/span&gt;
      &lt;span&gt;World&lt;/span&gt;
  &lt;/MyDiv&gt;,
  node  
);
`</pre>

### this.props.children

If you look at the **JSX** transform, you'll find that XML children are appended as arguments to the _React.createElement_ call.
 Most often, your component will render content and include the children in the _render_ output. This is a great way to create UI components, like cards, headers, and buttons.

Occasionally, you may want to interact with the children, maybe mutating or separating them. Be careful here and remember to treat **this.props.children** as an **opaque data structure**. Instead of working with **this.props.children** directly, use the **React.Children** utilities to work with children.

<pre>`var ListComponent = React.createClasss({
  render: function(){
      var children = React.Children.map(
        this.props.children,
        function(child){
            return &lt;li&gt;{child}&lt;li&gt;
        }
    );
    return &lt;ul&gt;{children}&lt;/ul&gt;;
  }
  });

  var middleChildren = [
  &lt;strong key='2'&gt;Child 2&lt;/strong&gt;,
  &lt;a href='#' key='3'&gt;Child 3&lt;/a&gt;
  ];

  ReactDOM.render(
  &lt;ListComponent&gt;
    &lt;span&gt;Child 1&lt;/span&gt;
    {middleChildren}
    &lt;em&gt;Child 4&lt;/em&gt;
  &lt;/ListComponent&gt;,
  document.body
);

Node

A Node is an interface from which a number of DOM types, and allows these various types to be treated similarly.

Properties

  • Node.baseURI: return a DOMStirng representing the base URL
  • Node.childNodes: return a live NodeList containing all the children of this node. NodeList being live means that if the children of the Node change, the NodeList will update automatically.
  • Node.firstChild: return a Node representing the first direct child Node of this Node, or Null if the node has no child.
  • Node.lastChild: Return a Node representing the last direct child Node of this Node, or Null if the node has no child.
  • Node.nextSibling: return a Node representing the next Node in the tree, or null if there is no one.
  • Node.previousSibling
  • Node.nodeName: return a DOMString containing the name of the node. The structure of the name will differ with the name type. E.g. An HTMLElement will contain the name of the corresponding tag, like “audio”, for an HTMLAudioElement, a Text node will have the “#text” string, or a Document node will have the “#document” string.
  • Node.nodeType: return an unsigned short representing the type of the node. Possible values are:





































Name Value
Element_Node 1
Attribute_Node 2
Text_Node 3
Document_Node 9
Document_Type_Node 10
Notation_Node 12
  • Node.nodeValue: return a DOMString representing the value of an object. For most node types, this returns null, and any set operation is ignored.
    For Nodes of type TEXT_NODE(Text objects), COMMENT_NODE(Comment objects), and PROGRESSING_INSTRUCTION_NODE(ProgressingInstruction objects), the value corresponds to the text data contained in the obejct.
  • Node.parentNode: return a Node that is the parent of this node, if there is no such node, like if this node is the top of the tree or if doesn’t participate in a tree, this property returns Null.
  • Node.parentElement: returns an Element that is the parent of this node. If the node has no parent, or if that parent is not an Element, this property returns Null.
  • Node.rootNode: return a Node representing the topmost Node in this tree or the current node if it’s the topmost node in the tree.
  • Node.textContent: is a DOMString representing the textual content of an element and all its descendants.

Methods

  • Node.appendChild()
  • Node.cloneNode(): Clone a Node and optionally all of its contents. By default, it clones the content of the node.
  • Node.hasChildNodes(): return a boolean indicating if the element has any child nodes, or not.
  • Node.insertBefore(newNode, beforeItsChild)
  • Node.isEqualNode(): return a boolean which indicating whether or not two nodes are of the same type and all their defining data points match.
  • Node.isSameNode(): return a boolean value indicating whether or not the two nodes are the same(that is they reference the same object).
  • Node.removeChild()
  • Node.replace(newNode, replaceItsChild)

    *   Note: replaceNode will not generate new one.</p>
    
    • E.g.

      ul&gt;li*3

      ul.replace(li[2],li[0])

      it will act as:
      remove li[2], put it li[0], remove li[0], so the result looks like

      ul
      –li[2]
      –li[1]
      `

    Examples

    Browser All Child Nodes

    The following function recursively cycles all child nodes of a node and executes a callback function upon them(and upon the parent node itself).

    `function DOMComb(oParent, oCallBack){
      if(oParent.hasChildNodes()){
        for(var oNode = oParent.firstChild; oNode; oNode = oNode.nextSibling){
          DOMComb(oNode, oCallBack);
        }
      }
      oCallBack.call(oParent);
    }
    `

    Remove all children nested within a node

    `Element.prototype.removeAll = function(){
    while(this.firstChild){

    this.removeAll(this.firstChild);
    

    }
    return this;
    };

innerHTML and textContext and NodeValue

Summary:

  • nodeValue is a little more confusing to use, but faster than innerHTML
  • innerHTML parses content as HTML and takes longer(output text/html)
  • textContent uses straight text, does not parse HTML, and is faster(output text/plain)
  • innerText takes styles into consideration. It won’t get hidden text for instance.

node.textContent

The Node.textContent property represents the text content of a node and it descendants.

Syntax

example.textContent ="&lt;a href='...'&gt;textContent&lt;/a&gt;"
will output &lt;a href='...'&gt;textContent&lt;/a&gt;

Differences from innerText

  • textContent gets the content of all elements, including
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×