一、js基础&es6
1.数组去重
方法一:使用Array的filter + indexOf
var arr = [1, '1', 2, 2, 3,3]
var distinctArr = arr.filter(function(element, index, self){
return self.indexOf(element) === index; // 只返回首次出现的 self为数组arr
})
console.log(distinctArr);
方法二:es6的Set
var arr = [1, '1', 2, 2, 3, 3, 3, 3, 1, '1']
const items = new Set(arr); //初始化一个Set
const array = Array.from(items); // 通过Array将Set转为数组
console.log(array)
方法三:循环数组判断,符合的加入新数组
var data = [1, '1', 2, 2, 3, 3, 3, 3, 1, '1'];
Array.prototype.unique=function(){
var arr=[];//创建新数组
for(var i=0;i<this.length;i++){ //遍历当前数组
if(arr.indexOf(this[i]) === -1) {
arr.push(this[i]);
}
}
return arr;
}
console.log(data.unique());
2.js原生深度克隆
1.浅克隆
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
obj1.b.c = 55; // 两个对象都修改了
console.log(JSON.stringify(obj1));//"{\"a\":0,\"b\":{\"c\":55}}"
console.log(JSON.stringify(obj2));//"{\"a\":0,\"b\":{\"c\":55}}"
2.深度克隆
方法一:通过JSON的序列化与反序列化
//对象
var obj1 = { a: 0 , b: { c: 0}, arr:[1,2,3]};
var obj2 = JSON.parse(JSON.stringify(obj1));
// 修改obj1的值
obj1.a = 4;
obj1.arr.push(4)
obj1.b.c = 4;
console.log(JSON.stringify(obj1)); // "{\"a\":4,\"b\":{\"c\":4},\"arr\":[1,2,3,4]}"
console.log(JSON.stringify(obj2)); // "{\"a\":0,\"b\":{\"c\":0},\"arr\":[1,2,3]}"
//数组
var arr1 = [1,2,3];
var arr2 = JSON.parse(JSON.stringify(arr1));
arr1.push(4);
console.log(arr1)
console.log(arr2)
方式二:原生JS
var obj1 = { a: 0 , b: { c: 0}, arr:[1,2,3]};
var obj2 = cloneObj(obj1);
obj1.arr.push(4);
obj1.b.c = 99;
console.log(obj1);
console.log(obj2);
function cloneObj(obj) {
var newObj = {};
if (obj instanceof Array) {
newObj = [];
}
for (var key in obj) {
var val = obj[key];
newObj[key] = typeof val === 'object' ? cloneObj(val): val;
}
return newObj;
}
方式三:空数组concat
var a=[1,2,3];
var b=a;
var c=[].concat(a);
a.push(4);
console.log(b);
console.log(c);
3.数组判断
var arr = [];
console.log(arr instanceof Array);// true
console.log(Array.isArray(arr));// true
console.log(arr.constructor.name);// "Array"
二、webpack
1.loader和plugin的区别
对于loader,它就是一个转换器,将A文件进行编译形成B文件,这里操作的是文件,比如将A.scss或A.less转变为B.css,单纯的文件转换过程;用于加载某些资源文件。 因为webpack 本身只能打包commonjs规范的js文件,对于其他资源例如 css,图片,或者其他的语法集,比如 jsx, coffee,是没有办法加载的。 这就需要对应的loader将资源转化,加载进来。从字面意思也能看出,loader是用于加载的,它作用于一个个文件上。
plugin 用于扩展webpack的功能。它直接作用于 webpack,扩展了它的功能。当然loader也时变相的扩展了 webpack ,但是它只专注于转化文件(transform)这一个领域。而plugin的功能更加的丰富,而不仅局限于资源的加载。
它就是一个扩展器,它丰富了wepack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,例如
run
:开始编译make
:从entry开始递归分析依赖并对依赖进行buildbuild-moodule
:使用loader加载文件并build模块normal-module-loader
:对loader加载的文件用acorn编译,生成抽象语法树ASTprogram
:开始对AST进行遍历,当遇到require
时触发call require
事件seal
:所有依赖build完成,开始对chunk进行优化(抽取公共模块、加hash等)optimize-chunk-assets
:压缩代码emit
:把各个chunk输出到结果文件
通过对节点的监听,从而找到合适的节点对文件做适当的处理。
三、Router
1.React-router 中的BrowserRouter 和 HashRouter
假如有一个 Link 标签,点击后跳转到 /abc/def
。
- BrowserRouter:
http://localhost:8080/abc/def
- HashRouter:
http://localhost:8080/#/abc/def
如果有服务器端的动态支持,建议使用 BrowserRouter
,否则建议使用 HashRouter
。
官方推荐使用browserHistory
这样看起来当然是browerHistory更好一些,但是它需要server端支持。
使用hashHistory时,因为有 # 的存在,浏览器不会发送request,react-router 自己根据 url 去 render 相应的模块。
使用browserHistory时,从 / 到 /user/liuna, 浏览器会向server发送request,所以server要做特殊请求,比如用的 express 的话,你需要 handle 所有的路由 app.get('*', (req, res) => { ... })
,使用了 nginx 的话,nginx也要做相应的配置。
如果只是静态页面,就不需要用browserHistory,直接hashHistory就好了。
四、Redux + React Redux常用函数
1.redux
1. combineReducers(reducers)
combineReducers辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore。
2.bindActionCreators(actionCreators,dispatch)
经过bindActionCreators处理的actions,直接调用函数就相当于进行了dispatch,因而实现了不调用dispatch即可触发state的改变。
使用场景: 当你需要把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,而且不希望把 Redux store 或 dispatch传给它。
3.createStore(reducer, [initState, enhancer])
- 作用:创建一个Redux store来存放应用中所有的state,一个应用只能有个store。函数返回store对象。
- 参数:
- reducer(Function):两个参数:state和action,返回一个state。 不要对参数state进行修改,需要返回一个新的对象。
- initStatate:初始state。如果不为空,需要和reducer中处理的state结构一致
- enhancer:一个中间件,如logger等。
4.applyMiddleware(...middlewares)
输入一个middlewares数组,返回一个函数,函数以createStore为参数.
每个 middleware 接受 Store的 dispatch和 getState函数作为命名参数,并返回一个函数。该函数会被传入 被称为 next 的下一个 middleware 的 dispatch 方法,并返回一个接收 action 的新函数,这个函数可以直接调用next(action),或者在其他需要的时刻调用,甚至根本不去调用它。调用链中最后一个 middleware 会接受真实的 store 的 dispatch
方法作为 next 参数,并借此结束调用链。所以,middleware 的函数签名是 ({ getState, dispatch }) => next => action。
2.react - redux
1.connect方法
来看下connect函数到底是如何将store和组件联系在一起的,注意到api文档中有这样的一句话:
It does not modify the component class passed to it; instead, it returns a new, connected component class for you to use.
connenct并不会改变它“连接”的组件,而是提供一个经过包裹的connect组件。 conenct接受4个参数,分别是mapStateToProps,mapDispatchToProps,mergeProps,options(使用时注意参数位置顺序)。
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
mapStateToProps(state, ownProps) 方法允许我们将store中的数据作为props绑定到组件中,只要store更新了就会调用mapStateToProps方法,mapStateToProps返回的结果必须是object对象,该对象中的值将会更新到组件中,例子:
const mapStateToProps = (state) => {
return ({
count: state.counter.count
})
}
mapDispatchToProps(dispatch, [ownProps]) 第二个参数允许我们将action作为props绑定到组件中,mapDispatchToProps希望你返回包含对应action的object对象,例如:
const mapDispatchToProps = (dispatch, ownProps) => {
return {
increase: (...args) => dispatch(actions.increase(...args)),
decrease: (...args) => dispatch(actions.decrease(...args))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(yourComponent)
当你想对组件的render更新进行更好的控制的时候,它也支持返回function方法,具体可以点击#279查看,例子:
const mapDispatchToProps = {
// increment: () => increment(1),
increase, // import increase function from action
decrease
}
mergeProps(stateProps, dispatchProps, ownProps) 该参数非必须,redux默认会帮你把更新维护一个新的props对象,类似调用Object.assign({}, ownProps, stateProps, dispatchProps)。
而options是为了更好的定制化设置的一个参数,允许返回5个boolean、function的值,我平时基本上没有接触到,想了解的可以参考api文档。
2.Provider 组件
Context解决了一个React中很常见的问题:当你的组件嵌套越来越深的时候,context能让你父组件和其它里层组件之间的通信变的更方便,createProvider方法将返回一个Provider组件,该组件接受store和子组件,在Provider中定义了getChildContext方法来传递store,那么在子组件中利用contextTypes,你就能利用context访问到父级组件传递的store数据了。