Git Product home page Git Product logo

blog's Introduction

blog's People

Contributors

huyuee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

blog's Issues

react高阶组件构想

基础组件的维护

  1. 分配每个人统计各个组件在不同框架中的样式,详细至链接,或者截图

  2. 通过查看各个不同样式的,来分析出各个组件的最小版本,需要的各个功能

  3. 抽离出最小的组件样式,给出默认样式

第一种组件的维护方式(高阶模板组件)

以后随着不同项目组的不同的需求,提炼出多个高阶模板函数,多种不同的设计风格和场景,针对于类似的设计风格,可以在现有高阶模板函数的基础上进行拓展;否则就建立新的高阶模板组件

第二种组件的维护方式(高阶组件)

  1. 针对于复杂的功能拓展,需要提前判断,看是否需要加入进原有组件中,暴露接口或参数。否则都按照高阶组件的方式提供给项目开发人员。
  2. 我们这边的组件开发人员,按照一个复杂功能,一个高阶组件的模式

使用python脚本清理阿里云cdn缓存

步骤如下:

  1. 将下面的脚本中的三处xxxx的位置替换相应的数据

    注意:第三处ObjectPath的xxx处的替换为你想要刷新缓存的域名,比如我这里是:http://design.yonyoucloud.com/

  2. 然后再该python文件目录下运行python xx.py

#!/usr/bin/python
# -*- coding:utf-8 -*-

import sys,os
import urllib, urllib2
import base64
import hmac
import hashlib
from hashlib import sha1
import time
import uuid

class pushAliCdn:
    def __init__(self):
        self.cdn_server_address = 'http://cdn.aliyuncs.com'
        self.access_key_id = 'xxxxxxxxx'
        self.access_key_secret = 'xxxxxxxxxxxxxxxx'

    def percent_encode(self, str):
        res = urllib.quote(str.decode(sys.stdin.encoding).encode('utf8'), '')
        res = res.replace('+', '%20')
        res = res.replace('*', '%2A')
        res = res.replace('%7E', '~')
        return res

    def compute_signature(self, parameters, access_key_secret):
        sortedParameters = sorted(parameters.items(), key=lambda parameters: parameters[0])
        canonicalizedQueryString = ''
        for (k,v) in sortedParameters:
            canonicalizedQueryString += '&' + self.percent_encode(k) + '=' + self.percent_encode(v)
        stringToSign = 'GET&%2F&' + self.percent_encode(canonicalizedQueryString[1:])
        h = hmac.new(access_key_secret + "&", stringToSign, sha1)
        signature = base64.encodestring(h.digest()).strip()
        return signature

    def compose_url(self, user_params):
        timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
        parameters = { \
                'Format'        : 'JSON', \
                'Version'       : '2014-11-11', \
                'AccessKeyId'   : self.access_key_id, \
                'SignatureVersion'  : '1.0', \
                'SignatureMethod'   : 'HMAC-SHA1', \
                'SignatureNonce'    : str(uuid.uuid1()), \
                'TimeStamp'         : timestamp, \
        }
        for key in user_params.keys():
            parameters[key] = user_params[key]
        signature = self.compute_signature(parameters, self.access_key_secret)
        parameters['Signature'] = signature
        url = self.cdn_server_address + "/?" + urllib.urlencode(parameters)
        return url

    def make_request(self, user_params, quiet=False):
        url = self.compose_url(user_params)
        #print url
        #刷新url
        try:
            req = urllib2.Request(url)
            res_data = urllib2.urlopen(req)
            res = res_data.read()
            return res
        except:
            return user_params['ObjectPath'] + ' refresh failed!'

if __name__ == '__main__':
    f = pushAliCdn()
    params = {'Action': 'RefreshObjectCaches', 'ObjectPath': 'http://xxxxxxxxxx/', 'ObjectType': 'Directory'}
    res = f.make_request(params)
    print res

参考地址:http://www.xiaomastack.com/2015/10/21/alipushcdn/

js数字的货币格式表示法(每三位一个逗号分隔)

概述

大概的**就是:先拆分,然后反转,然后拼接,然后使用match已三位数截断,然后用逗号拼接,再拆分,然后反转,最后拼接!ok!

下面是源码,可以在codepen中打开,地址

//保留两位小数并且整数部分三位一个逗号分隔符的数字金钱标准表示法:  
 //这里假设我们即不知道输入数字的整数位数,也不知道小数位数  
/*将100000转为100,000.00形式*/  
var dealNumber = function(money){  
    if(money && money!=null){  
        money = String(money);  
        var left=money.split('.')[0],right=money.split('.')[1];  
        right = right ? (right.length>=2 ? '.'+right.substr(0,2) : '.'+right+'0') : '.00';  
        var temp = left.split('').reverse().join('').match(/(\d{1,3})/g);  
        return (Number(money)<0?"-":"") + temp.join(',').split('').reverse().join('')+right;  
    }else if(money===0){   //注意===在这里的使用,如果传入的money为0,if中会将其判定为boolean类型,故而要另外做===判断  
        return '0.00';  
    }else{  
        return "";  
    }  
};  
/*将100,000.00转为100000形式*/  
var undoNubmer = function(money){  
    if(money && money!=null){  
        money = String(money);  
        var group = money.split('.');  
        var left = group[0].split(',').join('');  
        return Number(left+"."+group[1]);  
    }else{  
        return "";  
    }  
};

npm实用小技巧

  • 更快init出package.json

    npm init -y
    
  • 枚举可用的脚本

    1.cat package.json
    2.使用ntl工具,npm install -g ntl,然后再项目中使用ntl命令选择脚本
    
  • 枚举已经安装的包

    npm ls --depth 0
    
  • 访问项目的github主页

    npm repo
    
  • 访问项目的homepage

    npm home
    
  • 访问项目的readme

    npm docs
    
  • 修改包的版本

    npm version patch
    npm version minor
    npm version major
    

如何写好一篇入门教程?

开篇我声明,是写入门教程的套路,并不是所有的教程都是如此。不喜勿喷..

我总结了下,入门教程要想写的好(被人点的赞多),首先我们得清楚看这个入门教程的人想知道什么。其实,无非就是三点:

  1. 什么是xx?
  2. xx主要包含什么内容?
  3. 怎么使用?

什么是xx?

入门教程第一个标题一般就是,什么是xx?那么回答这个问题,核心描述一定得抓住

核心要浅显易懂,要直入主题,一定不要搞一些复杂的专有名词(个人认为就是装X),不要说的花里胡哨。最好就是一句话。

这里我举了两个例子,比如:

MobX只做一件事,解决 state 到 view 的数据更新问题

还有一个例子:

MobX 是一个简单、方便扩展、久经考验的状态管理解决方案。这个教程旨在十分钟内向你介绍 MobX 的一些重要概念。MobX 是一个独立的苦,不过大多数人都把它和 React 一起使用,所以本教程也就着眼于这个组合展开。

这里很清楚、很明显的能看到这两个回答的对比之处。

第二个例子太含糊其词了,状态管理,什么状态,如何管理的。到底是什么东西,这个到底有什么,用户还是不太明白你再说什么。所以入门教程最重要的就是尽量用不专业的名词,来解释专业名词。通俗的说就是入门教程的内容尽量要用小孩能听懂的词语来解释一个比较专业的东西,这是最重要的一点

xx主要包含什么内容?

这里我们需要交代这个框架或者这个技术他主要涉及到的技术点有什么内容,一定要配合图片

比如

核心理念

mobx 引入了几个概念,Observable state, DerivationsReactions

img

可以拿 Excel 表格做个比喻,Observable state 是单元格,Derivations 是计算公式,单元格的修改会触发公司的重新计算,并返回值,而最终公式的计算结果需要显示在屏幕上(比如通过图表的方式),这是 Reactions

作者通过一个图片来展示,主要涉及的就是三块,一个state,一个derivations,一个Reactions。并且通过Excel表格的比喻来解释这个核心理念,就更加通俗易懂了。

所以图片和通俗易懂的比喻更加能让读者明白

怎么使用?

怎么使用?当然就是一段能够快速上手的简单示例或者demo了。

没错,确实是这样。但是不仅仅是demo,而且一定要有可以在线调试的地址(方便读者可以快速练手或者快速改动代码看效果)。不明白?没关系,看看别的大神是怎么做的。如下图:

a111

如上图所示,一个在线调试的地址和demo代码片段同样重要

前端开发规范

规范有很多,但是可以参考下面规范👇

原则和目的

基于开发共识,结合实际项目,坚持制定好的代码规范。确保同一团队以及不同的项目间,都能够实现代码风格的一致性,提高可维护性、可读性。

细则

命名规则和项目目录规范

命名规则

项目命名

全部采用小写方式, 以下划线分隔。

例:my_project_name

目录命名

参照项目命名规则;

有复数结构时,要采用复数命名法。

例:scripts, styles, images, data_models

JS文件命名

参照项目命名规则。

例:account_model.js

CSS, SCSS文件命名

参照项目命名规则。

例:retina_sprites.scss

HTML文件命名

参照项目命名规则。

例:error_report.html

项目目录规范

│  .babelrc
│  .gitignore
│  LICENSE
│  package.json
│  postcss.config.js
│  README.md
│  uba.config.js
│  uba.mock.js
│
├─dist
│  ├─assets
│  │   ├─css
│  │   ├─js
│  │   ├─images
│  │     
│  │ index.html
├─mock
│  └─index.json
└─src
    │  constant.js
    │  index.html
    │  index.js
    │  index.less
    │
    ├─assets
    │  README.md
    │
    ├─components
    │  │  index.js
    │  ├─LoadingTable
    │     index.css
    │     index.jsx
    │
    ├─pages
    │  │  index.js
    │  │
    │  ├─App
    │     index.css
    │     index.jsx
    │  
    └─api
            index.js

HTML 编码规范

语法

  • 缩进使用soft tab(4个空格);
  • 嵌套的节点应该缩进;
  • 在属性上,使用双引号,不要使用单引号;
  • 属性名全小写,用中划线做分隔符;
  • 不要在自动闭合标签结尾处使用斜线(HTML5 规范 指出他们是可选的);
  • 不要忽略可选的关闭标签,例:</li></body>
<!DOCTYPE html>
<html>
    <head>
        <title>Page title</title>
    </head>
    <body>
        <img src="images/company_logo.png" alt="Company">

        <h1 class="hello-world">Hello, world!</h1>
    </body>
</html>

HTML5 doctype

  • 在页面开头使用这个简单地doctype来启用标准模式,使其在每个浏览器中尽可能一致的展现;
  • 虽然doctype不区分大小写,但是按照惯例,doctype大写 (关于html属性,大写还是小写)。
<!DOCTYPE html>
<html>
	...
</html>

lang属性

  • 根据HTML5规范:

应在html标签上加上lang属性。这会给语音工具和翻译工具帮助,告诉它们应当怎么去发音和翻译。

  • 更多关于 lang 属性的说明在这里
  • 在sitepoint上可以查到语言列表

sitepoint 只是给出了语言的大类,例如中文只给出了zh,但是没有区分香港,**,大陆。而微软给出了一份更加详细的语言列表,其中细分了 zh-cn, zh-hk, zh-tw

<!DOCTYPE html>
<html lang="en-us">
    ...
</html>

字符编码

通过声明一个明确的字符编码,让浏览器轻松、快速的确定适合网页内容的渲染方式,通常指定为'UTF-8'。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
    </head>
    ...
</html>

IE兼容模式

<meta> 标签可以指定页面应该用什么版本的IE来渲染;

如果你想要了解更多,请点击这里

不同 doctype 在不同浏览器下会触发不同的渲染模式(这篇文章总结的很到位)。

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    </head>
    ...
</html>

引入CSS, JS

根据HTML5规范, 通常在引入CSS和JS时不需要指明 type,因为 text/css 和 text/javascript 分别是他们的默认值。

HTML5 规范链接:

<!-- External CSS -->
<link rel="stylesheet" href="code_guide.css">

<!-- In-document CSS -->
<style>
    ...
</style>

<!-- External JS -->
<script src="code_guide.js"></script>

<!-- In-document JS -->
<script>
    ...
</script>

属性顺序

属性应该按照特定的顺序出现以保证易读性:

  • class
  • id
  • name
  • data-*
  • src, for, type, href, value , max-length, max, min, pattern
  • placeholder, title, alt
  • aria-*, role
  • required, readonly, disabled

class是为高可复用组件设计的,所以应处在第一位;

id更加具体且应该尽量少使用,所以将它放在第二位。

<a class="..." id="..." data-modal="toggle" href="#">Example link</a>

<input class="form-control" type="text">

<img src="..." alt="...">

boolean属性

boolean属性指不需要声明取值的属性,XHTML需要每个属性声明取值,但是HTML5并不需要;

更多内容可以参考 WhatWG section on boolean attributes:

boolean属性的存在表示取值为true,不存在则表示取值为false。

<input type="text" disabled>

<input type="checkbox" value="1" checked>

<select>
    <option value="1" selected>1</option>
</select>

JS生成标签

在JS文件中生成标签让内容变得更难查找,更难编辑,性能更差。应该尽量避免这种情况的出现。

减少标签数量

在编写HTML代码时,需要尽量避免多余的父节点;

很多时候,需要通过迭代和重构来使HTML变得更少。

<!-- Not well -->
<span class="avatar">
    <img src="...">
</span>

<!-- Better -->
<img class="avatar" src="...">

实用高于完美

尽量遵循HTML标准和语义,但是不应该以浪费实用性作为代价;

任何时候都要用尽量小的复杂度和尽量少的标签来解决问题。

CSS 编码规范

以下为前端开发团队遵循和约定的 CSS 编码规范。

代码风格

  • 代码应该符合 CSS 语法有效性,可以使用 W3C CSS validator 工具来验证。

  • ID 和 Class 应该按照元素功能命名,不应该按照元素表现命名,命名应该含义清晰。

    /* bad: 含义不清 */
    #yee-1901 {}
    
    /* bad: 表现化 */
    .button-green {}
    .clear {}
    
    /* good: 功能化 */
    #gallery {}
    #login {}
    .video {}
  • ID 和 Class 命名应该在保持含义清晰的前提下尽可能简短。

    /* bad */
    #navigation {}
    .atr {}
    
    /* good */
    #nav {}
    .author {}
  • ID 和 Class 命名中单词应该全部小写,单词之间使用 - 作为分隔符。

    /* bad */
    #videoId {}
    .demoimage {}
    .error_status {}
    
    /* good */
    #video-id {}
    .ads-sample {}
  • 不能「MUST NOT」把 ID 和 Class 选择符作为类型选择符的限定符,这样做没必要,反而还影响性能。

    /* bad */
    ul#example {}
    div.error {}
    
    /* good */
    #example {}
    .error {}
  • CSS 属性应该尽可能使用简化方式书写,需注意简写时默认值的副作用,详细参考 Shorthand properties

    /* bad */
    border-top-style: none;
    font-family: palatino, georgia, serif;
    font-size: 100%;
    line-height: 1.6;
    padding-bottom: 2em;
    padding-left: 1em;
    padding-right: 1em;
    padding-top: 0;
    
    /* good */
    border-top: 0;
    font: 100%/1.6 palatino, georgia, serif;
    padding: 0 1em 2em;
  • CSS 属性中的 0 值不应该带单位。

    /* bad */
    margin: 0px;
    padding: 0px;
    
    /* good */
    margin: 0;
    padding: 0;
  • CSS 属性中数值介于-1到1之间的小数应该忽略开头的 0

    /* bad */
    font-size: 0.8em;
    
    /* good */
    font-size: .8em;
  • CSS 的色值应该尽可能使用简化写法。

    /* bad */
    color: #eebbcc;
    
    /* good */
    color: #ebc;

组织格式

  • 必须采用 4 个空格为一次缩进。

  • CSS 属性声明应该按字母升序排列。

    /* good */
    background: fuchsia;
    border: 1px solid;
    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
    border-radius: 4px;
    color: black;
    text-align: center;
    text-indent: 2em;
  • CSS 每个代码块相对于父代码库必须有缩进。

    /*good*/
    @media screen, projection {
    
      html {
        background: #fff;
        color: #444;
      }
    
    }
  • CSS 属性声明必须以分号结尾。

  • CSS 属性名冒号后必须有一个空格。

    /* bad */
    color:#eebbcc;
    
    /* good */
    color: #ebc;
  • CSS 中的属性名建议按照字母顺序排列,可以使用 Sublime Text 的 F5 命令来自动格式化。

  • 最后的选择符与 { 之间必须有一个空格。

    /* bad */
    #video{
      margin-top: 1em;
    }
    .author
    {
      margin-top: 1em;
    }
    
    /* good */
    #video {
      margin-top: 1em;
    }
  • 多个并列的选择符必须换行。

    /* bad */
    a:focus, a:active {
      position: relative; top: 1px;
    }
    
    /* good */
    h1,
    h2,
    h3 {
      font-weight: normal;
      line-height: 1.2;
    }
  • CSS 规则之间必须以空白行分隔。

    /* good */
    html {
      background: #fff;
    }
    
    body {
      margin: auto;
      width: 50%;
    }
  • CSS 属性值中所有使用到引号的位置必须使用单引号。

    /* bad */
    @import url("//www.google.com/css/maia.css");
    
    html {
      font-family: "open sans", arial, sans-serif;
    }
    
    /* good */
    @import url('//www.google.com/css/maia.css');
    
    html {
      font-family: 'open sans', arial, sans-serif;
    }

代码注释

  • CSS规则段落之前应该添加注释说明。

    /* good */
    /* Header */
    
    #adw-header {}
    
    /* Footer */
    
    #adw-footer {}
    
    /* Gallery */
    
    .adw-gallery {}

JavaScript 编码规范

以下内容前端开发团队遵循和约定的 JavaScript 编码规范。

缩进

使用soft tab(4个空格)。

    var x = 1,
        y = 1;

    if (x < y) {
        x += 10;
    } else {
        x += 1;
    }

单行长度

不要超过 80,但如果编辑器开启 word wrap可以不考虑单行长度。

类型

  • 原始值: 相当于传值

    • string
    • number
    • boolean
    • null
    • undefined
    var foo = 1,
        bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9
  • 复杂类型: 相当于传引用

    • object
    • array
    • function
    var foo = [1, 2],
        bar = foo;
    
    bar[0] = 9;
    
    console.log(foo[0], bar[0]); // => 9, 9

对象

  • 使用字面值创建对象

    // bad
    var item = new Object();
    
    // good
    var item = {};
  • 不要使用保留字 reserved words 作为键

    // bad
    var superman = {
      class: 'superhero',
      default: { clark: 'kent' },
      private: true
    };
    
    // good
    var superman = {
      klass: 'superhero',
      defaults: { clark: 'kent' },
      hidden: true
    };

数组

  • 使用字面值创建数组

    // bad
    var items = new Array();
    
    // good
    var items = [];
  • 如果你不知道数组的长度,使用push

    var someStack = [];
    
    // bad
    someStack[someStack.length] = 'abracadabra';
    
    // good
    someStack.push('abracadabra');
  • 当你需要拷贝数组时使用slice

    var len = items.length,
        itemsCopy = [],
        i;
    
    // bad
    for (i = 0; i < len; i++) {
      itemsCopy[i] = items[i];
    }
    
    // good
    itemsCopy = items.slice();
  • 使用slice将类数组的对象转成数组.

    function trigger() {
      var args = Array.prototype.slice.call(arguments);
      ...
    }

字符串

  • 对字符串使用单引号 ''

    // bad
    var name = "Bob Parr";
    
    // good
    var name = 'Bob Parr';
    
    // bad
    var fullName = "Bob " + this.lastName;
    
    // good
    var fullName = 'Bob ' + this.lastName;
  • 超过80个字符的字符串应该使用字符串连接换行

    • 注: 如果过度使用,长字符串连接可能会对性能有影响.
    // bad
    var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
    
    // bad
    var errorMessage = 'This is a super long error that \
    was thrown because of Batman. \
    When you stop to think about \
    how Batman had anything to do \
    with this, you would get nowhere \
    fast.';
    
    // good
    var errorMessage = 'This is a super long error that ' +
    'was thrown because of Batman.' +
    'When you stop to think about ' +
    'how Batman had anything to do ' +
    'with this, you would get nowhere ' +
    'fast.';
  • 编程时使用join而不是字符串连接来构建字符串,特别是IE

    var items,
        messages,
        length, i;
    
    messages = [{
      state: 'success',
      message: 'This one worked.'
    },{
      state: 'success',
      message: 'This one worked as well.'
    },{
      state: 'error',
      message: 'This one did not work.'
    }];
    
    length = messages.length;
    
    // bad
    function inbox(messages) {
      items = '<ul>';
    
      for (i = 0; i < length; i++) {
        items += '<li>' + messages[i].message + '</li>';
      }
    
      return items + '</ul>';
    }
    
    // good
    function inbox(messages) {
      items = [];
    
      for (i = 0; i < length; i++) {
        items[i] = messages[i].message;
      }
    
      return '<ul><li>' + items.join('</li><li>') + '</li></ul>';
    }

函数

  • 函数表达式:

    // 匿名函数表达式
    var anonymous = function() {
      return true;
    };
    
    // 有名函数表达式
    var named = function named() {
      return true;
    };
    
    // 立即调用函数表达式
    (function() {
      console.log('Welcome to the Internet. Please follow me.');
    })();
  • 绝对不要在一个非函数块里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同。

    // bad
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }
    
    // good
    if (currentUser) {
      var test = function test() {
        console.log('Yup.');
      };
    }
    • 绝对不要把参数命名为 arguments, 这将会逾越函数作用域内传过来的 arguments 对象.
    // bad
    function nope(name, options, arguments) {
      // ...stuff...
    }
    
    // good
    function yup(name, options, args) {
      // ...stuff...
    }

属性

  • 当使用变量访问属性时使用中括号.

    var luke = {
      jedi: true,
      age: 28
    };
    
    function getProp(prop) {
      return luke[prop];
    }
    
    var isJedi = getProp('jedi');

变量

  • 总是使用 var 来声明变量,如果不这么做将导致产生全局变量,我们要避免污染全局命名空间。

    // bad
    superPower = new SuperPower();
    
    // good
    var superPower = new SuperPower();
  • 使用一个 var 以及新行声明多个变量,缩进4个空格。

    // bad
    var items = getItems();
    var goSportsTeam = true;
    var dragonball = 'z';
    
    // good
    var items = getItems(),
        goSportsTeam = true,
        dragonball = 'z';
    • 最后再声明未赋值的变量,当你想引用之前已赋值变量的时候很有用。
    // bad
    var i, len, dragonball,
        items = getItems(),
        goSportsTeam = true;
    
    // bad
    var i, items = getItems(),
        dragonball,
        goSportsTeam = true,
        len;
    
    // good
    var items = getItems(),
        goSportsTeam = true,
        dragonball,
        length,
        i;
    • 在作用域顶部声明变量,避免变量声明和赋值引起的相关问题。
    // bad
    function() {
      test();
      console.log('doing stuff..');
    
      //..other stuff..
    
      var name = getName();
    
      if (name === 'test') {
        return false;
      }
    
      return name;
    }
    
    // good
    function() {
      var name = getName();
    
      test();
      console.log('doing stuff..');
    
      //..other stuff..
    
      if (name === 'test') {
        return false;
      }
    
      return name;
    }
    
    // bad
    function() {
      var name = getName();
    
      if (!arguments.length) {
        return false;
      }
    
      return true;
    }
    
    // good
    function() {
      if (!arguments.length) {
        return false;
      }
    
      var name = getName();
    
      return true;
    }

条件表达式和等号

  • 适当使用 ===!== 以及 ==!=.

  • 条件表达式的强制类型转换遵循以下规则:

    • 对象 被计算为 true
    • Undefined 被计算为 false
    • Null 被计算为 false
    • 布尔值 被计算为 布尔的值
    • 数字 如果是 +0, -0, or NaN 被计算为 false , 否则为 true
    • 字符串 如果是空字符串 '' 则被计算为 false, 否则为 true
    if ([0]) {
      // true
      // An array is an object, objects evaluate to true
    }
  • 使用快捷方式.

    // bad
    if (name !== '') {
      // ...stuff...
    }
    
    // good
    if (name) {
      // ...stuff...
    }
    
    // bad
    if (collection.length > 0) {
      // ...stuff...
    }
    
    // good
    if (collection.length) {
      // ...stuff...
    }

  • 给所有多行的块使用大括号

    // bad
    if (test)
      return false;
    
    // good
    if (test) return false;
    
    // good
    if (test) {
      return false;
    }
    
    // bad
    function() { return false; }
    
    // good
    function() {
      return false;
    }

注释

  • 使用 /** ... */ 进行多行注释,包括描述,指定类型以及参数值和返回值

    // bad
    // make() returns a new element
    // based on the passed in tag name
    //
    // @param <String> tag
    // @return <Element> element
    function make(tag) {
    
      // ...stuff...
    
      return element;
    }
    
    // good
    /**
    * make() returns a new element
    * based on the passed in tag name
    * @param <String> tag
    * @return <Element> element
    */
    function make(tag) {
        // ...stuff...
        return element;
    }
  • 使用 // 进行单行注释,在评论对象的上面进行单行注释,注释前放一个空行.

    // bad
    var active = true;  // is current tab
    
    // good
    // is current tab
    var active = true;
    
    // bad
    function getType() {
      console.log('fetching type...');
      // set the default type to 'no type'
      var type = this._type || 'no type';
    
      return type;
    }
    
    // good
    function getType() {
      console.log('fetching type...');
    
      // set the default type to 'no type'
      var type = this._type || 'no type';
    
      return type;
    }
    • 如果你有一个问题需要重新来看一下或如果你建议一个需要被实现的解决方法的话需要在你的注释前面加上 FIXMETODO 帮助其他人迅速理解
    function Calculator() {
    
      // FIXME: shouldn't use a global here
      total = 0;
    
      return this;
    }
    function Calculator() {
    
      // TODO: total should be configurable by an options param
      this.total = 0;
    
      return this;
    }

空白

  • 将tab设为4个空格

    // bad
    function() {
      ∙∙var name;
    }
    
    // bad
    function() {
      ∙var name;
    }
    
    // good
    function() {
      ∙∙∙∙var name;
    }
  • 大括号前放一个空格

    // bad
    function test(){
      console.log('test');
    }
    
    // good
    function test() {
      console.log('test');
    }
    
    // bad
    dog.set('attr',{
      age: '1 year',
      breed: 'Bernese Mountain Dog'
    });
    
    // good
    dog.set('attr', {
      age: '1 year',
      breed: 'Bernese Mountain Dog'
    });
    • 在做长方法链时使用缩进.
    // bad
    $('#items').find('.selected').highlight().end().find('.open').updateCount();
    
    // good
    $('#items')
      .find('.selected')
      .highlight()
      .end()
      .find('.open')
      .updateCount();
    
    // bad
    var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
        .attr('width',  (radius + margin) * 2).append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);
    
    // good
    var leds = stage.selectAll('.led')
        .data(data)
      	.enter().append('svg:svg')
        .class('led', true)
        .attr('width',  (radius + margin) * 2)
      	.append('svg:g')
        .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
        .call(tron.led);

逗号

  • 不要将逗号放前面

    // bad
    var once
      , upon
      , aTime;
    
    // good
    var once,
        upon,
        aTime;
    
    // bad
    var hero = {
        firstName: 'Bob'
      , lastName: 'Parr'
      , heroName: 'Mr. Incredible'
      , superPower: 'strength'
    };
    
    // good
    var hero = {
      firstName: 'Bob',
      lastName: 'Parr',
      heroName: 'Mr. Incredible',
      superPower: 'strength'
    };
  • 不要加多余的逗号,这可能会在IE下引起错误,同时如果多一个逗号某些ES3的实现会计算多数组的长度。

    // bad
    var hero = {
      firstName: 'Kevin',
      lastName: 'Flynn',
    };
    
    var heroes = [
      'Batman',
      'Superman',
    ];
    
    // good
    var hero = {
      firstName: 'Kevin',
      lastName: 'Flynn'
    };
    
    var heroes = [
      'Batman',
      'Superman'
    ];

分号

  • 语句结束一定要加分号

    // bad
    (function() {
      var name = 'Skywalker'
      return name
    })()
    
    // good
    (function() {
      var name = 'Skywalker';
      return name;
    })();
    
    // good
    ;(function() {
      var name = 'Skywalker';
      return name;
    })();

类型转换

  • 在语句的开始执行类型转换.

  • 字符串:

    //  => this.reviewScore = 9;
    
    // bad
    var totalScore = this.reviewScore + '';
    
    // good
    var totalScore = '' + this.reviewScore;
    
    // bad
    var totalScore = '' + this.reviewScore + ' total score';
    
    // good
    var totalScore = this.reviewScore + ' total score';
  • 对数字使用 parseInt 并且总是带上类型转换的基数.

    var inputValue = '4';
    
    // bad
    var val = new Number(inputValue);
    
    // bad
    var val = +inputValue;
    
    // bad
    var val = inputValue >> 0;
    
    // bad
    var val = parseInt(inputValue);
    
    // good
    var val = Number(inputValue);
    
    // good
    var val = parseInt(inputValue, 10);
    
    // good
    /**
    * parseInt was the reason my code was slow.
    * Bitshifting the String to coerce it to a
    * Number made it a lot faster.
    */
    var val = inputValue >> 0;
  • 布尔值:

var age = 0;

// bad
var hasAge = new Boolean(age);

// good
var hasAge = Boolean(age);

// good
var hasAge = !!age;

命名约定

  • 避免单个字符名,让你的变量名有描述意义。
// bad
function q() {
  // ...stuff...
}

// good
function query() {
  // ..stuff..
}
  • 当命名对象、函数和实例时使用驼峰命名规则
// bad
var OBJEcttsssss = {};
var this_is_my_object = {};
var this-is-my-object = {};
function c() {};
var u = new user({
  name: 'Bob Parr'
});

// good
var thisIsMyObject = {};
function thisIsMyFunction() {};
var user = new User({
  name: 'Bob Parr'
});
  • 当命名构造函数或类时使用驼峰式大写

    ```javascript
    // bad
    function user(options) {
      this.name = options.name;
    }
    
    var bad = new user({
      name: 'nope'
    });
    
    // good
    function User(options) {
      this.name = options.name;
    }
    
    var good = new User({
      name: 'yup'
    });
    ```
    
    • 命名私有属性时前面加个下划线 _

      // bad
      this.__firstName__ = 'Panda';
      this.firstName_ = 'Panda';
      
      // good
      this._firstName = 'Panda';
  • 当保存对 this 的引用时使用 _this.

    ```javascript
    // bad
    function() {
      var self = this;
      return function() {
        console.log(self);
      };
    }
    
    // bad
    function() {
      var that = this;
      return function() {
        console.log(that);
      };
    }
    
    // good
    function() {
      var _this = this;
      return function() {
        console.log(_this);
      };
    }
    ```
    

存取器

  • 属性的存取器函数不是必需的
  • 如果你确实有存取器函数的话使用getVal() 和 setVal('hello')
// bad
dragon.age();

// good
dragon.getAge();

// bad
dragon.age(25);

// good
dragon.setAge(25);
  • 如果属性是布尔值,使用isVal() 或 hasVal()
// bad
if (!dragon.age()) {
  return false;
}

// good
if (!dragon.hasAge()) {
  return false;
}
  • 可以创建get()和set()函数,但是要保持一致
function Jedi(options) {
  options || (options = {});
  var lightsaber = options.lightsaber || 'blue';
  this.set('lightsaber', lightsaber);
}

Jedi.prototype.set = function(key, val) {
  this[key] = val;
};

Jedi.prototype.get = function(key) {
  return this[key];
};

构造器

  • 给对象原型分配方法,而不是用一个新的对象覆盖原型,覆盖原型会使继承出现问题。

    function Jedi() {
      console.log('new jedi');
    }
    
    // bad
    Jedi.prototype = {
      fight: function fight() {
        console.log('fighting');
      },
    
      block: function block() {
        console.log('blocking');
      }
    };
    
    // good
    Jedi.prototype.fight = function fight() {
      console.log('fighting');
    };
    
    Jedi.prototype.block = function block() {
      console.log('blocking');
    };
  • 方法可以返回 this 帮助方法可链。

    // bad
    Jedi.prototype.jump = function() {
      this.jumping = true;
      return true;
    };
    
    Jedi.prototype.setHeight = function(height) {
      this.height = height;
    };
    
    var luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20) // => undefined
    
    // good
    Jedi.prototype.jump = function() {
      this.jumping = true;
      return this;
    };
    
    Jedi.prototype.setHeight = function(height) {
      this.height = height;
      return this;
    };
    
    var luke = new Jedi();
    
    luke.jump()
      .setHeight(20);
  • 可以写一个自定义的toString()方法,但是确保它工作正常并且不会有副作用。

    function Jedi(options) {
      options || (options = {});
      this.name = options.name || 'no name';
    }
    
    Jedi.prototype.getName = function getName() {
      return this.name;
    };
    
    Jedi.prototype.toString = function toString() {
      return 'Jedi - ' + this.getName();
    };

事件

  • 当给事件附加数据时,传入一个哈希而不是原始值,这可以让后面的贡献者加入更多数据到事件数据里而不用找出并更新那个事件的事件处理器

    // bad
    $(this).trigger('listingUpdated', listing.id);
    
    ...
    
    $(this).on('listingUpdated', function(e, listingId) {
      // do something with listingId
    });

    更好:

    // good
    $(this).trigger('listingUpdated', { listingId : listing.id });
    
    ...
    
    $(this).on('listingUpdated', function(e, data) {
      // do something with data.listingId
    });

模块

  • 模块应该以 ! 开始,这保证了如果一个有问题的模块忘记包含最后的分号在合并后不会出现错误
  • 这个文件应该以驼峰命名,并在同名文件夹下,同时导出的时候名字一致
  • 加入一个名为noConflict()的方法来设置导出的模块为之前的版本并返回它
  • 总是在模块顶部声明 'use strict';
// fancyInput/fancyInput.js

!function(global) {
  'use strict';

  var previousFancyInput = global.FancyInput;

  function FancyInput(options) {
    this.options = options || {};
  }

  FancyInput.noConflict = function noConflict() {
    global.FancyInput = previousFancyInput;
    return FancyInput;
  };

  global.FancyInput = FancyInput;
}(this);

jQuery

  • 缓存jQuery查询
// bad
function setSidebar() {
  $('.sidebar').hide();

  // ...stuff...

  $('.sidebar').css({
    'background-color': 'pink'
  });
}

// good
function setSidebar() {
  var $sidebar = $('.sidebar');
  $sidebar.hide();

  // ...stuff...

  $sidebar.css({
    'background-color': 'pink'
  });
}
  • 对DOM查询使用级联的 $('.sidebar ul')$('.sidebar ul')
  • 对有作用域的jQuery对象查询使用 find
// bad
$('.sidebar', 'ul').hide();

// bad
$('.sidebar').find('ul').hide();

// good
$('.sidebar ul').hide();

// good
$('.sidebar > ul').hide();

// good (slower)
$sidebar.find('ul');

// good (faster)
$($sidebar[0]).find('ul');

ECMAScript 5兼容性

性能

react组件开发规范

要求编码规范,接口定义规范,组件结构自由给予用户充分定制能力。

文件命名

  • 每一个文件只包含一个组件,每一个基本组件只包含单一功能
  • src目录下,如果文件返回是一个类,文件名首字母大写
  • 文件js模块统一使用js后缀名
  • 测试用例文件名使用.spec.js后缀
  • 每一个组件使用一个单独的测试用例文件

js规范

  • 使用es6开发,尽量使用常用的ES6语法,(ES6语法参考)[http://es6.ruanyifeng.com/]

  • 使用jsx语法

  • 组件仓库命名为小写和“-”连接,如button、button-group

  • 组件文件命名使用大驼峰, ComponentDemo

  • 带命名空间的组件,如果一个组件包含只有自身使用的子组件,以该组件为命名空间编写组件,例如Table,Table.Head

  • 不使用displayName命名

  • 自定义属性使用data-

  • 使用propTypes进行props类型校验

  • 使用defaultProps定义默认参数

  • 定义props避开react关键字及保留字,常用的props及state定义可参考下表

  • 尽量少或者不使用ref获取和操作dom节点,使用state和prop进行控制dom

  • 事件调用使用在元素上onClick调用

  • 注意,react和html的表单元素的差异

  • 使用es6后,不支持mixin,使用decorator进行扩展,(babel?需要增加解析器)和高阶组件方式扩展。

  • 尽量不使用比较大的第三方js库

  • 组件方法定义顺序 constructor --> 声明周期方法(componentWillMount,componentDidMount,
    componentWillUpdate,componentDidUpdate,componentWillUnmount)

  • 尽量多而有用的代码注释,方法用块级注释,结构如下例。

  • 有必要需要些组件的销毁方法,比如 定时器,需要用销毁方法销毁定时器

  • ...others 没有必要 勿用

  • 自身定义的props属性应避免与react的关键字相同

  • 代码规范使用 airbnb规范

样式规范

  • 组件样式使用sass编写,公用样式使用tinper-bee-core包,请阅读tinper-bee-core文档
  • 组件样式调用,使用classnames模块,进行样式处理,使用className调用
  • 所有组件默认类名命名以`u-``开头
  • 组件使用clsPrefix为样式前缀,用户也可在组件上设置自定义的clsPrefix="yourPre"
const clsPrefix = 'u-select';
const class1 = {
    [`${clsPrefix}-item`]: true,
    [`${clsPrefix}-item-last`]: stepLast,
    [`${clsPrefix}-status-${status}`]: true,
    [`${clsPrefix}-custom`]: icon
  };
const class2 = [`${clsPrefix}-submit`, `${clsPrefix}-item`];

const classString = classNames('hide', class1, class2);
  • 可提供多种颜色的组件,在写scss文件时,颜色设置需提出公用的minxin方法例如Alert组件中设置多种颜色: @alert-styles-variant

通用组件接口规范

参数 说明 类型 默认值
size 尺寸 string medium
color 颜色 string ''
shape 形状 string ''
disabled 是否禁用(disabledtrue false) bool false
className 增加额外的类名 string ''
htmlType html dom 的 type 属性 string ''
style 内联样式 object ''
clsPrefix 自定义样式前缀 string ''

对于方法的传递,外部使用onClick传入事件,内部使用handleClick进行接收使用

国际化

当你的组件包含一些文字时,在src目录下,创建i18n.js文件,写下对应的hash值。内容如下:

module.exports = {
    'zh-cn': {
        'ok': '确定',
        'cancel': '取消',
        'isee': '知道了'
    },
    'en-us': {
        'ok': 'ok',
        'cancel': 'cancel',
        'isee': 'ok'
    }
}

组件内这么使用:

import i18n from './i18n';
import React from 'react';

Example.defaultProps = {
    locale: 'zh-cn'
};

class Example extends React.Component {
    constructor(props) {
        super(props);
    }


    render() {
        const {locale} = this.props;
        const locale = i18n[locale];

        const buttons= [
            <Button>
                {locale['ok']}
            </Button>,
            <Button>
                {locale['cancel']}
            </Button>
        ];
        return (
            <div>
            { buttons }
            </div>
            )
    }
}


基本代码结构

//引入依赖
import React from 'react';
import ReactDOM from'react-dom';
import classnames from 'classnames';

//定义prop检验
const propTypes = {
//每一个props都要写注释
}

//定义默认参数
const defaultProps = {

}

/**
 * 定义组件
 */
class Button extends React.Component {
	constructor (props) {
		super(props);
		//定义state
		this.state = {
    //每一个state要写注释
		}
		// 事先声明方法绑定
		this.MyEvent = this.MyEvent.bind(this);
	}

    //自定义函数方法,及注释
      MyEvent () {

      }
    //组件生命周期方法


	render () {
		return (
			// <div onClick={this.MyEvent}></div>
		)
	}
}

Button.propTypes = propTypes;
Button.defaultProps = defaultProps;

export default Button;

常用npm包

keyCode
warning
var warning = require('warning');

var ShouldBeTrue = false;

warning(
  ShouldBeTrue,
  'This thing should be true but you set to false. No soup for you!'
);
bee-animate
bee-overlay
dom-helpers (3.0.0)

参考链接
https://github.com/react-component/react-component.github.io/blob/master/docs/zh-cn/code-style/js.md

规范的落地:编辑器配置和构建流程集成

编辑器配置文件

.editorconfig 文件:

## http://editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 80
trim_trailing_whitespace = true

[*.md]
max_line_length = 0
trim_trailing_whitespace = false

[COMMIT_EDITMSG]
max_line_length = 0

eslint、csslint

可采用开源方案 eslint 和 csslint ,将其集成在 webpack、gulp 等构建工作流中。后续 uba 将会在工具层结合规范进行封装。

资源:

性能优化相关方案及规范

以下为前端性能优化相关的方案指导,具体优化实践应结合项目具体情况进行,不可为了优化而优化(性能优化和开发效率、用户体验以及实现成本等是相结合的)。性能优化的实现手段多样,关注领域复杂,从前到后,自上而下,方方面面都是性能优化的地方。

图片优化

  • 优化图像

    • 检查gif图片图像颜色数量和调色板规格是否一致
    • 有gif的情况考虑换成png
    • 色值较少的图片切成jpg
  • Inline images

    • 通过编码的字符串将图片直接内嵌在网页文本中
    • base64编码
  • image Maps

    • 将多张图拼在一起,通过坐标来控制显示导航
  • 优化css sptite,合成雪碧图

    • 可以选用单独的工具来生成雪碧图
    • 使用构建工具来分析产出雪碧图
  • 不在html中缩放图片

  • 使用小且可缓存defavicon.ico

    • 浏览器总会去请求这个图标
    • 确保图标存在,否则报错
    • 文件尽量小,最好小于1K
    • 设置一个长的过期时间

对 javascript 脚本代码的优化

  • js脚本文件置底
  • 现在主流浏览器都支持defer关键字,可以指定脚本在文档加载后执行
  • 使用外链js和css文件
  • 减少DOM访问和查询
    • 换成已经访问过的元素
    • 优化dom的选择器
    • 避免通过js修复layout
    • 优化逻辑减少dom操作
    • 双向数据绑定
    • dom diff
    • dom拼接
  • 减少或避免引起页面repaint或reflow的代码逻辑
  • 使用智能事件处理方式
    • 事件代理

对 css 的优化

  • 样式表置顶
  • 避免css表达式
  • 用link代替@import
  • 减少层级
  • 避免filters
  • 避免冗余
  • css文件合理管理

关于 cookie 的使用规范

  • 减少cookie大小
  • cookie用来做认证和个性化设置,在请求中包含在http报文头
  • 如果网页不需要用cookie,就完全禁掉
  • cookie的domain不可影响到子domain
  • 设置合适的过期时间
  • 页面内容使用无cookie域名

在服务器端的一些优化手段

  • 使用cdn分发资源
    • cdn通过部署在不同地区的服务器来提高客户的下载速度
    • 可将站点大量的静态内容放上cdn
  • 添加expires或cache-control报文头
    • 静态内容添加expires,将静态内容设置为永不过期
    • 动态内容适合cache-control,让浏览器根据条件来发送请求
  • gzip压缩
  • 配置etags
  • flush输出
  • get请求
  • 避免空的图片src

对于网页资源的优化

  • 减少http请求次数
    • combo合并多个文件请求为一个
    • 打包合并文件,打包策略很重要
  • 减少dns查询次数
    • 愿意在于网页中包含不同domain的内容时,如嵌入广告或引用了外部图片或脚本导致
    • dns查询结果可缓存在本地和浏览器一段时间,所以一般在首次访问时消耗流量
  • 避免页面跳转
  • 缓存ajax请求
  • 延迟加载
    • 确定页面初始加载需要的最小内容集,剩下内容推到延迟加载的集合中
  • 提前加载
    • 有条件提前加载
      • 用户的输入推断需要加载的内容,如智能搜索框
    • 无条件提前加载
      • 当前网页加载完成后,马上去下载一些其他的内容,这些内容是必须会用到的或是公共依赖的
  • 减少DOM元素数量
  • 根据域名划分内容
  • 减少iframe数量
    • 优点
      • 用来加载速度较慢的广告
      • 安全沙箱保护
      • 脚本可以并行下载
    • 缺点
      • 即使iframe内容为空也消耗加载时间
      • 会阻止页面的加载
  • 避免404

移动端方面的优化

  • localStorage本地存储与优化
    • 大数据量交互,数据不怎么更新的,含版本控制机制,一次请求,之后高枕无忧
    • 充分利用其资源
  • 保持单个内容小于25K
    • 这是因为iphone的限制,它只能缓存解压后小于25K的资源
    • 所以单纯gzip不一定够用,精简文件工具
  • 打包文档

参考链接
https://github.com/iuap-design/YY-Code-Guide

《平凡的世界》赏析

关于作者

这是我读的第一本路遥的小说,但是就在我读完这本书的第一章之后。我就深深的被路遥细腻的文笔所吸引了,这也使我兴奋了很久。那细腻的文笔让人能很清晰的在脑海中绘画出,那文笔中透露出来的画面。这种文笔让我觉得哪怕他的小说的情节再烂,也有一种让读者读下去的欲望,更何况情节很曲折动人(虽然我还没有看完)。

场景赏析

1.贫穷的少平捡残汤剩饭情节:

“他直起身子来,眼睛不由地朝三只空荡荡的菜盆里了一眼。他瞧见乙菜盆的底子上还有一点残汤剩水。房上的檐水滴答下来,盆底上的菜汤四处飞溅。他头瞧了瞧:雨雪迷蒙的大院坝里空无一人。他很快蹲下来,慌得如同偷窃一般,用勺子把盆底上混合着雨水的剩菜汤往自己的碗里舀。铁勺刮盆底的嘶啦声象炸弹的爆炸声一样令人惊心。血涌上了他黄瘦的脸。一滴很大的檐水落在盆底,溅了他一脸菜汤。他闭住眼,紧接着,就见两颗泪珠慢慢地从脸颊上滑落了下来——唉,我们姑且就认为这是他眼中溅进了辣子汤吧!” 选自《平凡的世界》第一章

这一段中通过一些人物细微的动作,还有通过描写铁勺在盆底舀菜汤的动作,生动的描写了一个自尊心很强的,贫穷的农村小伙子捡残汤剩饭,害怕被别的同学发现的丰富的内心纠葛,将主人公的紧张恐惧的心里表现的淋漓尽致

2.作为大学生的晓霞再见到少平后对时代的感慨:

”是的,他在我们的时代属于这样的青年:有文化,但没有幸运地进入大学或参加工作,因此似乎没有充分的条件直接参与�到目前社会发展的主潮之中。而另外一方面,他们又不甘心把自己局限在狭小的生活天地里。因此,他们往往带着一种悲壮的激情,在一条最为艰难的道路上进行人生的搏斗。他们顾不得高谈阔论或愤世嫉俗地忧患人类的命运。他们首先得改变自己的生存条件,同时也放弃最主要的精神追求;他们既不鄙视普通人的世俗生活,但又竭力使自己对生活的认识达到更深的层次

这段话在现在的社会何尝不是这样呢,每个人基本顾不得忧患人类的命运,都是在思考自己怎么去改变自己的生存条件。自己何时才能买得起一套房,一辆车。更有甚者,沦为车奴,房奴。但是现在社会已较当时的社会现状好了很多,现在至少农民的孩子能通过自己的努力能够获得成功,能让自己获得财富。所以让我们整理好思绪再出发。

加油,2017!

出发,2017!

github pages+阿里云域名绑定搭建个人博客

一直想整出一个个人博客出来玩玩,于是就查了些资料,发现在域名绑定个人博客这一块的资料比较杂,试了很多次才成功,所以写出篇文章供大家更方便的操作。

1.获取github pages的ip地址

打开你的电脑的命令行工具,ping你的github地址,忽略“/”后面的路径,比如我的github pages地址是huyuee.github.io/blog,那么我需要ping的地址就是huyuee.github.io,如下图:

image

我得到了我的github pages的ip地址:151.101.100.133

2.配置阿里云域名解析

进入你的阿里云的解析域名列表,选择你想要解析的域名,点击后面的解析。如下图所示:

image

然后点击添加解析,因为我的ip地址是151.101.100.133,所以我添加了两条解析记录。如下图所示:

image

3.配置github pages的custom domain

进入你的github pages的仓库,然后在设置里面将的你的域名的地址,添加到custom domain中,然后保存即可。如下图所示:

image

设置到这个地方,你现在访问你的域名地址,比如我的是www.huyuee.com。就能看到你的github pages了!

with语句详解

with这种语法现如今应该已经无人问津了,但是还是想来说说这个在JavaScript中的用法和缺点

介绍

with语句的作用是将代码的作用域设置到一个特定的对象中。

利:with语句可以在不造成性能损失的情况下,减少变量的长度。很多情况下,也可以不使用with语句,而是使用一个临时变量来保存指针,来达到同样的效果。

弊:with语句使得程序在查找该语句块中的所有的变量值时,都是先在该with语句指定的对象下面先寻找一遍,然后再去外面的作用域去寻找。所以尽量不要在该语句块中去使用一些不属于该对象中的变量

用法

var x = {
  name : "古朋",
  nick_name : "gupeng"
};
with(x){
  console.log(name+'的小名是'+nick_name);
}

可以替换为:

var x = {
  name : "古朋",
  nick_name : "gupeng"
};
/*
 *这里将x对象赋值到当前局部变量中,减少不必要的指针路径解析运算
 *一般用于在在方法中将this对象局部化,比如:var this_ = this;
 */
var x_ = x;
console.log(x_.name+'的小名是'+x_nick_name);

个人主页

  1. 主页
  2. 简历
  3. 博客
  4. 生活
    1. 使用jq效果
    2. 拆分效果代码实现组件化,方便利用

算法:排序

1.堆排序
先使用最大堆的算法排出顺序,然后取出根节点继续递归使用最大堆算法算出第二大的数,以此类推。
1.1 最大堆算法

算法:小试牛刀

  1. 如何判断一个点 p3 是在直线 p1p2 的左边还是右边呢?
  2. 凸包
  3. 时间复杂度

form文件提交过程

form表单提交

标签的属性enctype设置以何种编码方式提交表单数据。可选的值有三个:
  • application/x-www-form-urlencoded(默认值): 在发送到服务器之前,所有字符都会进行编码(空格转换为 "+" 加号,特殊符号转换为 ASCII HEX 值)
  • multipart/form-data : 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值,否则会无视掉文件
  • text/plain(不常见): 空格转换为 "+" 加号,但不对特殊字符编码。

优秀的品质

优秀的本质

  1. 内心深处对优秀的一种的强烈的渴望
  2. 对生命追求的火热的激情

--来自俞敏洪的《开讲啦》

apply和call的说明?

介绍

有编程开发经验的都知道函数有作用域这种东西,JavaScript中的函数中的亦是如此。但是想要更改该函数的作用域,最方便的方式就是通过apply和call方法

用法

apply和call在功能上是相同的,但是唯一的不同之处在于提供参数的方式。

  1. apply使用参数数组而不是一组参数列表

    window.color = "red";
    var a = {
      color : "blue"
    };
    var x = function(){
      alert(this.color+"--"+arguments.length);
    }
    x();//red is 0
    x.apply(window);//red is 0
    x.apply(a,[1,2,3]);//blue is 3

  2. call使用时参数列表

    window.color = "red";
    var a = {
      color : "blue"
    };
    var x = function(){
      alert(this.color+" is "+arguments.length);
    }
    x();//red is 0
    x.call(window);//red is 0
    x.call(a,1,2,3);//blue is 3

1.apply语法

fun.apply(thisArg[, argsArray])

参数

  • thisArg

    fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 nullundefined会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。

  • argsArray

    一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 {{jsxref("Global_Objects/undefined", "undefined")}},则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。浏览器兼容性请参阅本文底部内容。

2.call语法

fun.call(thisArg[, arg1[, arg2[, ...]]])

参数

  • thisArg

    fun函数运行时指定的this值*。*需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为nullundefinedthis值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。

  • arg1, arg2, ...

    指定的参数列表。

兼容性

apply兼容性
call兼容性

react学习笔记(二)

10. 事件处理

React事件处理和DOM元素很相似。但是语法上有点不一样:

  • React事件绑定属性的命名采用驼峰式写法,而不是小写(DOM元素使用小写)。比如:onClick = { xxx }
  • 在React中不能通过return false的方式来阻止默认行为,必须明确的使用e.preventDefault();

在组件中,必须谨慎对待JSX回调函数中的this,类的方法默认是不会绑定this的。

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    //如果不在此绑定this,那么this在handleClick方法中将是undefined.也可以使用箭头函数语法,就不用在此绑定了👍
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

11. 条件渲染

1. 普通用法

直接可以使用if表达式进行判断,然后再加载不同的组件。不能直接在render()方法中书写。在线地址

2. JSX用法

####与运算符 &&

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
);

总结:可以直接在render中书写,如果条件是 true&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。

三目运算符

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}

阻止组件渲染

总结:可以通过return null来实现。很暴力!😜😜😜

注意:阻止组件渲染,并不会影响该组件生命周期方法的回调。例如,componentWillUpdatecomponentDidUpdate 依然可以被调用。

12. 列表渲染

list元素中必须包括一个特殊的key属性。

key在DOM中的某些元素被增加或删除的时候帮助React识别哪些元素发生了变化。key最好是该元素在列表中独一无二。通常使用id,没有id时候也可以使用序列号索引index作为key。但是如果列表可以重新排序,不见使用索引。这会导致渲染变得很慢。因为在操作的时候,React依赖于启发式算法。不稳定的key将使得组件实例和DOM节点进行不必要的重建,使得性能下降并丢失子组件的状态。

注意:key会作为给React的提示,但不会传递给你的组件。

13. 表单

当在多个输入的解决方法,你可以通过给每个元素添加一个name属性,然后让state中添加name的值,来动态的判断是何组件

handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

<input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
            
            

受控组件

也就是说通过修改state的状态来动态的渲染ui和更新数据

<input type="text" value={this.state.value} onChange={this.handleChange} />

非受控组件

不需要为每个状态更新编写事件处理程序,你可以 使用 ref 从 DOM 获取表单值。

//通过this.input.value来取到value
<input type="text" ref={(input) => this.input = input} />

总结:这两者差别这篇关于受控和非受控的表单输入

14. 状态提升

通常,状态都是首先添加在需要渲染数据的组件中。此时,如果另一个组件也需要这些数据,你可以将数据提升至离它们最近的父组件中。你应该在应用中保持 自上而下的数据流,而不是尝试在不同组件中同步状态。

好处:可以更快地寻找和定位bug的工作

code地址

15. 组合

包含关系

可以使用children属性将子元素直接传递到输出。props.children

也可以使用自己约定的属性而不是children,比如下面例子的left和right:

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={
        <Contacts />
      }
      right={
        <Chat />
      } />
  );
}

16. React 理念

使用 React 一起创建一个可搜索的产品数据表格,并向你展示我们的思考过程。地址

总结:这篇文章从一个具体的需求来给读者展示,一个需求功能如何优雅的通过react完成。

前端知识体系目录

  1. HTML/HTML5基础:

  2. 高健壮性CSS

    • 学习基础知识,包括大部分常用属性、选择器的用法,要对大多数标签有个基础概念,在日常使用的基础上,尝试学习浏览器兼容性问题,要知道兼容性的主要问题及解决方法
    • 深入理解盒子模型,一定要弄清楚区分盒子、行内盒子的概念另外可以考虑学一些预编译语言:sass、less,都很简单—CSS盒模型
    • 有几个比较重要的属性:display、float、position
    • 学习常用框架,可以使用bootstrap构建项目
    • 学习框架的代码组织方式包括:12格栅系统、组件化、组件的风格化等
    • 学习CSS 3的新功能,特别是动画效果、选择器
    • 认真学习一些CSS对象化**,学习编写简洁性、高复用性、高健壮性的CSS
    • 有空的话,可以看看所谓的扁平化设计,还有简洁性
    • 理解CSSOM、render、reflow、CSS性能、CSS阻塞概念
    • 多看别人的代码,一些设计的不错的网站就是很好的学习素材,比如拉勾网
    • 一定要学会使用grunt、gulp压缩CSS
    • display + position + float 可以组合出很复杂的效果,多想想盒子模型
    • 尝试在不用float,且position不为absolute的情况下实现等高、等宽等布局
    • 推荐书籍:
      - 《图灵程序设计丛书:HTML5与CSS3设计模式》
      - 《Web开发技术丛书:深入理解Bootstrap》
      - 《高流量网站CSS开发技术》
      - 《CSS设计彻底研究》 这个一定要
      - 《Web开发技术丛书:深入理解Bootstrap》
      - 可以找一些专门讲SASS的书,但是我没找到
      - 《CSS权威指南(第3版)》
  3. 深入学习JS

    • #82
    • 深入理解JS的“一级函数”、对象、类的概念,学会使用函数来构造类、闭包,学会用面向对象的方式组织代码
    • 深入理解JS的作用域、作用域链、this对象(在各种调用形式中,this的指向)理解函数的各种调用方法(call、apply、bind等)
    • 利用正则表达式进行字符串替换
    • 理解对象、数组的概念;理解对象的“[]”调用,理解对象是一种“特殊数组”;理解for语句的用法;深入理解JS中原始值、包装对象的概念(重要)
    • 学习一些常用框架的使用方法,包括:JQUERY、underscore、EXTJS,加分点有:backbone、angularjs、ejs、jade;通过比较多个框架的使用方法,想清楚“JS语言极其灵活”这一事实;总结常见用法,提高学习速度;学习模块化开发(使用require.js、sea.js等)
    • 适当看一些著名框架的源码,比如jQuery(不建议看angularjs,太复杂了);重要的是学习框架中代码的组织形式,即设计模式
    • 了解JS解释、运行过程,理解JS的单线程概念;深入理解JS事件、异步、阻塞概念
    • 理解浏览器组成部件,理解V8的概念;学习V8的解释-运行过程;在V8基础上,学会如何提高JS性能;学会使用chrome的profile进行内存泄露分析
    • 学习方法:
      - 提高对自己的要求,要有代码洁癖
      - 适当的时候看看优秀框架的源码,特别是框架的架构模式、设计模式
      - 多学学设计模式
      - 学习原生JS、DOM、BOM、Ajax
    • 推荐书籍:
      - 《O’Reilly精品图书系列:JavaScript权威指南(第6版)》 必看
      - 《JavaScript设计模式》
      - 《WebKit技术内幕》
      - 《JavaScript框架高级编程:应用Prototype YUI Ext JS Dojo MooTools》
      • 《用AngularJS开发下一代Web应用》
  4. 跨终端

    • 理解混合APP的概念
    • 理解网页在各类终端上的表现
    • 理解网页与原生app的区同,重在约束
    • 理解单页网站,特别要规避页面的内存泄露问题
    • 入门nodejs,对其有个基础概念,知道它能做什么,缺点是什么
    • 推荐书籍:
      - 《单页Web应用:JavaScript从前端到后端 》
      - 《Web 2.0界面设计模式》
      - 《响应式Web设计:HTML5和CSS3实战》
  5. 工具

    • 学会使用grunt进行JS、CSS、HTML 压缩,特别是模块化js开发时候的压缩
    • 会用PS进行切图、保存icon
    • 入手sublime、webstorm
    • 学会使用chrome调试面板,特别是:console、network、profile、element
  6. 性能

    • 理解资源加载的过程,包括:TCP握手连接、HTTP请求报文、HTTP回复报文
    • 理解资源加载的性能约束,包括:TCP连接限制、TCP慢启动
    • 理解CSS文件、JS文件压缩,理解不同文件放在页面不同位置后对性能的影响
    • 理解CDN加速
    • 学会使用HTTP头控制资源缓存,理解cache-control、expire、max-age、ETag对缓存的影响
    • 深入理解浏览器的render过程
    • 推荐书籍:
      - 《Web性能权威指南》
      - 雅虎网站页面性能优化的34条黄金守则
  7. HTTP及TCP协议族

    • 学习http协议,理解http请求-响应模式
    • 理解http是应用层协议,它是构建在TCP/IP协议上的
    • 理解http报文(请求-响应报文)
    • 理解http代理、缓存、网关等概念,指定如何控制缓存
    • 理解http协议内容,包括:状态码、http头、长连接(http1.1)
    • 学习http服务器的工作模型,对静态文件、CGI、DHTML的处理流程有个大致概念
    • 推荐书籍:
      - 《HTTP权威指南》
      - 《TCP/IP详解》
      - 《图解TCP/IP(第5版)》
  8. 安全性

    • XSS、SQL注入

[转]MobX 入门教程

本文导读

最近一直在学习并研究mobx相关的,看了官方文档,也看到了阿华的日报里面推荐了相关的文章链接。但是要说mobx入门教程,这篇文章着实让人比较容易明白。所以迫切的想分享给各位,从下个段落开始就是那篇文章了,原文地址。但是我事后好好思考了一番,为什么别的大神(大牛)写的入门教程为什么这么通俗易懂呢。于是我总结了一个写入门教程的好一点的方式和套路。地址:如何写好一篇入门教程?

什么是 mobx

mobx 只做一件事,解决 state 到 view 的数据更新问题

img

mobx 是一个库 (library),不是一个框架 (framework)。他不限制如何组织代码,在哪里保存 state 、如何处理事件,怎么发异步请求等等。我们可以回归到 Vanilla JavaScript,可以和任意类库组合使用。

核心理念

mobx 引入了几个概念,Observable state, DerivationsReactions

img

可以拿 Excel 表格做个比喻,Observable state 是单元格,Derivations 是计算公式,单元格的修改会触发公司的重新计算,并返回值,而最终公式的计算结果需要显示在屏幕上(比如通过图表的方式),这是 Reactions

下面通过代码理解下这些概念,以 mobx 和 react 的组合使用为例:(Open Demo on jsfiddle)

import { observable, computed } from 'mobx';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

////////////////////
// Store

class TodoStore {
  @observable todos = [];
  @computed get completedTodosCount() {
    return this.todos.filter(todo => todo.completed === true).length;
  }
  addTodo(task) {
    this.todos.push({ task, completed: false });
  }
}

////////////////////
// Components

@observer
class TodoList extends Component {
  render() {
    const { todoStore } = this.props;
    return (
      <div>
        { todoStore.todos.map((todo, index) => <Todo todo={todo} key={index} />) }
        Progress: { todoStore.completedTodosCount }
      </div>
    );
  }
}

@observer
class Todo extends Component {
  render() {
    const { todo } = this.props;
    return (
      <li onDoubleClick={this.onRename}>
        <input
          type="checkbox"
          checked={ todo.completed }
          onChange={ this.onToggleCompleted }
        />
        { todo.task }
      </li>
    );
  }
  onToggleCompleted = () => {
    const todo = this.props.todo;
    todo.completed = !todo.completed;
  }
  onRename = () => {
    const todo = this.props.todo;
    todo.task = prompt('Task name', todo.task) || ""; 
  }
}

////////////////////
// Init

const todoStore = new TodoStore();
todoStore.addTodo('foo');
todoStore.addTodo('bar');

ReactDOM.render(
  <TodoList todoStore={todoStore} />,
  document.getElementById('mount')
);

这里通过 @observable 定义 Observable state,通过 @computed 定义 Derivations,通过 @observer 封装了 React Component 的 render 方法,这是 Reactions

为什么用 mobx

mobx 官网 罗列了不少区分与 flux 框架的优点,这里摘录一些比较打动我的。

简单

没有 connect,没有 cursor,没有 Immutable Data ... 总之感觉会少很多代码。同时概念也更少。

可以用 class 来组织和修改数据

对于组织复杂的领域模型比较适用。

可以用 JavaScript 引用来组织和修改数据

比如,可以直接

todo.completed = true;

而不需要

return todos.map((todo) => {
  if (todo.id === action.payload.id) {
    return {...todo, {completed: true}}
  else {
    return todo;
  }
});

同时也不需要引入额外的 immutable.js。

性能相比 redux 有优势

mobx 会建立虚拟推导图 (virtual derivation graph),保证最少的推导依赖。dan_abramov 亲自操刀为 todoMVC 做了极致的优化才和 mobx 打成平手。链接

不足

参考之前 redux + redux-saga 的方案,这里的一些点可能会成为你我不用他的原因。

浏览器兼容性,不支持 IE8

由于用了 reactive arrays, objects with reactive properties (getters) 这些 ES5 特性,而且这些特性不能通过 es5-shim 解决。兼容列表可参考:http://kangax.github.io/compat-table/es5/

缺少最佳实践

这部分不在 mobx 的范围之内,需要自己探索一套最佳实践。比如如何触发 action,如何组织 store,如何组织业务逻辑,如何发异步请求,如何在 React Component 之间传递数据等等。

热替换 (Hot Module Replacement)

用过 HMR,就不愿再回到手动刷页面的时代。mobx 支持 [react-transform] 的热替换方式,但是否支持 webpack 原生热替换情况下对 store 进行替换,还有待探索。

总结

mobx 简单高效,在用吐了 redux 之后,对 mobx 简直爱不释手。除了不支持 IE8 这个硬伤,其他缺点都还是可以接受的。我会在后面的小项目中应用它,并尝试探索一套最佳实践。

扩展阅读

原型对象

为什么要写原型对象?

原型,其实已经是前端知识中老生常谈的内容了。很多初学者和工作者其实都觉得这个概念其实跟你使用JavaScript没有太大的联系(因为我刚开始其实就是这样)。但是当你深入到代码中,一些架构中的时候,你就会发现巧妙的运用原型,能让你的代码写的既简洁又优美

什么是原型对象

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数原型对象

举个栗子:

function Person{
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
	alert(this.name);
};

var person1 = new Person();
person1.sayName(); //"Nicholas"

var person2 = new Person();
person2.sayName(); //"Nicholas"

alert(person1.sayName == person2.sayName); //true

如下图图一所示,针对于上面的“栗子”,Person是一个函数,那么在 JavaScript中就会为这个函数创建一个prototype的属性,这个prototype属性指向该函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor属性,这个属性指向该函数。

图一

如上图图一所示:当调用构造函数创建一个新实例(person1和person2)后,该实例的内部将包含一个指针,指向构造函数的原型对象(Person Prototype)。

原型对象的属性查找机制

查找机制是这样的:首先会先在实例上面搜索属性,如果找到了直接返回,否则就继续去原型上面寻找

说个形象一点的故事,这样好理解一点。假设:实例就是你,原型就是你的父亲。你的有些东西是继承自你的父亲。比如你父亲在北京有一套价值1000W的别墅,他作为不动产留给了你。你自己也通过自己的努力,积攒了300W的积蓄。这个时候,你急需要用钱,你改怎么办?首先你会看你自己有没有这个符合条件的积蓄,如果有,那么就用掉自己的积蓄,如果没有,那么就只能用父亲的房子作抵押给别人了。

先来个栗子:

function Person(){
}

Person.prototype.money = "1000W";

var person1 = new Person();
var person2 = new Person();

person1.money = "300W";
alert(person1.money); //"300W"----来自实例,是自己的钱
alert(person2.money); //"1000W"----来自原型,是父亲的钱

从上面的例子我们能发现,当在alert()中访问person1.name时,他就会去实例上面搜索一个名为name的属性。这个属性在person1实例中找到了,直接返回。同理在person2的实例中寻找name属性时,没有找到,这时就需要继续去原型寻找,这个时候找到了,于是返回原型上面的值。

如何判断属性值是来自实例还是原型?

在了解完上面的知识之后,有的人就会问了,那我在写代码的时候,如何去判断属性值是来自实例的,还是来自原型对象上面的?就是说我想知道那个钱,到底我自己的积蓄,还是用的我父亲的房子。这个时候我就可以借助方法hasOwnProperty(),当属性值是来自实例,也就是说是自己的钱,那么返回true,否则返回false

来段代码来看看:

function Person(){
}

Person.prototype.money = "1000W";

var person1 = new Person();
var person2 = new Person();

person1.money = "300W";
alert(person1.hasOwnProperty(money)); //true----来自实例,是自己的钱
alert(person2.hasOwnProperty(money)); //false----来自原型,是父亲的钱

更简单的原型语法

在看了前面栗子之后,你们可能注意到了,每添加一个属性和方法就要敲一遍Person.prototype。为了使代码简洁美观,最常见的做法是用一个包含所有属性的方法的对象字面量来重写整个原型对象。

来看个栗子:

function Person(){
}
Person.prototype = {
  name : "Lee",
  age : 20
}

但是上面的这种更简单的写法有几个问题:

1.上面的写法本质上完全重写了默认的prototype对象,因此使得原型中的constructor属性不再指向Person了。这种情况的时候如果constructor属性很重要,可以像下面这样特意将他设置回适当的值

function Person(){
}
Person.prototype = {
  constructor : Person,//设置回适当的值
  name : "Lee",
  age : 20
}

2.上面的写法在重写了默认的prototype对象,切断了现有原型与任何之前已经存在的对象实例之间的联系,他们引用的仍然是最初的原型

下面两个栗子来对比这个问题:

1)没有重写原型对象的栗子:

function Person(){
}
var lee = new Person();
Person.prototype.name = 'Lee';
alert(lee.name);//'Lee'

2)重写原型对象的栗子

function Person(){
}
var lee = new Person();
Person.prototype = {
  constructor : Person,//设置回适当的值
  name : "Lee",
  age : 20
}
alert(lee.name);//undefined

原型对象的问题

原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性也说得过去,毕竟(上面例子中所示),通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性就有问题了

举个栗子:

function Person(){
}

Person.prototype = {
  constructor : Person,//设置回适当的值
  name : "Lee",
  age : 20,
  friends : ["Wang","Tang"]
}
var p1 = new Person();
var p2 = new Person();

p1.friends.push("Zhang");

alert(p1.friends);//"Wang,Tang,Zhang"
alert(p2.friends);//"Wang,Tang,Zhang"
alert(p1.friends === p2.friends);//true

在上面的例子中,Person.prototype对象有一个名为friends的属性,该属性包含一个字符串数组。这个属性就是包含引用类型值属性。因为该属性是保存的对这个数组的引用,相当于就是说所有的实例都是公用的同一个这个数组,只要一个人对这个数组进行了修改,其他实例就都会改变。

shell脚本--判断系统

以下小脚本内容用于系统判断的示例

sysOS=`uname -s`
if [ $sysOS == "Darwin" ];then
	echo "I'm MacOS"
elif [ $sysOS == "Linux" ];then
	echo "I'm Linux"
else
	echo "Other OS: $sysOS"
fi

react学习笔记(一)

image

1. Jsx语法

在html中属性的值通过双引号(字符串数据)或者大括号(表达式)

//双引号
const a = <img src="1.jpg" />

//大括号
const x = "1.jpg"
const a = <img src={x} />

//有子元素的情况,都只能包含在同一个元素内,与vue语法保持一致
const a = (
	<div>
		<h1>标题</h1>
		<span>gogogo</span>
	</div>
)

注意:react对于jsx中的变量都会进行转义,以免xss攻击

2. 渲染DOM

通过reactDOM.render方法来渲染dom节点,并且react元素一旦创建就是不可变的,唯一的办法就是重新创建个新的元素然后重新通过ReacDOM.render去渲染,就是这么cool!😝😝😝。但是每次更新,不是统一将整个元素都更新,都只会修改更新了的元素

function tick(){
  const ele = (
  	<div>
  		<h1>现在的时间是:{new Date().toLocaleTimeString()}</h1>
  	</div>
  );
  ReactDOM.render(
  	ele,
  	document.getElementById('root')
  )
}
setInterval(tick,1000);

3. 函数组件开发

当用户看到用户自定义的组件的时候,就会将jsx的属性作为单个对象(props)传递给此组件

function Aiv(props){
  return <h1>hi,{props.name}</h1>
}
const e = <Aiv name = "haha" />;
ReactDOM.render(
	e,
	document.getElementById('root')
)

注意:自定义的组件的首字母必须为大写,否则不能识别

4. Props是只读的

react虽然是非常灵活的,但是有一条严格的规范:props是只读的,虽然也可以改变,但是不推荐。😝😝😝

比如:

//合格的形式
function Aiv (x, y){
	return x+y;
}
//不合格的形式,传参x被修改了
function Aiv (x, y){
  x = x + y;
}

5. 类组件开发

注意事项:

  1. 创建一个es6语法的class类,并且继承自React.Component
  2. 里面有一个render()方法,将原先函数组件的中的内容,如第3点函数组件例子的内容放到此方法中
  3. props用this.props替换
class Aiv extends React.Component{
  render(){
    return <h1>hi,{this.props.name}</h1>
  }
}

PS:相比于函数组件,类组件还多了本地状态和生命周期挂钩。👍👍👍

6. 增加本地状态state

  1. 将render中的this.props替换为this.state

    class Aiv extends React.Component{
      render(){
        return <h1>hi,{this.state.name}</h1>
      }
    }
  2. 在类组件中增加一个constructor方法来初始化this.state

    class Aiv extends React.Component{
      constructor(props){
        super(props);
        this.state = {name:'hy'};
        
      }
      render(){
        return <h1>hi,{this.state.name}</h1>
      }
    }

7. 增加生命周期方法

此系列方法是为了拓展ReacDOM的渲染的不可变性。使用此方法可以动态的去改变dom,让我们拭目以待。

class Aiv extends React.Component{
  constructor(props){
    super(props);
    this.state = {name:'hy'};
    this.i = 1;
  }
  componentDidMount() {
    this.timerID = setInterval(()=>this.setName(),1000);
  }
  componentWillUnmount() {
	clearInterval(this.timerID);
  }
  setName(){
    this.i ++;
    this.setState({name:"hy"+this.i})
  }
  render(){
    return <h1>hi,{this.state.name}</h1>
  }
}
ReactDOM.render(
  <Aiv />,
  document.getElementById('root')
); ;
  1. componentDidMount方法是在ReacDOM渲染dom节点之后执行
  2. componentWillUnmount方法是在该dom节点被删除的时候执行

8. 正确地使用state

1). 不能直接操作state属性

//wrong
this.state.name = "hy1";

//correct
this.setState({
  name: "hy1"
})

2). state更新可能是异步的

React为了性能,支持单次更新中可以批量执行多个setState,所以你不能在setState中使用this.state这种方式来操作state属性。因为this.state可能是之前的属性,还没来得及改变。如下面的例子对比:

//假设count = 1
this.setState({
  count:this.state.count+1
})
this.setState({
  count:this.state.count+1
})
//最后count = 2

但是,setState方法可以除了接收object对象,还可以接收function参数。传入function完美解决异步问题😎😎😎。使用方法:setState( function( prevState,[props] ){} )

this.setState(function(x){
  return {
    count: x.count+1
  }
})
this.setState(function(x){
  return {
    count: x.count+1
  }
})

操练以下

3). state属性可以只更新单个属性

this.state = {
	posts: [],
	comments: []
};

this.setState({
  posts: ['hy']
})

9. state作为参数传递

直接看例子:

<FormattedDate date={this.state.date} />

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

等价于下面:

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>

HTML标签的默认样式和CSS-reset

默认样式表

此样式表基于对当前UA实践的广泛研究,描述了所有HTML4元素的典型格式。鼓励开发人员在其实现中将其用作默认样式表。

以下样式表供大家去查看:

html, address,
blockquote,
body, dd, div,
dl, dt, fieldset, form,
frame, frameset,
h1, h2, h3, h4,
h5, h6, noframes,
ol, p, ul, center,
dir, hr, menu, pre   { display: block; unicode-bidi: embed }
li              { display: list-item }
head            { display: none }
table           { display: table }
tr              { display: table-row }
thead           { display: table-header-group }
tbody           { display: table-row-group }
tfoot           { display: table-footer-group }
col             { display: table-column }
colgroup        { display: table-column-group }
td, th          { display: table-cell }
caption         { display: table-caption }
th              { font-weight: bolder; text-align: center }
caption         { text-align: center }
body            { margin: 8px }
h1              { font-size: 2em; margin: .67em 0 }
h2              { font-size: 1.5em; margin: .75em 0 }
h3              { font-size: 1.17em; margin: .83em 0 }
h4, p,
blockquote, ul,
fieldset, form,
ol, dl, dir,
menu            { margin: 1.12em 0 }
h5              { font-size: .83em; margin: 1.5em 0 }
h6              { font-size: .75em; margin: 1.67em 0 }
h1, h2, h3, h4,
h5, h6, b,
strong          { font-weight: bolder }
blockquote      { margin-left: 40px; margin-right: 40px }
i, cite, em,
var, address    { font-style: italic }
pre, tt, code,
kbd, samp       { font-family: monospace }
pre             { white-space: pre }
button, textarea,
input, select   { display: inline-block }
big             { font-size: 1.17em }
small, sub, sup { font-size: .83em }
sub             { vertical-align: sub }
sup             { vertical-align: super }
table           { border-spacing: 2px; }
thead, tbody,
tfoot           { vertical-align: middle }
td, th, tr      { vertical-align: inherit }
s, strike, del  { text-decoration: line-through }
hr              { border: 1px inset }
ol, ul, dir,
menu, dd        { margin-left: 40px }
ol              { list-style-type: decimal }
ol ul, ul ol,
ul ul, ol ol    { margin-top: 0; margin-bottom: 0 }
u, ins          { text-decoration: underline }
br:before       { content: "\A"; white-space: pre-line }
center          { text-align: center }
:link, :visited { text-decoration: underline }
:focus          { outline: thin dotted invert }

/* Begin bidirectionality settings (do not change) */
BDO[DIR="ltr"]  { direction: ltr; unicode-bidi: bidi-override }
BDO[DIR="rtl"]  { direction: rtl; unicode-bidi: bidi-override }

*[DIR="ltr"]    { direction: ltr; unicode-bidi: embed }
*[DIR="rtl"]    { direction: rtl; unicode-bidi: embed }

@media print {
  h1            { page-break-before: always }
  h1, h2, h3,
  h4, h5, h6    { page-break-after: avoid }
  ul, ol, dl    { page-break-before: avoid }
}

CSS-Reset

reset 的目的,是将所有的浏览器的自带样式重置掉,这样更易于保持各浏览器渲染的一致性。

这里提供链接给小伙伴去了解各类人士的cssreset文,里面包含YUI等等——cssreset

国内的大牛们也很多自己去制定属于自己的CSS Rest。但是在玉伯写完第一版之后,在总结文章的结尾还是千叮咛,万嘱咐说:

请记住:永远不存在万能解决方案,永远没有银弹。 因此我的建议和 Eric 是一样的:请根据具体需求,适量裁剪和修改后再使用。

替代品 Normalize.css

reset 的目的,是将所有的浏览器的自带样式重置掉,这样更易于保持各浏览器渲染的一致性。

而normalize 的理念则是尽量保留浏览器的默认样式,不进行太多的重置。——normalize

优势对比

前面讲到CSS Reset的核心作用就是清零,而且过于暴力;那么作为后者Normalize.css,到底有什么优势可以完全取代前者呢?

1.Normalize.css 保护了有价值的默认值
Reset通过为几乎所有的元素施加默认样式,强行使得元素有相同的视觉效果。 相比之下,Normalize.css保持了许多默认的浏览器样式。 这就意味着你不用再为所有公共的排版元素重新设置样式。 当一个元素在不同的浏览器中有不同的默认值时,Normalize.css会力求让这些样式保持一致并尽可能与现代标准相符合。

2.Normalize.css 修复了浏览器的bug
它修复了常见的桌面端和移动端浏览器的bug。这往往超出了Reset所能做到的范畴。 关于这一点,Normalize.css修复的问题包含了HTML5元素的显示设置、预格式化文字的font-size问题、在IE9中SVG的溢出、许多出现在各浏览器和操作系统中的与表单相关的bug。

3.Normalize.css 修复了浏览器的bug
使用Reset最让人困扰的地方莫过于在浏览器调试工具中大段大段的继承链。在Normalize.css中就不会有这样的问题,因为在我们的准则中对多选择器的使用时非常谨慎的,我们仅会有目的地对目标元素设置样式。

4.Normalize.css 是模块化的
这个项目已经被拆分为多个相关却又独立的部分,这使得你能够很容易也很清楚地知道哪些元素被设置了特定的值。因此这能让你自己选择性地移除掉某些永远不会用到部分(比如表单的一般化)。

5.Normalize.css 拥有详细的文档
Normalize.css的代码基于详细而全面的跨浏览器研究与测试。这个文件中拥有详细的代码说明并在Github Wiki中有进一步的说明。这意味着你可以找到每一行代码具体完成了什么工作、为什么要写这句代码、浏览器之间的差异,并且你可以更容易地进行自己的测试。

这个项目的目标是帮助人们了解浏览器默认是如何渲染元素的,同时也让人们很容易地明白如何改进浏览器渲染。

总结

还是要根据自身网站系统的情况来考虑之后,自己去修改出一份最适合自己的css-reset。

最后还是引用张鑫旭的一句话来总结下:

最少的CSS代码,最少的渲染,最少的重置就是最好的CSS样式代码,这反应了您的CSS层次。说句不好听的话,CSS reset是用来让那些CSS菜鸟,对CSS不太了解的人准备的。

参考地址

关于CSS Reset 那些事

CSS reset的重新审视

cssreset

Normalize.css

CSS盒模型

盒子的属性

文档的每个元素被构造成文档布局内的一个矩形盒子,盒子每层的大小都可以使用一些特定的CSS属性调整。相关属性如下:

img

  • width和height

    width和height设置内容盒(content box)盒子的宽度和高度。内容盒是盒子内容显示的区域 — 包括盒子内的文本内容,以及表示嵌套子元素的其它盒子。注意: 还有其他属性可以更巧妙地处理内容的大小 — 设置大小约束而不是绝对的大小。这些属性包括min-widthmax-widthmin-heightmax-height

  • padding

    padding表示一个 CSS 盒子的内边距 — 这一层位于内容盒的外边缘与边框的内边缘之间。该层的大小可以通过简写属性padding 一次设置所有四个边,或用 padding-toppadding-rightpadding-bottompadding-left 属性一次设置一个边。

  • border

    CSS 盒的边框(border)是一个很明显的层,位于内边距的外边缘以及外边距的内边缘之间。边框的默认大小为 0 — 从而让它不可见 — 不过我们可以设置边框的厚度、风格和颜色让它出现。 border 简写属性可以让我们一次设置所有四个边,例如 border: 1px solid black。This can be broken down into numerous different longhand properties for more specific styling needs:

    border-topborder-rightborder-bottomborder-left:设置厚度,款式和边境一侧的颜色。border-widthborder-styleborder-color:设置仅厚,样式或颜色独立,但边界的所有四个侧面。您还可以设置单独的边框的单面的三个属性之一,使用border-top-widthborder-top-styleborder-top-color,等。

  • margin

    外边距(margin)代表 CSS 盒子周围的外部区域,在布局中推开其它 CSS 盒子。其表现与与 padding 很相似;简写属性为 margin,单个属性分别为 margin-topmargin-rightmargin-bottommargin-left

更改默认的盒模型

**box-sizing **属性用于更改用于计算元素宽度和高度的默认的 CSS 盒子模型。可以使用此属性来模拟不正确支持CSS盒子模型规范的浏览器的行为。

  • content-box

    默认值,标准盒子模型。width和height只包括内容的宽和高, 不包括边框(border),内边距(padding),外边距(margin)。

    **注意: 内边距, 边框 & 外边距 都在这个盒子的外部。 **

    比如. 如果 .box {width: 350px}; 而且 {border: 10px solid black;} 那么在浏览器中的渲染的实际宽度将是370px;

    尺寸计算公式:width = 内容的宽度,height = 内容的高度。

  • border-box

    widthheight 属性包括内容,内边距和边框,但不包括外边距。

    这是当文档处于 Quirks模式 时Internet Explorer使用的盒模型。padding和border将属于盒子的一部分

    例如, .box {width: 350px; border: 10px solid black;} 导致在浏览器中呈现的宽度为350px的盒子。这个例子虽然没有设置高度,但是因为设置了border,所以高度自动就成了20px。

    尺寸计算公式:width = border + padding + 内容的 width*,height = border + padding + 内容的 height

利用正则表达式进行字符串替换(replace方法)

语法

str.replace(regexp|substr, newSubStr|function)

参数

  • regexp (pattern)

    一个RegExp对象或者其字面量。该正则所匹配的内容会被第二个参数的返回值替换掉。

  • substr (pattern)

    一个要被 newSubStr 替换的{{jsxref("String","字符串")}}。其被视为一整个字符串,而不是一个正则表达式。仅仅是第一个匹配会被替换。

  • newSubStr (replacement)

    用于替换掉第一个参数在原字符串中的匹配部分的 {{jsxref("String", "字符串")}}

  • function (replacement)

    一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。

返回值

一个部分或全部匹配由替代模式所取代的新的字符串。

描述

上面语法的含义是说:一共两个参数,但是两个参数可以分别传输不同的类型的值。

可能你看上面BB半天了也没看明白,没关系,我们直接来上代码:

用法

  1. 基本用法

    var x = "abcda";
    //两个参数都是字符串
    var y = x.replace('a','x');//'xbcda'
  2. 进阶用法

    var x = "abcda";
    //前面参数使用正则,后面使用字符串
    var y = x.replace(/a/g,'x');//'xbcdx'
  3. 复杂用法

    var x = 'abcda';
    //前面参数使用正则,后面使用字符串
    var y = x.replace(/a/g,function(match){
      return match.toUpperCase();
    });//'AbcdA'

应用场景

这里只讲复杂用法中的应用场景实际使用,比如有个需求:你需要html文件中的标签之间的所有

标签中的字符a替换为字符b。当然如果是正则大神的话就可以跳过这里了,主要以下方式比较容易理解,更适合正则新手。

解决办法:

var allData = "<body>"+'\r\n'+
    			"<div>aaa</div>"+'\r\n'+
    			"<p>aaa</p>"+'\r\n'+
    		"</body>";
allData = allData.replace(/\<body\>([\s\S]*?)\<\/body\>/g, function(match) {
        return match.replace(/\<p\>(.*?)\<\/p\>/g, function(match1) {
            return match1.replace(/a/g, "b")
        })
    });

PS:在进行全局的搜索替换时,正则表达式需包含 g 标志。

如果对以上有什么疑问,可以在评论区发表,方便大家进行探讨

Git--将已有的项目添加到github

在本地仓库陆续执行以下命令:

  1. git init
  2. git add .
  3. git commit -m ‘提交说明’
  4. git remote add origin 远程仓库地址
  5. git pull origin master --allow-unrelated-histories
  6. git branch --set-upstream-to=origin/master master
  7. git push

顺序执行完即可正常操作

Zen Coding--如何快速地书写HTML代码

描述

在本文中我们将展示一种新的使用仿CSS选择器的语法来快速开发HTML的方法。

我使用的是atom编辑器——由 Github 打造的编程开发利器,他自带这个解析功能。当然其他的如sublime,webstorm等都会自带这个功能,或者使用相关的插件即可。

你在写HTML代码(包括所有标签、属性、引用、大括号等)上花费多少时间?如果你的编辑器有代码提示功能,你编写的时候就会容易些,但即便如此你还是要手动敲入很多代码。

比如,你这么写,按下tab键:

div#content>h1+p 

然后就看到了这样的输出:

<div id="content">  
<h1></h1>  
<p></p>  
</div> 

用法

这里是一个支持的属性和操作符的列表:

  • E

    元素名称(div, p等);

  • E#id
    使用id的元素(div#content, p#intro, span#error);

  • E.class
    使用类的元素(div.header, p.error.critial). 你也可以联合使用class和idID: div#content.column.width;

  • E>N
    子代元素(div>p, div#footer>p>span);

  • E+N
    兄弟元素(h1+p, div#header+div#content+div#footer);

  • E*N
    元素倍增(ul#nav>li*5>a);

  • E$*N

    条目编号 (ul#nav>li.item-$*5);

示例

这里就针对于倍增和条目编号来举例子吧。

元素倍增

比如你写个li*4>a,就会生成以下HTML代码:

<li><a href=""></a></li>  
<li><a href=""></a></li>  
<li><a href=""></a></li>  
<li><a href=""></a></li>  

条目编号

假设你想生成class为item1item2item3的3个<div>元素。你可以写成这样的缩写,div.item$*3:

<div class="item1"></div>  
<div class="item2"></div>  
<div class="item3"></div>

简单吧,赶紧打开你的编辑器操练起来吧!

Html5语义化标签

什么是语义化?

简单说来就是让机器可以读懂内容。

语义化的优点:

  • 搜索引擎的爬虫依赖于标记来确定上下文和各个关键字的权重,利于 SEO

  • 去掉或样式丢失的时候能让页面呈现清晰的结构。

  • 使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。

PS:一般的爬虫框架流程为----从互联网海量页面中先抓取一些高质量页面,抽取其中所包含的url,将这些URL放入待抓取队列中,爬虫依次读取该队列中的url,通过DNS解析,将这些url转化成对应网站的IP地址,网页下载器则通过IP地址下载页面所有内容。

html5语义化标签

123

header元素

header 元素代表“网页”或“section”的页眉。
通常包含h1-h6元素或hgroup,作为整个页面或者一个内容块的标题。也可以包裹一节的目录部分,一个搜索框,一个nav,或者任何相关logo。

整个页面没有限制header元素的个数,可以拥有多个,可以为每个内容块增加一个header元素

<header>
	<hgroup>
  		<h1>xxx</h1>
  	</hgroup>
	<nav></nav>
</header>

footer元素

footer元素代表“网页”或“section”的页脚,通常含有该节的一些基本信息,譬如:作者,相关文档链接,版权资料。如果footer元素包含了整个节,那么它们就代表附录,索引,提拔,许可协议,标签,类别等一些其他类似信息。

<footer>
	Copyright © 2017 ...
</footer>

nav元素

nav元素代表页面的导航链接区域,用在整个页面主要导航部分上,不合适就不要用nav元素

<nav>
	<ul>
      	<li>首页</li>
      	<li>xxx</li>
      	...
  	</ul>
</nav>

section元素

section元素代表文档中的“节”或“段”,“段”可以是指一篇文章里按照主题的分段;“节”可以是指一个页面里的分组。

<section>
    <h1>section是啥?</h1>
    <article>
        <h2>关于section</h1>
        <p>section的介绍</p>
        <section>
            <h3>关于其他</h3>
            <p>关于其他section的介绍</p>
        </section>
    </article>
</section>

article元素

article代表一个在文档,页面或者网站中自成一体的内容,其目的是为了让开发者独立开发或重用。譬如论坛的帖子,博客上的文章,一篇用户的评论,一个互动的widget小工具。并不是说只有是文章内容才能使用,而是说只要是自成一体的内容就可以用这个标签(特殊的section)

<article>
    <h1>一篇文章</h1>
    <p>文章内容..</p>
    <footer>
        <p><small>版权:html5jscss网所属,作者:小北</small></p>
    </footer>
</article>

aside元素

aside元素被包含在article元素中作为主要内容的附属信息部分,其中的内容可以是与当前文章有关的相关资料、标签、名次解释等。(特殊的section)

<article>
    <p>内容</p>
    <aside>
        <h1>作者简介</h1>
        <p>小北,前端一枚</p>
    </aside>
</article>

使用注意:

  • 自身独立的情况下:用article——是一个独立的内容
  • 是相关内容:用section----它是一个部分,可以是一个大部分,也可以是一个小部分
  • 没有语义的:用div

参考地址:

搜索引擎和如何SEO

html5语义化标签兼容方案

其他语义化标签

浏览器的解析原理

浏览器工作流程

先来个流程图,让大家心里有个底:

webkitflow

从上图,我们能看到这几点:

  1. 浏览器会解析
    • HTML生成DOM Tree
    • CSS生成Style Rules
  2. 解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Render Tree(渲染树)。注意:Render Tree 渲染树并不等于DOM树,因为head元素和一些display:none的元素没有放在渲染树中

浏览器解析

有下面的HTML示例如下:

<html> 
	<body> 
		<div class =“err” id =“div1”> 
			<p> 
              这是一个
              <span class =“big”>大错误</span> 
              这也是一个
              <span class =“big”>非常大的错误</span>错误
        	</p> 
		</div> 
		<div class =“err” id =“div2”>另一个错误</div> 
    </body> 
</html>

然后我们的CSS文档是这样的:

/*1.*/ div {margin:5px; colorblack} 
/*2.*/ .err {colorred} 
/*3.*/ .big {margin-top:3px} 
/*4.*/ div span {margin-bottom:4px} 
/*5.*/div1 {color:蓝色} 
/*6.*/ #div2 {colorgreen}

于是我们的CSS Rule Tree是这样:

image027

注意:CSS匹配HTML元素是一个相当复杂和有性能问题的事情。所以,你就会在N多地方看到很多人都告诉你,DOM树要小,CSS尽量用id和class,千万不要过渡层叠下去,……

通过这两个树,我们可以得到一个叫Style Context Tree,也就是下面这样(把CSS Rule结点Attach到DOM Tree上):

image029

这个时候就有必要说下这个CSS选择器特性了

选择器特性

CSS选择器由CSS2规范定义如下:

  • 如果声明来自是“样式”属性,则计数1,否(= a)
  • 计数选择器中的ID属性数(= b)
  • 计数选择器中其他属性和伪类的数量(= c)
  • 计数选择器中元素名称和伪元素的数量(= d)

连接四个数字abcd(在具有大基数的数字系统中)具有特异性。

这个四个数字保持的优先级是:a>b>c>d

您需要使用的数字基数由您在其中一个类别中的最高数量定义。
例如,如果a = 14,您可以使用十六进制基数。在不太可能的情况下,您将需要一个17位数的基数。后来的情况可能会发生在这样的选择器:html body div div p ...(你的选择器中的17个标签不太可能)。

一些例子:

* {} / * a = 0 b = 0 c = 0 d = 0  - > specificity = 0,0,0,0 * / 
li {} / * a = 0 b = 0 c = 0 d = 1  - >specificity= 0,0,0,1 * / 
li:first-line {} / * a = 0 b = 0 c = 0 d = 2  - > specificity = 0,0,0,2 * / 
ul li {} / * a = 0 b = 0 c = 0 d = 2  - > specificity = 0,0,0,2 * / 
ul ol + li {} / * a = 0 b = 0 c = 0 d = 3  - > specificity = 0 ,0,0,3 * / 
h1 + * [rel = up] {} / * a = 0 b = 0 c = 1 d = 1  - > specificity = 0,0,1,1 * / 
ul ol li.red {} / * a = 0 b = 0 c = 1 d = 3  - > specificity = 0,0,1,3 * / 
li.red.level {} / * a = 0 b = 0 c = 2 d = 1 - > specificity = 0,0,2,1 * / 
#test {} / * a = 0 b = 1 c = 0 d = 0  - > specificity = 0,1,0,0 * / 
style =“”/ * a = 1 b = 0 c = 0 d = 0  - > specificity = 1,0,0,0 * /

(译)最全的javaScript中对象深度拷贝指南

原文地址

我在JavaScript中如何拷贝一个对象?这是一个简单的问题,但是答案确不是很简单。

Did you ever wanted to create a deep copy of an object in JavaScript? There is a way, but you are not gonna like it...

I feel like we need something better 🤔 pic.twitter.com/IDazhB8BKJ

— Surma (@DasSurma) 2018年1月22日
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

引用调用

JavaScript通过引用来传递所有的值。如果你不知道这是什么意思,下面有个例子👇:

function mutate(obj) {
  obj.a = true;
}

const obj = {a: false};
mutate(obj)
console.log(obj.a); // prints true

mutate方法改变了作为参数传递进来的这个对象。在值调用环境中,这个函数式传递的这个值,所以相关于这个函数是执行了一个拷贝。这个函数使这个对象对外是不可见的。但是在像js的这种引用调用的环境,将会得到这个真实的对象。所以最后控制台输出的为true

不过,你想要保持你的原始的对象,其他函数只是创建了这个对象的拷贝。

在下面就介绍几种深度拷贝的方式

JSON.parse

第一种最古老的方式就是通过将对象转换为JSON字符串格式,然后将其转换为对象。

let obj = { name : "huyue" };
let copy = JSON.parse(JSON.stringify(obj));
obj.name = 'hy';
console.log(copy);//'huyue'

但是这种方式有些问题

问题一:当对象中出现循环引用的时候会报错。尽管你可能认为你不会如此使用,但是那些还是会很容易发生。比如当你构建了树状类型的数据机构的时候,其中一个节点引用了父级的某个节点,这样就出现了这种场景。

const x = {};
const y = {x};
x.y = y; // Cycle: x.y.x.y.x.y.x.y.x...
const copy = JSON.parse(JSON.stringify(x)); // throws!

问题二:这种方式只支持基础类型,像MapSetRegExpDateArrayBuffer,函数对象等都会在序列化的时候弄丢

var source = { name:function(){console.log(1);}, child:{ name:"child" } } 
var target = JSON.parse(JSON.stringify(source));
console.log(target.name); //undefined

注:JSON对象是ES5中引入的新的类型(支持的浏览器为IE8+),浏览器支持情况

结构化克隆

结构化克隆是一个现有算法,它是被用来把一个领域的值传递到另一个。比如,你调用postMessage去发送一个消息给另一个窗口或WebWorker。结构化很好的地方就是他能处理循环对象,并且支持多种内置类型

MessageChannel

我们通过MessageChannel创建一个新的消息通道,并通过它的两个MessagePort属性来发送数据和获取数据。我们接受到的这条信息就是会包含原始数据的结构化克隆对象。但是这种方式是异步情况,所以下面例子使用的async awit实现了的,也可参见在线地址

function structuralClone(obj) {
  return new Promise(resolve => {
    const {port1, port2} = new MessageChannel();
    port2.onmessage = ev => resolve(ev.data);
    port1.postMessage(obj);
  });
}

const obj = /* ... */;
const clone = await structuralClone(obj);

注:浏览器支持IE10+,浏览器支持力度情况

History API

如果你曾经使用过history.pushState()去构建一个SPA(单页应用),你应该会知道能提供一个状态对象去保存这URL。这个状态对象就是结构化克隆,并且还是同步的。我们一定要小心,避免在使用这个状态对象的时候去混淆任何程序逻辑,所以我们需要在我们克隆了之后去恢复这个原始的状态对象。为了防止发生任何事件,请使用history.replaceState()而不是history.pushState()。replaceState和pushState区别详情

function structuralClone(obj) {
  const oldState = history.state;
  history.replaceState(obj, document.title);
  const copy = history.state;
  history.replaceState(oldState, document.title);//就是为了恢复原始状态对象,避免干扰
  return copy;
}

const obj = /* ... */;
const clone = structuralClone(obj);

为了复制一个对象,使用浏览器的引擎感觉有些笨拙。不过你还是可以这么做,有些事情还是得注意,因为Safari浏览器会限制30秒内调用relaceState的次数上限为100次

注:浏览器支持IE10+,浏览器支持力度情况

Notification API

这种方式由Jeremy Banks建议,通知接口用于向用户配置和显示桌面通知,这个消息通知的api有一个与它们相关的数据对象被克隆。看到这,可能有的人表示有点不是很明白,那么可以点击在线示例

function structuralClone(obj) {
  return new Notification('', {data: obj, silent: true}).data;
}

const obj = /* ... */;
const clone = structuralClone(obj);

它基本触犯了浏览器内的权限机制,所以怀疑这个可能会非常慢。出于某种原因,Safari浏览器总是返回undefined。可以使用在线示例

注:浏览器不支持IE,浏览器支持力度情况

性能测试

对上面几种方式进行性能测试看哪种方式性能最高。刚开始尝试时,我拿一个小JSON对象,并通过这些克隆对象一千次的不同方式来进行测试。幸运的是, Mathias Bynens告诉我在给一个对象增加属性的时候V8是有缓存。为了确保不走缓存,所以我写了一个[函数](a function that generates objects of given depth and width using random key names),使用随机键名称生成给定深度和宽度的对象,并重新运行测试示例

图表统计

image
image
image

总结

  • 如果你不会使用循环对象并且不会使用内置类型,那么还是推荐使用JSON.parse。并且浏览器兼容性还更好(ie8+)
  • 如果在考虑性能和浏览器兼容,MessageChannel是最好的选择。(ie10+)

rollup的使用说明

特别声明:如果你的工作内容是基于es2015(也就是es6),并且不需要代码分割,也不需要[模块热替换(HMR)][https://webpack.js.org/concepts/hot-module-replacement/],那么你可以很愉快的使用rollup进行开发了。否则,你可以绕行webpack了。

优势(与webpack相比)

  • 代码的内容格式:编译运行出来的内容,人能看,并且能调试。如果你没办法理解我说的话,可以去看看webpack打包出来的代码
  • 命令行的角度:比webpack更加的人性化,有什么问题或者警告都很详细的描述出来,并且准确的提供问题所在文件的位置,方便查找问题
  • 如果是引入第三方的js,一旦import进来就会加载进入入口文件中,但如果不是第三方的js,要引入进来之后进行export操作或者执行,才会被解析到入口文件中

所用插件

  • "babel-plugin-external-helpers": 这个模块是在.babelrc文件中体现,目的是让babel转义出来的帮助性代码只在该文件的头部出现一次,而不会再每个引入的模块中加入
  • "babel-preset-latest": 这个模块也是在.babelrc文件中体现,目的是让babel转义的操作移至的最后,等rollup编译代码之后,否则会出错
  • "rollup-plugin-babel": babel转义
  • "rollup-plugin-node-resolve": 将import的代码的代码和自己写的代码打包打在一起
  • "rollup-plugin-uglify": 压缩代码

比较好用的插件

  • rollup-plugin-multi-entry 多入口
  • rollup-plugin-multidest 多出口
  • gulp-rollup-each 基于gulp的rollup转译的多入口到多出口

工具使用问题总结

  • 当format改变为umd和iife的时候,如果你的入口文件中有export,那么就需要添加moduleName这个参数,为它产出的文件整体加个变量
    问题解决地址:rollup/rollup#1157

备注

rollup已经原生支持多入口多出口,可以查看英文文档

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.