2017年前端技术学习回顾

2017年8月10日(为什么记得这么清楚~),加入了易鑫,之前公司是做p2p,属于c端项目,当时项目的框架是公司自己开发的前端框架,后面在项目优化的过程中,我们单独引入了vue.js,出于开发成本考虑,项目全部改造成vue全家桶项目成本太高(vue+vue-router+vuex+axios+es6+sass),没有这个时间成本去替换。在使用vue的过程中,真的喜欢上了这个框架,入门简单,易用,还便于与第三方库或既有项目整合,数据驱动的模式,让我们不用频繁的去处理dom,而是关注与数据的处理。

一 淘车拍app的开发(h5)

来到易鑫之后,当时前端人手比较少,大家都在leader的带领下做c2b后台的开发,淘车拍app根据实际情况采用的混合app开发,h5项目我采用的是vue全家桶。

由于项目是b端的,想比c端业务场景更加复杂,在项目开发主要难点有:

1.各个组件数据的共享

传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。而且也会导致代码难以维护

解决方法:采用vuex进行状态管理,把所有事件和状态存储在store对象中,在组件中通过计算属性获得事件,因此就有了实时性。

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。每一个 Vuex 应用的核心就是 store(仓库)。”store” 基本上就是一个容器,它包含着应用中大部分的状态(state)。Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交(commit) mutations。这样使得我们可以方便地跟踪每一个状态的变化。

经常看到小伙伴们为什么用vux,什么时候使用vux?

引用 Redux 的作者 Dan Abramov 的话说就是: Flux 架构就像眼镜:您自会知道什么时候需要它。

vux官方文档地址:vuex

vue调试神器vue-devtools:vue-devtools

2.项目结构复杂

由于我们的业务涉及c2b业务以及车商工具业务,项目结构比较复杂。

解决办法:在项目中,我们将组件和页面,router以及api,按照业务模块化开发。降低耦合,提高模块的维护性。

eg:api模块化

import base from './base';
import common from './common';
import auction from './auction';
import sales from './sales';
import overhaul from './overhaul';
import purchase from './purchase';
import assess from './assess';
import inventory from './inventory';

export default {
  ...base,
  ...common,
  ...auction,
  ...sales,
  ...overhaul,
  ...purchase,
  ...assess,
  ...inventory,
};

技术栈

1、Vue全家桶(vue2、vue-router、vuex) 快速开发SPA神器

2、Axios vue作者推荐的数据请求方案

3、ES6 全面过度es6的写法 趋势

4、Webpack2,vue-cli 脚手架已经配置好了

5、flex布局 对于移动端可以放心大胆的使用

6、移动端屏幕适配 采用手淘的flexible+rem方案

二、es6语法

1.两种新的声明变量的方法

①let,用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

特点1.块级作用域。2.不存在变量提升。3.不允许重复声明

②const,const声明一个只读的常量。一旦声明,常量的值就不能改变。const一旦声明变量,就必须立即初始化,不能留到以后赋值。只在声明所在的块级作用域内有效。

2.变量的解构赋值
解构赋值允许你使用类似数组或对象字面量的语法将数组和对象的属性赋给各种变量。这种赋值语法极度简洁,同时还比传统的属性访问方法更为清晰

数组的解构赋值
数组的元素是按次序排列的,变量的取值由它的位置决定

let [a, b, c] = [1, 2, 3]
a // 1
b // 2
c // 3
let [head, ...tail] = [1, 2, 3, 4]
head // 1
tail // [2, 3, 4]
*默认值
let [foo = true] = [];
foo // true

eg:

//返回一个数组
function example(){
 return [1,2,3];
}
let [a,b,c]=example();

对象的结构赋值
对象的属性没有次序,变量必须与属性同名,才能取到正确的值

let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
*默认值
var {x = 3} = {};
x // 3
var {x, y = 5} = {x: 1};
x // 1
y // 5

eg:

*将现有对象的方法,赋值到某个变量。
//将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上
let { log, sin, cos } = Math    
// 返回一个对象
function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();
*提取json数据
let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]

字符串的解构赋值

const [a, b, c, d, e] = 'hzzly'
a // "h"
b // "z"
c // "z"
d // "l"
e // "y"

函数参数的解构赋值

function add([x, y]){
  return x + y;
}
add([1, 2]); // 3

3.函数的扩展
①函数参数的默认值

*参数变量是默认声明的,所以不能用let或const再次声明
*通常情况下,定义了默认值的参数,应该是函数的尾参数
function log(x, y = 'World') {
  console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello

②与解构赋值默认值结合使用

function foo({x, y = 5}) {
  console.log(x, y);
}
foo({}) // undefined, 5
foo({x: 1}) // 1, 5
foo({x: 1, y: 2}) // 1, 2
foo() // TypeError: Cannot read property 'x' of undefined

③reset参数

ES6 引入 rest 参数(形式为“…变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错

function add(...values) {
  let sum = 0;
  for (var val of values) {
    sum += val;
  }
  return sum;
}
add(2, 5, 3) // 10
function push(array, ...items) {
  items.forEach(function(item) {
    array.push(item);
    console.log(item);
  });
}
var a = [];
push(a, 1, 2, 3)

④扩展运算符(…)

*它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
*扩展运算符内部调用的是数据结构的Iterator接口
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [
,
,
] function push(array, ...items) { array.push(...items); } function add(x, y) { return x + y; } let numbers = [4, 38]; add(...numbers) // 42

eg:

*替代数组的apply方法
// ES5的写法
Math.max.apply(null, [14, 3, 77])
// ES6的写法
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);
*合并数组
// ES5
[1, 2].concat(more)
// ES6
[1, 2, ...more]
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
// ES5的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
与解构赋值结合
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]
const [first, ...rest] = [];
first // undefined
rest  // []:
const [first, ...rest] = ["foo"];
first  // "foo"
rest   // []

⑤箭头函数

一 箭头函数可以让this指向固定化,这种特性很有利于封装回调函数

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。

(4)不可以使用yield命令,因此箭头函数不能用作Generator函数。

var f = () => 5;
// 等同于
var f = function () { return 5 };
var f = v => v;
//等同于:
var f = function(v) {
  return v;
};
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
  return num1 + num2;
};
*箭头函数简化回调函数

// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});
// 箭头函数写法
[1,2,3].map(x => x * x);
*箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域
function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval(function () {
    this.s2++;
  }, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0
*因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this

function foo() {
  return () => {
    return () => {
      return () => {
        console.log('id:', this.id);
      };
    };
  };
}
var f = foo.call({id: 1});
var t1 = f.call({id: 2})()(); // id: 1
var t2 = f().call({id: 3})(); // id: 1
var t3 = f()().call({id: 4}); // id: 1

你可能感兴趣的:(2017年前端技术学习回顾)