Git Product home page Git Product logo

blog's Introduction

云峰profile 👋

  • 🔭 I’m currently working on BAT
  • 🌱 I’m currently learning Javascript
  • 💻 I’m familiar with front-end monitoring, nodejs high concurrency service, rich text editor
  • 📫 How to reach me: [email protected] or [email protected]

blog's People

Contributors

ihtml5 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

blog's Issues

前端性能优化

前端性能优化的要点

1. 前端静态资源合并

Why

通过前端资源打包合并,减少页面的http请求,提升页面的加载速度

How to do

使用Gulp,Webpack等前端打包工具,对资源进行打包合并

Links

  1. react和webpack小人书
  2. Gulp 入门指南
  3. Yahoo前端性能优化34条军规

2.table组件,form表单页面样式交互统一

Why

后端在开发页面的时候,未能按照前端指定的规范编写页面

How to do

前端以测试的身份,逐一检查页面的样式和交互,使其统一

Links

3.iframe性能优化

Why

在npc项目中,通过使用iframe来快速实现单页面应用的效果,但是随着iframe的大量使用,页面的性能越来越低,急需优化。

How to do

  1. 调研iframe的渲染原理,更加明晰其如何影响性能 2. 查找目前已有的国内外关于iframe性能调优的解决方案

Links

  1. Iframes, onload, and document.domain
  2. iframe异步加载技术及性能
  3. Using Iframes Sparingly
  4. Iframe loading techniques and performance
  5. Modern iframe programing
  6. Using Iframes to Address Third-Party Script Issues and Boost Performance
  7. Non-onload-blocking async JS

4.交互优化

Why

页面中有许多页面交互存在着不合理,使用不方便等问题

How to do

通过修改页面显示,交互逻辑修改等优化交互

Links

5.js代码逻辑调优

Why

后端在编写前端js代码时,会出现js代码编写不规范,代码逻辑不严谨等问题

How to do

类似于2中修改table和form,逐一检查,修改完善

Links

兼容ie8项目前端技术选型

一.整体策略

模块化+工程化

二.框架选型及其场景

  1. require.js

模块加载器,相应规范amd
版本:2.3.2

  1. jquery

基础库
版本号:1.9.2

  1. bootstrap3/amazeui 2.7.x(ie8有限支持)

样式优化
版本号: 2.x.x/3.x.x

  1. bootstrap-table

数据表格包括增,删,改,查,导出,过滤,切换视图等
版本号:所有版本均支持ie8以上
常见问题:export 插件有兼容问题

  1. bootstrap-multiselect

多项选择框
版本号:所有版本均支持ie8以上
常见问题:option.class写法有问题需改成option['class']

  1. ztree

树形菜单
版本号:所有版本均支持ie8以上

三.目前开发存在的问题

  1. 没有形成通用模块及其使用规范

解决办法:

  • 目前js文件加载多,依赖不清楚,使用require.js清晰依赖,提高加载速度
  • 选择合适的ui库,目前自己编写
  • 根据业务编写通用ui元素比如导航,面包屑,菜单等;
  • 根据项目类型,选择不同的目录结构
  1. 针对业务场景尽可能多的封装前端操作功能,简化后端使用成本

解决办法:

  • 进一步封装bootstrap-table的操作接口,简化使用
  • 进一步封装bootstrap-multiselect的操作接口,简化使用
  • 进一步封装ztree的操作接口,简化使用。
  1. 在前端建立服务层

解决办法:
抽象前台与后台的请求接口,独立成服务层

相关脚手架

require-jquery-bootstrap

javascript如何实现面向对象编程

Es5

一. new命令背后发生了什么

1. 原理:

  • 创建一个空对象,作为将要返回的对象实例
  • 将这个空对象的原型,执行构造函数的prototype属性
  • 将这个空对象赋值给函数内部的this关键字
  • 开始执行构造函数内部的代码

2. 相关代码

Object.create = Object.create || function(prototype) {
    var F = function () {};
    F.prototype = prototype;
    return new F();
}
function _new () {
    var args = [].slice.call(arguments);
    var constructor = args.shift();
    var context = Object.create(constructor.prototype);
    var result = constructor.apply(context,args);
    return typeof result === 'object' && result !=null ? result : context;
}

3.如何防止因没有使用new命令,而发生意外

var Tu = function(obj) {
    if ( this instanceof obj) { return obj }
   if (!(this instanceof obj) ) { return new Tu(obj);}
   // 构造函数执行一些动作
};

redux源码解读

一.目录分析

1.src

项目的源代码,包括以下几个文件:

  • index.js

    整个redux框架的入口文件
    作用: 导出redux的几大函数包括createStore,bindActionCreators,combineReducers,compose,applyMiddleware

  • createStore.js

    创建应用唯一的state树

  • bindActionCreators.js

    工具类函数
    作用: 方便开发者将dispatch和actioncreator当props绑定到组件中

  • combineReducers.js

    将多个reducer,合并成一个reducer,传入到createStore函数中

  • compose.js

    将多个函数组合执行

  • applyMiddleware

    工具类函数
    作用: 将中间件如redux-thunk应用到createStore函数上

  • util/warning.js

    自定义的错误信息提示函数

2.docs

redux的文档.
官方网站:www.redux.js.org
中文翻译:cn.redux.js.org

3.build

构建redux所需要的一些文件

4.examples

redux的使用案例,从简单的原生counter到复杂到真实场景的应用,都提供了案例参考

5.test

测试文件目录

6.node_modules

redux源码所依赖的node包


二.源码分析

1.src/index.js

  • 关键词

源代码使用了es6语法,使用import关键词从文件中导出模块

  • 源码解读
    export {
        createStore,
        compose,
        warning,
        combineReducers,
        bindActionCreators
    }

2.src/utils/warning.js

  • 关键词

    1. export default
    2. javascript中异常处理
    3. javascript中错误处理
    4. 阮一峰谈javascript错误处理
  • 源码解读

    1.判定console.error是否存在且可用

        // 导出warning函数
        export default function warning(message) {
            // 判断console.error函数是否存在且可用
            if (typeof console !== 'undefined' && typeof console.error == 'function') {
                console.error(message);
            }
        }

    2.捕获异常并处理

          try {
              // 抛出异常
            throw new Error(Message)
          } catch(e) {
            // 捕获异常
         }

3.src/combineReducer.js

  • 关键词

    闭包

  • 源码解读

  1. 前置部分

      var  reducers = { reducer1:reducer, reducer2: reducer}
  2. 辅助对象导出部分:

     import { ActionTypes } from './createStore';
     import isPlainObject from 'lodash/isPlainObject';
     import warning from './utils/warning'
  3. 辅助函数定义部分

    getUndefinedStateErrorMsg(key,action)

    • 何时用: 当reducer(previousState,action) === undefined时,调用这个函数,给予用户一定警告。
    • 返回结果: 告诉用户你当前没有给reducer一个初始值,你必须显式的指明初始值

    getUnexpectedStateShapeWarningMessage(inputState,reducers, action)

    • 何时用: 检测输入的inputState是否和reducers对应
    • 原理: 首先检测inputState必须是个对象,reducers是否有效(检测reducers对应的key数组是否长度大于1),inputState中的key是否完全包含在reducers的key中,如果以上几种情况有任一一种不满足情况,函数都会停止执行,并返回相应的错误信息提示.

    assertReducerSanity(reducers)

    • 何时用: 判断输入reducers对象中给定reducer是否有效
    • 原理: 将reducers对象中的reducer进行分别测试,如下:
      javascript var initialState = reducer(undefined,{type: ActionTypes.INIT}); var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.'); typeof reducer(undefined, { type } === 'undefined') /* 如果给定的reducer在初始化或者给定的action的type是一个'@@redux/PROBE_UNKNOWN_ACTION'开头的随机类型时,返回值为undefined,则 直接扔出异常,证明其传入的reducer不符合要求,需要检查核对,重新修改。 */
  4. 核心 combineReducers函数详解

    • 初步筛选

      终于到了分析combineReducers的时候了,该函数最终返回回来一个rootreducer,形式如 rootReducer(state= {},action);在返回这个根reducers函数前,进行了两部分的工作,
      将参数reducers进行过滤,初步筛选出类型为function的reducer并存入finalReducers对象中,相关代码如下:

      var reducerKeys = Object.keys(reducers)
      var finalReducers = {}
      for (var i = 0; i < reducerKeys.length; i++) {
      var key = reducerKeys[i]

        if (process.env.NODE_ENV !== 'production') {
            // 开发环境下,判断reducer是否未定义
            if (typeof reducers[key] === 'undefined') {
                warning(`No reducer provided for key "${key}"`)
            }
        }
        // 当reducer类型为function的时候,才存入finalReducers对象中
        if (typeof reducers[key] === 'function') {
            finalReducers[key] = reducers[key]
        }
      

      }

    • 传入的reducer有效性验证

        if (process.env.NODE_ENV !== 'production') {
            // 如果是开发环境,检测是否传入了不恰当的key
            var unexpectedKeyCache = {}
        }
        /*
           对初步筛选出来的finalReducers进行有效性检测,除了要求reducer是函数外,
        还需满足assertReducerSanity,否则抛出异常,程序终止
        */
        var sanityError
        try {
            assertReducerSanity(finalReducers)
        } catch (e) {
            sanityError = e
        }
    • 返回根reducer

        return function combination(state = {}, action) {
            // reducers中有reducer无效,程序就会抛出异常
            if (sanityError) {
                throw sanityError
            }
      
            if (process.env.NODE_ENV !== 'production') {
                // 开发环境下,检测给定的state,finalReducers是否对应,如果不对应,就会抛出异常
                var warningMessage = getUnexpectedStateShapeWarningMessage(
                       state, finalReducers, action, unexpectedKeyCache)
                if (warningMessage) {
                    warning(warningMessage)
                }
            }
            var hasChanged = false
            var nextState = {}
            // finalReducers如何合成根state
            for (var i = 0; i < finalReducerKeys.length; i++) {
                var key = finalReducerKeys[i]
                var reducer = finalReducers[key]
                var previousStateForKey = state[key]
                var nextStateForKey = reducer(previousStateForKey, action)
                if (typeof nextStateForKey === 'undefined') {
                    var errorMessage = getUndefinedStateErrorMessage(key, action)
                    throw new Error(errorMessage)
                }
                nextState[key] = nextStateForKey
                hasChanged = hasChanged || nextStateForKey !== previousStateForKey
            }
            return hasChanged ? nextState : state
        }

    相关链接

    1. redux offical site
    2. Redux系列01:从一个简单例子了解action、store、reducer
    3. Redux系列02:一个炒鸡简单的react+redux例子
    4. Redux 在实践中的一些问题及思考
    5. React和Redux的连接react-redux
    6. 对Redux实践中数据请求的一些想法
    7. Redux系列x:源码解析

无阻塞加载js

背景

如果把脚本写死在页面中,当页面加载脚本时,会直接下载并解析脚本内容,页面停止渲染。这种情况对于大型网站来说,其对性能影响很大。而动态脚本加载可以无阻塞加载js,不影响网站性能。

无阻塞加载js三种方法

  1. 设置defer属性
<script charset=‘utf-8 src='a.js'></script>
  • 浏览器兼容性:
    ie4+,opera浏览器不支持
  • 加载时机
    立即加载
  • 执行时机::
    在dom加载完成之前即DOMContentLoaded事件触发之前执行,按照他们出现在文档中顺序加载,但是在ie浏览器不一定
  1. 设置async属性
<script charset=‘utf-8 src='a.js'></script>
  • 浏览器兼容性:
    ie9+,opera浏览器不支持
  • 加载时机
    立即加载
  • 执行时机::
    在脚本load事件即将发生之前执行
  1. 动态脚本
 (function(d,s,id) {
    var js = document.createElement(s);
    var tjs = document.getElementsByTag(s)[0];
    js.id = id;
    js.src = "//connect.facebook.net/en_US/all.js#xfbml=1"
   if (document.getElementById(id)) {
     return;  
   }
   tjs.parentNode.insertBefore(js,tjs);
   
})(document,'script','ihtml5')
/*
loadScript
*/
function loadScript(src,func) {
   var dscript = document.createElement('script');
   if (dscript.onreadystatechange) { 
      if (dscript.readyState === 'loaded' || dscript.readyState === 'complete') {
          dscript.onreadystatechange = null;
          func();
      }
  } else {
      dscript.onload = func;
  }
  dscript.src = src;
  document.body.appendChild(dscript);
}

注意:

  1. 下载并未开始,直到脚本加载完成,这和动态加载图片不同(动态加载图片,只要设置src属性就会立即加载)
  2. 无论动态加载的脚本添加到head还是body标签里都不会阻塞页面渲染

相关资源

  1. IE’s Premature Execution Problem
  2. The art and craft of the async snippet
  3. Deep dive into the murky waters of script loading
  4. Loading JavaScript without blocking
  5. non-blocking-scripts
  6. The truth about non-blocking JavaScript

元素的宽度和长度

Width

max-width

如果width没有设置时,元素的宽度将由max-width决定。如果width值被设置且小于max-width时,将会使用width的值,否则将使用max-width的值。

min-width

min-width会重载width,max-width设置,如果width设置的为绝对值比如px, pt, in, cm, mm等,这时候min-width就不会起作用。使用min-width最好的办法是设置width为百分比,min-width为绝对值。

相关链接

  1. max-width
  2. min-widht

探索react技术栈-技术选型

一.前言


陆陆续续接触react有一年多了,深感react的简单优雅,急切地想用react去开发程序。但是热情之后,发现react社区的种种问题。比如在社区打打常常提到的 angular vs react。react作为view层的库,
并没有给我们提供像angular那样全方位的解决方案。社区很多围绕react的解决方案层出不断,尚没有形成一致的最佳实践。那么,在现有的react解决方案下,我们能否提炼出一个行之有效的方案呢,笔者认为可以从以下几方面入手:

  1. 技术选型
  2. 项目目录划分
  3. 应用程序状态管理
  4. 前后台交互
  5. 测试
  6. 迭代式开发

本文作为探索react技术栈第一篇,首先来聊一聊基于react技术栈的技术选型。

二.技术选型


  1. View(react)

    使用react来构造view

  2. 状态管理(redux or mobx)

    reduxmobx是社区两个最著名的状态管理框架。可以选择其中一种,因为redux作者是react核心团队的开发者,基于redux的社区也非常庞大,推荐使用redux

  3. 路由(react-router)

    react-router是react社区公认的路由框架,但是这个库更新频繁,api变动比较大,笔者推荐使用其较稳定的v2.8.1

  4. 样式

    当前围绕react的样式解决方案,有三种即传统class声明,css in js,css modules

  5. 语言(Es6)

    对浏览器要求不高,即满足ie9+以上的,可以使用es6开发应用,然后通过babel转码,对于浏览器要求较高的,使用es5来编写,并引入pollify来支持浏览器兼容

  6. fetch

    fetch spec使用promise接口来进行后端接口请求,相比ajax来说,使用更加方便,在项目中,推荐使用fetch的官方实现

  7. 构建工具(webpack)

    webpack是社区公认的优秀打包工具,和react非常搭。配合gulp来完成流畅地前端开发。

  8. 测试(jest or enzyme)

    facebook推出的react测试工具jest和airbnb推出的enzyme都可以用来测试react

  9. mock(node or json mock server)

    基于react的开发,几乎都是前后端分离,通过mock后端的接口,可以加快前端的开发效率。构建mock接口,一可以通过node来自己编写mock server或者可以通过现有的json mock server比如jsonyeah

  10. 异步数据流处理

    对于简单的异步数据处理我们可以使用redux-thunk或者redux-promise,对于复杂的异步交互,可以使用redux-observableredux-sagas

相关链接


  1. react howto

  2. React + Redux 最佳实践

聊聊前端布局

聊聊前端布局

作为一名前端工程师,页面布局能力是最基本能力。最近公司招聘前端,自己作为面试官,出了一些题,其中一道就是布局的题目:实现一个左侧定宽,右侧充满剩余屏幕的布局。

布局涉及的点包括以下几个方面:

  1. position属性理解运用
  2. flat属性理解运用
  3. 盒模型
  4. BFC/IFC/GFC/CFC
  5. 块级元素和内联元素

position

position有4个属性,分别为static,relative,absolute,fixed。

属性 相对谁定位 使用场景 注意事项
static 默认值 没有top,left,right,bottom,z-index属性
relative 相对于其默认位置(static) 微调元素的位置 没有脱离文档流
absolute 相对于离它最近的已定位元素(如fixed,relative,absolute) 弹出框 脱离文档流
fixed 相对于浏览器窗口定位 固定导航菜单,滚动到头部 脱离文档流

脱离文档流指的是元素的布局不再影响文档中的其他元素。

float

属性 规则 使用场景 注意事项
none
left 向左浮动,直到遇到带框的元素 左侧定宽布局 脱离文档流
right 向右浮动,直到遇到带框的元素 右侧定宽布局 脱离文档流

BFC

BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

使用那些属性会形成BFC:

  1. 根元素
  2. float属性不为none
  3. position为absolute或fixed
  4. display为inline-block, table-cell, table-caption, flex, inline-flex
  5. overflow不为visible

BFC布局规则:

具体布局规则有以下几条:

  1. BFC会阻止垂直外边距(margin-top、margin-bottom)折叠
  2. BFC不会重叠浮动元素
  3. BFC会包含浮动元素
  4. 计算BFC的高度时,浮动元素也参与计算

低版本浏览器比如ie6,7如何触发BFC

  1. postion:absolute
  2. float: left|right
  3. display: inline-block
  4. width:除"auto"外的任意值
  5. height:除"auto"外的任意值
    6.zoom:除"normal"外的任意值

当元素的hasLayout属性值为false的时候,元素的尺寸和位置由最近拥有布局的祖先元素控制。当元素的hasLayout属性值为true的时候会达到和BFC类似的效果,元素负责本身及其子元素的尺寸设置和定位。

清除浮动

/*兼容ie6,7的清除浮动方法*/
.clearfix {
    *zoom: 1;
}

.clearfix:after {
    display: table;
    content: '';
    clearboth;
}

深入浅出webfont

相关资源

图标资源收集。图标是现代web开发中经常用到的资源。使用图标有以下几个好处:(1)从可配置上来讲,图标字体可修改颜色,可定制大小 (2)从文件大小上来说,相比图片,图标体积要更小(3)从易用的角度来说,图标字体使用简单,只需要在i标签引用相应的类就可以。

1.font awesome

使用最多的图标字体库,包含了国内外常用的图标

2.easy icon

小清晰的图标库,你可以在这里搜到常用的图标。

3.iconfont

阿里巴巴公司推出的字体图标库,这个网站除了包含阿里巴巴内部产出的图标字体,也包括外部的图标设计者上传的图标,图标资源比较丰富。

如何确保页面始终在一个窗口中打开

用途

页面始终在一个窗口中打开

Code

    var mainWin = null;
   // window.open有窗口菜单配置项时,为新窗口打开,否则是标签页打开
    function newFullscreenWindow(action, name) {
        if (mainWin == undefined || mainWin == null || mainWin.closed) {
            mainWin = window.open(action, "_blank");
            mainWin.moveTo(0, 0);
            mainWin.resizeTo(screen.width + 20, screen.height);
            mainWin.focus();
            console.log(mainWin.document);
        } else {
            mainWin.close();
            mainWin = window.open(action, "_blank");
            mainWin.moveTo(0, 0);
            mainWin.resizeTo(screen.width + 20, screen.height);
            mainWin.focus();
            mainWin.document.location.reload();
        }
    }
   //  事件代理,拦截链接点击默认行为,改为新窗口打开
    $('table').on('click',function(event) {
        if(event.target.tagName === 'A') {
            event.preventDefault();
            newFullscreenWindow(event.target.href);
        }
    });

Learn ES6 [函数篇]

函数参数的默认值

规则

  1. 参数变量是默认声明的,所以不能用let或const再次声明
 let oPlus = (x,y=5) => {
    let x = 1; // 语法错误
   return x + y;
 }

3.当传入的参数是undefined时,如果有默认参数,将会调用默认值,传入参数为null时,不会调用默认值

let oPlus = (x,y='world') => {
  return x+y;
}
console.clear(); 
console.log(oPlus('hello ',undefined));  //'hello world'
console.log(oPlus('hello '));  //'hello world'
console.log(oPlus('hello ',null));  //'hello null'

4.非尾部的参数设置默认值,实际上这个参数是没法省略的

let oPlus = (x='world',y) => {
  return x+y;
}
console.clear(); 
console.log(oPlus());  // 报错
console.log(oPlus(,));   // 1 undefined
console.log(oPlus(null)); // null undefined
console.log(oPlus(undefined)); 1 undefined

代码示例CODEPEN

// es5中默认参数的写法
function oPlus(x,y) {
    if (typeof y === 'undefined') {
        y = 'world'
    } 
    return x + y;
}
// es6中默认值写法
let oPlus = (x,y='world') => {
  return x+y;
}
console.clear(); 
console.log(oPlus()); // 'undefinedworld'
console.log(oPlus('hello '));  //'hello world'
console.log(oPlus(undefined)); // 'undefinedworld'
console.log(oPlus(null)); // 'nullworld'
console.log(oPlus(undefined,undefined)); // 'undefinedworld'
console.log(oPlus(null,null)); // 0
console.log(oPlus(undefined,'ok')); // 'undefinedok'
console.log(oPlus(null,'ok')); // 'nullok'
console.log(oPlus(null,undefined)); // 'nullworld'
console.log(oPlus(undefined,null)); // NaN

与解构赋值默认值一起使用

规则

  1. 默认参数仍然可以进行二次默认参数设置,比如 {x,y=5} = {}或者 {x,y} = {x:1,y:5}

    这两种写法稍微有些不同,个人更倾向于第一种

// {x,y=5} = {} 等同于 {x,y} = {y:5} 双重默认值
let destructFunc = ({x,y=5} = {}) => {
  console.log(x,y);
}
console.clear();
destructFunc(); // undefined 5
destructFunc({x:1}) // 1 5
destructFunc({x:2,y:10}) // 2 10
let foo = ({x,y=5}) => {
  console.log(x,y);
}
foo(); // 报错
foo({x:1}); // 1 5
foo({}) // undefined 5

函数的length

规则

  1. 函数length的含义指的是预计传入函数的参数个数,如果用...rest表示参数的话,其length = rest.length;
  2. 参数设置默认值后,自身以及后续参数都不纳入函数length统计范围;

    示例代码

 (x,y=5) => {}  // length: 1
 (x=5,y) => {} // length: 0
 (x,y=5,z) => {} // length: 1
 ({x,y=5}) = {}  // lenght: 1
 ({x,y}) = {}  // lenght: 1
 ({x=1,y}) = {}  // lenght: 1
 ({x,y=5} = {}) = {}  // lenght: 0

作用域

规则

默认参数的作用域规则也符合一般变量的作用域规则,即首先是函数作用域,其次是全局作用域

示例代码

let x = 1;
let foo = (y=x) => {
   let x  = 3;
   console.log(y);
}
foo();//1
// 参数默认值是函数
let strfoo = 'bar';
let sfunc = (func = () => strfoo) => {
  let strfoo = 'ccc';
  console.log(func());
}
// 传值的变量是全局变量是
let sx = 1;
let sxfoo = (x, y= () => { sx=x }) => {
  console.log('inner',x);
  x  = 4;
  y();
  console.log(sx);
}
sfunc(); // 'bar'
sxfoo(5); // 'inner' 5 \n 4
console.log(sx); // 4

原理

从上面可以看出,sxfoo执行时,分以下几步:

一、执行参数部分

  1. 先通过函数传参,显示指明第一个参数x等于5;
  2. 由于没有传值给参数y,此时其值为undefined,自动赋值y =() => {sx = x} ,然后初始化此匿名箭头函数,顺序也是从参数到函数体。由于该匿名函数此时只是进行一系列函数初始化并未执行,因此sx只是绑定了window'x'一个引用

二、执行函数体部分

  1. 执行函数体代码,x仍等于5,此时程序向控制台输出 inner 5
  2. x= 4 将 全局变量x即window['x']设置为4,
  3. 执行y() 此时sx= x实际执行,赋值sx等于window['x']即4
  4. 程序执行到最后一句console.log(sx),向控制台输出 4

rest

规则

  1. rest是一个真正的数组,可以使用数组对象的一切方法
  2. rest参数后不能再有参数,否则会报错
  3. 函数的length属性不包括rest参数

示例代码

  // rest可以使用一个真正的数组方法
  let arrPush = (array,..items) => {
     items.forEach( item => array.push(item));
  }
  let a = [];
  arrPush(a,1,2,3,4);
  // 函数长度
  let restFunc = (y,...rest) => {};
  let restFunc1 = (...rest) => {}
  console.log(reestFunc.length,restFunc1.length); // 1 0;

扩展运算符

1.扩展运算符可以将数组变成以逗号为分隔的字符串
2.如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。

代码示例CODEPEN

// 将数组转化为逗号分隔的字符串
let a = [1,2,3]
console.log(...a) // 1 2 3 
console.log(1,2,3);
// 合并数组
let b = [4,5]
a.push(...b)
console.log(a) // 1 2 3 4 5
// 替代apply
console.log(Math.max(...a)); // 3
console.log(Math.max.apply(null,a)); // 3
// 与解构赋值一起使用
const [first,...second] = [1,2,3,4];
console.log(first,second);// 1,[2,3,4]
const [ifirst,...isecond] = [];
console.log(ifirst,isecond); // undefined [];
const [...iisecond,iifirst] // 报错
// 处理函数的返回值,函数的返回值只有一个,如果想多个值,可以返回数组
let foo = () => [1,2,3];
console.log(...foo());
// 将字符串转化为真正的数组
console.log(...'helloworld');
/* 任何Iterator接口的对象,都可以用扩展运算符转为真正的数组。
...document.getElementsByTagName document.childNodes
上面代码中,arrayLike是一个类似数组的对象,但是没有部署Iterator接口,扩展运算符就会报错。这时,可以改为使用Array.from方法将arrayLike转为真正的数组。
*/
let arrayLike = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  length: 3
};

// TypeError: Cannot spread non-iterable object.
let arr = [...arrayLike];
// Map和Set结构,Generator函数都可以使用扩展运算符
let map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

let arr = [...map.keys()]; // [1, 2, 3]
var go = function*(){
  yield 1;
  yield 2;
  yield 3;
};

[...go()] // [1, 2, 3]

函数name

规则

将函数名称标准化了,纠正了es5,匿名函数赋值,函数名称为空的现象

代码示例

 let foo = () => {} // function name is 'foo'
 var foo = function() {} // function name is ''
 function foo() {} // function name is foo

严格模式

规则

  1. 参数使用了默认参数,解构赋值,扩展符的不能在函数体内部使用‘use strict’
  2. 在全局下使用严格模式,即将‘use strict’显示声明在所有函数体外
  3. 把函数包在一个无参数的立即执行函数里面,可以规避第一条规则
const doSomething = (() => {
  'use strict'
 return function(value=43) {
    return value; 
 }
})

原理

函数执行的顺序是先执行参数部分,再执行函数体,如果在函数内部常规声明严格模式,由于参数部分先执行,此时严格模式还没生效,而到了函数体部分,严格模式又生效了,这样参数部分和函数体部分就出现不一致的验证的规则,增加了程序的复杂度,es6标准索性禁止设置严格模式。

箭头函数

规则

  1. 箭头函数的this指的是它定义时的上下文环境,而不是运行时的上下文环境;
  2. 箭头函数不能当作构造函数,因为它没有new命令,否则会报错;
  3. 箭头函数不能使用arguments,因为箭头函数没有arguments这个值,可以用rest替代;
  4. 不可以用作yield函数,因为箭头函数不能用作Generator函数;
  5. 除了this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments、super、new target;
  6. 由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向。

    代码示例

// 简单的箭头函数
let foo = () => {}
// 作为回调函数被执行
[].map(v => v+1);
[].map(v => { return v+1;})
//等同于
[].map(function(v) { return v+1})
// 结合扩展符
let a = [1,2,3];
let oitem = (...numbers) => {
    let sum = 0;
    numbers.forEach(n => sum+=n);
    return sum;
}
console.log(oitem(...a)); //6
//和变量解构一起使用
let oput = ({first,second}) => `${first}${second}`;
console.log(oput({
  first: 'cuc',
  second: 'baidu'
})); // 'cucbaidu'
// 箭头函数的this指向
console.clear();
window['s2'] = 0;
class Timer {
  constructor() {
    this.s1 = 0;
    this.s2 = 0;
    this.count = 0;
    setInterval( () => {
      this.s1++;
    },1000);
    setInterval(function() {
      this.s2++;
      this.count++;
    },1000);
  }
}
let timer = new Timer();
console.log(timer.s2); // 0
setTimeout(() => console.log('s1',timer.s1,window['s1']),2100); // 2 undefined
setTimeout(() => console.log('s2',timer.s2,window['s2']),2100); // 0  2
console.log(window['s2']); // 0 
/* 
声明了一个类,类里面一个使用箭头函数作为回调函数,一个使用普通函数作为回调函数。
箭头函数绑定定义时的上下文环境也就是Timer,而普通函数绑定的是运行时的上下文环境,即window
*/

尾调用

什么是尾调用

  1. 尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数;
  2. 尾调用只发生在严格模式下。
  3. 最有最后一步调用的是函数,才可以称为尾调用
function f(x) {
    return g(x);
}
function f(x) {
    if (x<0) {
     return m(x);
    } else {
     return n(x);
    }
}
只有最后一步调用的是函数才是尾调用

原理

尾调用之所以与其他调用不同,就在于它的特殊的调用位置。我们知道,函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就可以了。

尾递归

尾递归的实现,往往需要改写递归函数,确保最后一步只调用自身。做到这一点的方法,就是把所有用到的内部变量改写成函数的参数。
CODEPEN

// hack尾递归方式一
 function currying(func,n) {
     return function(m) {
        return func.apply(this,m,n);
     }
  }
function tailFactorial(n, total) {
  if (n === 1) return total;
  return tailFactorial(n - 1, n * total);
}

const factorial = currying(tailFactorial, 1);
console.log(factorial(5)); // 120
// hack 尾递归方式二
function factorial(n,total = 1) {
    if (n===1) {
        return total;
    }
    return factorial(n-1,total);
}
console.log(factorial(5)) // 120
// hack 尾递归方式三
let tco = (f) => {
  let value = null;
  let active = false;
  let accumArr = [];
  return function() {
    accumArr.push(arguments);
    while(accumArr.length) {
      active = true;
      value = f.apply(this,accumArr.shift());
    }
    active = false;
    return value;
  }
}

let sum = tco((n,m) => {
  if (m>0) {
    return sum(n+1,m-1);
  } else {
    return n;
  }
});

console.log(sum(1,1000));

相关链接

  1. ECMAScript入门
  2. exploring es6
  3. 深入浅出Es6

跨域知识大全

背景

跨域字面意不同域,域指的是资源的访问路径包括协议,域名,端口,页面路径,跨域指的是协议,域名,端口,页面路径四者中至少其中之一不同。

注意: 协议和端口不同,不能仅靠设置客户端来实现跨域

实现跨域的常见方式有以下几种:

  1. 主域相同,比如http://www.a.com/a.html和http://www.a.com/b.html之间跨域通信
    首先要在a.html和b.html中设置document.domain = 'a.com',然后通过iframe在一个页面加载另一个页面来实现通信。
  2. 通过动态插入js脚本,来实现跨域
  3. hash+iframe,通过子iframe更改父页面location来进行数值传递,如果遇到兼容性问题,考虑使用同域来解决
  4. 通过在需要跨域访问的页面中设置window.name,来进行数据传递
  5. 通过设置xhr.withCredential=true或者使用xDomainRequest来设置自定义的请求头,来让服务端决定是否跨域请求成功
  6. 通过window.postMessage,指定跨域目标源来实现跨域
  7. jsonp,在script的src中传入参数,想服务器端请求需要执行的函数,然后在客户端执行
  8. webscoket 在需要跨域的服务器上部署websocket服务,这样可以通过websocket直接进行通信

相关链接

  1. 前端解决跨域的8种方案

yarn 将取代 npm cli ?

介绍

昨天facebook推出了node包管理工具**yarn**

yarn 安装

  1. 快速安装
    npm i yarn -g/sudo npm i yarn -g
  2. 详细安装
    yarn installation

yarn 特点

  1. 超级快
  2. 超级安全
  3. 超级靠谱

yarn 常用命令

  • 生成一个新项目
yarn init
  • 添加依赖包
yarn add [package]
yarn add [package]@[version]
yarn add [package]@[tag]
  • 更新依赖包
yarn upgrade [package]
yarn upgrade [package]@[version]
yarn upgrade [package]@[tag]
  • 移除依赖包
yarn remove packagename
  • 安装package.json中指定的所有依赖
yarn / yarn install

相关链接

yarn
npm
npm 模块安装机制简介
npm scripts 使用指南
Whey I'm Working on Yarn

说说window

window相关属性

window关键词在ES5非严格模式下,一般等于this,指的是浏览器窗口。

top

获取浏览器的最顶层窗口

parent

获取当前窗口的父级窗口

self

获取当前自身窗口

frames

当前文档中所有包含的iframe的集合。frames对象指向当前Window对象,真正的iframe集合以数组和Window对象属性的形式挂载到Window对象上。

document

对当前文档的只读引用

histtory

对当前历史记录的只读引用

closed

返回当前窗口是否关闭

name

返回当前窗口的名称

opener

  • 返回对创建该窗口的Window对象的引用
  • 可以通过该属性调用创建者Window对象的属性和方法,从而控制创建者窗口的内容变化
  • 如果被打开的页面和当前页面不在同一个域下,被打开的页面中opener为空

screen

返回对当前屏幕Screen的只读引用

location

返回对当前地址的只读引用

innerHeight & innerWidth

  • 只读属性
  • 返回窗口的文档显示区高度和宽度,不包括菜单栏、工具栏和滚动条等高度
  • IE不支持该属性,以clientHeight & clientWidth代替

screenLeft & screenTop & screenX & screenY

  • 只读属性
  • 返回浏览器窗口在屏幕上的x坐标和y坐标
  • 移动端无实际意义,因为移动端浏览器窗口始终是全屏幕打开的,这些数据会一直都是0

scrollBy(xnum,ynum)

  • 滚动条滚动多少像素

scrollTo(xnum,ynum)

  • 滚动到某个坐标

close

  • 仅能通过js调用
  • 对移动端无效

open

  • 打开一个新窗口,当不指定新打开窗口菜单配置时,在ie9+等现代浏览器上,会默认打开一个标签页
  • 移动端不能使用

navigator

  • 返回对Navigator对象的引用

特殊情况

只有一个窗口时

window.parent == window == window.self == window.top

参考资料

  1. 原生DOM系列-Window对象

深入react技术栈-读书笔记1

前言

接触react已经有一年多了,也曾向团队强烈推荐过react并自己亲自写过一个data table,自定义form表单。使用react之后,我感觉react在组件化方面非常棒,可以轻松实现组件复用。但是,单单有react是无法构建复杂应用的,基于react自身通过props和state层层传递数据的方式是无法适应大规模应用的。自己在编写data table的时候,就发现这样的问题。一年多,反反复复地看各种社区资料,没有一套自己系统的思维,幸好,最近看了《深入react技术栈》,帮助自己重新梳理react技术栈。

##《react技术栈》

这本书是由维护知乎pure render专栏的几个阿里巴巴工程师编写。内容属于中级难度。涵盖了react入门,react中事件,样式,复用,flux,redux,服务端渲染,可视化等诸多话题。

React入门

1. React简介

简单介绍下react的由来,react特点包括专注于视图层,使用虚拟dom和函数式编程。

2. JSX语法

类似于xml的ECMASCRIPT扩展,最初它的编译器是facebook内部开发的jsxtransform,后来又改为社区知名的编译插件babel

3. React组件

简单回顾下传统的组件构建方式即通过面向对象的方式来构建组件,如下:

class Tabs {
constructor(options) {
   this.options = options;
}
}

而react构建组件的方式和传统有很大的不同,react构建组件有三种不同的方式:

  • React.createClass 兼容性最好
  • class 跟随es6标准
  • 无状态组件,react官方极为推荐这种方式
    相比传统方式,react构建组件,简单轻松,很方便地把css,js,html结合在一起,充分利用js的灵活性和强大

4. React的数据流

  • react中数据一般从父组件传到子组件,数据通过state或props进行存储和传递。
  • state指的是组件内部的状态,props是指组件化时,组件由父组件传递进来的配置,是不可变的,除非父组件发生变化,子组件的props有可能发生变化

5. React的生命周期

生命周期分为三个阶段即挂载,更新,卸载。

挂载期的生命周期方法,只发生一次

React.createClass

  • propTypes,
  • getDefaultProps
  • getIntialState,
  • componentWillMount (可以调用setState)
  • componentDidMount

class

  • static propType,
  • static defaultProps
  • constructor,
  • this.state,
  • componentWillMount,
  • componentDidMount

更新期,生命周期方法可以发生多次

  • componentWillReceiveProps,(可以调用setState)
  • shouldComponentUpdate,
  • componentWillUpdate,
  • componentDidUpdate,(可以调用setState)

卸载期,生命周期方法仅发生一次

componentWillUnMount,在这个生命周期方法中,一般清除注册事件,定时器等防止内存泄漏。

6. React与dom

  • 使用ReactDOM.render方法将react元素渲染到屏幕上
  • 使用ref来引用react元素实例
  • findDOMNode来获取dom元素,只能用在dom元素已经生成的时期,比如componentDidMount和componentDidMount中

underscore源码阅读-开始篇

一.为什么选择underscore

underscore.js是一个javascript功能库,非常流行,同类的项目有lodash。它包含有我们日常前端开发中经常用的函数包括map,reduce,filter,find等,使用起来比较方便。每个函数定义相对独立,互为依赖较少,也便于阅读。函数是大型js框架的基础,通过阅读underscore代码可以增加自己的函数编程能力,了解js不太熟悉的知识点比如void expression返回undefined等,为后续阅读inferno做准备。

二.如何阅读

1.[误区]:

(1). 直接阅读源代码
(2). 只看不练

2.[可能正确的方式]:

(1). 简单翻阅别人已经有的源码分析,比如这个repo就很赞,简单翻阅,了解underscore源码阅读的一些基本思路。
(2). 对照underscore官网api使用说明,逐一先看通过该api能实现什么功能,进而对照源码看如何实现,然后自己在jsbin重新自己写一遍,这样下来,基本将如何用到如何创造走了一遍。
(3). 尝试用新的语言es6重新打造一个underscore,在此过程中对underscore用到的知识点进行调研整理

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.