ES5和ES6常用数据处理函数

ES5和ES6常用数据处理函数

前言

现代前端并不是画画静态页面那么简单,很多以前后端的数据处理都放到了前端,由于数据处理越来越多和频繁。对js的数据处理函数有一定了解会在遇到问题的时候找到最优解,下面一起来看看常用的数据处理。(由于数组,对象,字符串是处理较多的类型,下面围绕这三种类型展开)

内容

大纲

console.log([])
VM166:1 
[]
length: 0
__proto__: Array(0)
concat: ƒ concat()
constructor: ƒ Array()
copyWithin: ƒ copyWithin()
entries: ƒ entries()
every: ƒ every()
fill: ƒ fill()
filter: ƒ filter()
find: ƒ find()
findIndex: ƒ findIndex()
flat: ƒ flat()
flatMap: ƒ flatMap()
forEach: ƒ forEach()
includes: ƒ includes()
indexOf: ƒ indexOf()
join: ƒ join()
keys: ƒ keys()
lastIndexOf: ƒ lastIndexOf()
length: 0
map: ƒ map()
pop: ƒ pop()
push: ƒ push()
reduce: ƒ reduce()
reduceRight: ƒ reduceRight()
reverse: ƒ reverse()
shift: ƒ shift()
slice: ƒ slice()
some: ƒ some()
sort: ƒ sort()
splice: ƒ splice()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
unshift: ƒ unshift()
values: ƒ values()
Symbol(Symbol.iterator): ƒ values()
Symbol(Symbol.unscopables): {copyWithin: true, entries: true, fill: true, find: true, findIndex: true, …}
__proto__: Object

一 常用的处理数组和对象的方法

1.箭头函数(有了箭头函数this的指向有了变化,所以单独提出来说一下)

// var和let
var a = 99;            // 全局变量a
f();                   // f是函数,虽然定义在调用的后面,但是函数声明会提升到作用域的顶部。 
console.log(a);        // a=>99,  此时是全局变量的a
function f() {
  console.log(a);      // 当前的a变量是下面变量a声明提升后,默认值undefined
  var a = 10;
  console.log(a);      // a => 10
}
// 1. let定义块级作用域变量
{ 
  var i = 9;
} 
console.log(i);  // 9

{ 
  let i = 9;     // i变量只在 花括号内有效!!!
} 
console.log(i);  // Uncaught ReferenceError: i is not defined

// 2.没有变量提升与暂时性死区
console.log(aicoder);    // 错误:Uncaught ReferenceError ...
let aicoder = 'aicoder.com';

// 3.let变量不能重复声明
let a = 0;
let a = 'sss';
// Uncaught SyntaxError: Identifier 'a' has already been declared

// var 
for (var i = 0; i < 5; i++) { 
    setTimeout(function (){
        console.log(i);  
    },1000);  
}
// 旧解决方案
for (var i = 0; i < 5; i++) { 
    (function(i){      //立刻执行函数
        setTimeout(function (){
            console.log(i);  
         },1000);  
    })(i);  
}
// 新方案
for (let i = 0; i < 5; i++) { 
    setTimeout(function (){
        console.log(i);  
    },1000);  
}

// this指向
function Person() {  
    this.age = 0;  
    setTimeout(function() {
        // 回调里面的 `this` 变量就指向了期望的那个对象了
        console.log(this.age);
    }, 1000);
}
var p = new Person()
------------------------------------
function Person() {  
    this.age = 0;  
    setTimeout(() => {
        // 回调里面的 `this` 变量就指向了期望的那个对象了
        console.log(this.age);
    }, 1000);
}
var p = new Person()

2.forEach和map和for...in for...of

forEach和map都是遍历函数,大家用forEach会遇到很多的问题,比如不能break, 不能return,这些都做了优化

//map不会改变原数组, forEach会改变原数组
// 1. 需要一个新数组
var array = [1, 2, 3];
array.forEach((item, index) => {
  array[index] = item * 2
});
var ttt = array.map((item, index) => {
    return item * 2
});
// 2. 需要修改后台返回的对象,加一个sex字段
var array = [{name: 'zz'}, {name: 'yy'}, {name: 'cc'}];
array.forEach((item, index) => {
    forEach[index].sex = '男'
});

var array = [{name: 'zz'}, {name: 'yy'}, {name: 'cc'}];
var ttt = array.map((item, index) => {
    item.sex = '男'
    return item
});
// 如果不想改变原数组,返回一个新对象
var array = [{name: 'zz'}, {name: 'yy'}, {name: 'cc'}];
var ttt = array.map((item, index) => {
    return {
        ...item,
        key: '男'
    }
});
// 既然map返回的是一个新数组,那我们用链式调用看看
var array = [2, 3, 5];
var arr2 = array.map(value => value * value).filter(value => value > 10);
// console.log(arr2)
// [25]

// 总结
forEach()可以做到的东西,map()也同样可以。反过来也是如此(只是比较繁琐)。

map()会分配内存空间存储新数组并返回,forEach()不会返回数据。

forEach()允许callback更改原始数组的元素。map()返回新的数组(也可以改变原始数组)。

// for...in   for...of 区别
// for of无法循环遍历对象
var userMsg = {
    0: 'nick',
    1: 'freddy',
    2: 'mike',  
    3: 'james'
};
 
for(var key in userMsg){
    console.log(key, userMsg[key]); 
}
console.log('-----------分割线-----------');
for(var item of userMsg){   
    console.log(item);
}

// 遍历输出结果不同
var arr = ['nick','freddy','mike','james'];
for(var key in arr){
    console.log(key);   
}
console.log('-----------分割线-----------');
for(var item of arr){   
    console.log(item);
}

//for in 会遍历自定义属性,for of不会
var arr = ['nick','freddy','mike','james'];
arr.name = "数组";
 
for(var key in arr){
    console.log(key+': '+arr[key]); 
}
console.log('-----------分割线-----------');
for(var item of arr){   
    console.log(item);
}

二 ES5 和 ES6 处理数据的区别

1.处理数组

// includes(es6) 判断数组里面是否包含某个值
[1, 2, 3].includes(2)     // true
[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true

// for...in..(es5)  遍历数组
var arr= [0,1,2,3]
for(var i in arr) {
    console.log(i)
}

// for...of..(es6)  遍历数组
var arr= [0,1,2,3]
for(var i of arr) {
    console.log(i)
}

//find(es6) 返回数组的第一个匹配的元素的值
[1, 5, 10, 15].find(function(value, index, arr) {
  return value > 9;
}) // 10

// findindex(es6) 返回数组的第一个匹配的元素的位置值
[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2
console.log(found);

// ...扩展运算符(es6) 扩展运算符(spread)是三个点(...),将一个数组转为用逗号分隔的参数序列。
console.log(...[1, 2, 3])
// 1 2 3

// flat(es6) 地板函数可以把多维数组变成一维的
[1, 2, [3, 4]].flat(index) // 想展开几级数组就设置index为多少
[1, [2, [3]]].flat(Infinity) // 如果想展开所有的数组传值就设置为Infinity

// reverse(es5) 反转数组
[1,2,3].reverse()


2.处理对象

// for...in..  遍历对象
// 正常
var obj= {'a':1,'b':2,'c':3,'d':4}
for(var i in obj) {
    console.log(i)
}

// 变态(会把原型上的属性也遍历出来,所有有时候用for循环更好)
Array.prototype.myfun = () => {
    alert('myfun')
}
var arr= [0,1,2,3]
for(var i in arr) {
    console.log(arr[i])
}

// Object.keys(obj)获取对象的所有key返回一个数组集合
var obj = {'name': 'xiaoming', 'age': 18};
console.log(Object.keys(obj))

// Object.values(obj)获取对象的所有value返回一个数组集合
var obj = {'name': 'xiaoming', 'age': 18};
console.log(Object.values(obj))


3.处理字符串

// substr 字符串截取
let month = "07" // 想月份显示的时候不带0
if (month.substr(0, 1) === '0') {
    month = month.substr(1, 2)
}

// indexOf和lastIndexOf(es5) 字符串第一次和最后一次出现的位置
let str="Hello world, welcome to the universe.";
console.log(str.indexOf("welcome"))
let str="I am from runoob,welcome to runoob site.";
console.log(str.lastIndexOf("runoob"));

// split 分割字符串
"2019-08-06".split('-') // 返回分割数组 ["2019", "08", "06"]


三 模块的导入和导出 import和export

  1. 先看看常用的jquery是怎样来封装模块的

    // 一个大的闭包来定义jquery对象,然后把大对象挂载在window全局变量上
    (function(window, undefined) {
        var jQuery = function() {}
        // ...
        window.jQuery = window.$ = jQuery;
    })(window);
    
  2. 我们看看AMD和CMD是怎样来封装模块的

    // AMD代表require.js(前置加载)
    // module1.js
         define(function (require, exports, module) {
          //内部变量数据
       var data = 'atguigu.com'
          //内部函数
          function show() {
            console.log('module1 show() ' + data)
          }
             //向外暴露
          exports.show = show
        })
        define(['module1'], function(module1){
         ...
         return {
          ...
         };
        });
    
    // CMD代码sea.js(按需加载)
         // module1.js
         define(function (require, exports, module) {
          //内部变量数据
          var data = 'atguigu.com'
          //内部函数
          function show() {
            console.log('module1 show() ' + data)
          }
        ​
          //向外暴露
          exports.show = show
        })
    
         // main.js : 主(入口)模块
        define(function (require) {
          var m1 = require('./module1')
          m1.show()
        })
            
    // CommonJs:node 的支持格式
    
     //    文件名: foo.js
     var $ = require('jquery');
     var _ = require('underscore');
            
     //    methods
     function a(){};    //    私有方法,因为它没在module.exports中 (见下面)
     function b(){};    //    公共方法,因为它在module.exports中定义了
     function c(){};    //    公共方法,因为它在module.exports中定义了
      
      //    暴露公共方法
        module.exports = {
             b: b,
             c: c
        };    
    
  3. 让我们看es6原生的import和export是如何来导入导出模块的

    // export  circle.js
    // 第一组
    export default function crc32() { // 输出
      // ...
    }
    import crc32 from 'crc32'; // 输入
    // 第二组
    export function crc32() { // 输出
      // ...
    };
    import {crc32} from 'crc32'; // 输入
    
    // 上面代码的两组写法,第一组是使用export default时,对应的import语句不需要使用大括号;第二组是不使用export default时,对应的import语句需要使用大括号。
    // export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export default命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令。
    
    //上面写法是逐一指定要加载的方法,整体加载的写法如下。
    export function crc31() { // 输出
      // ...
    };
    export function crc32() { // 输出
      // ...
    };
    import * as circle from './circle';
    
    //本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。所以,下面的写法是有效的。
    // modules.js
    function add(x, y) {
      return x * y;
    }
    export {add as default};
    // 等同于
    // export default add;
    
    // app.js
    import { default as foo } from 'modules';
    // 等同于
    // import foo from 'modules';
    
    // 正是因为export default其实只是输出了一个default的变量;所以后面就不可以再跟变量声明的语句;
    //正确
    export var a=1;
    //正确
    var a=1;
    export default a;
    //错误;
    export default var a=1;
    
    上面的代码中export default a其实是将a 赋值给default;所以最后一种语法报错;
    所以本质上export dafault 是将变量赋值给default所以可以直接将值写在后面;
    export default 42 //正确;但是直接export 42就是错误;
    上面的代码中export default a其实是将a 赋值给default;所以最后一种语法报错;
    所以本质上export dafault 是将变量赋值给default所以可以直接将值写在后面;
    

四 数据请求ES6 promise和ES7 asyc...await

  1. 原始异步请求(回调地狱)

    $.ajax({
       url: '',
    dataType:'json',
       success: function(data) {
        // 获取data数据 传给下一个请求
        var id = data.id;
        $.ajax({
            url:'',
            data:{"id":id},
            success:function(){
                // .....
            }
        });
      }
    });
    
  1. promise
var ajaxPromise = new Promise(function(resolve){
    resolve();
});
ajaxPromise.then(function(){
    $.ajax({
        url:'',
        dataType:'json',
        success: function(data) {
            var id = data.id;
            return id;
        }
    })
}).then(function(id){
    $.ajax({
        url:'',
        dataType:'json',
        data:{"id":id},
        success: function(data){
            console.log(data);
        }
    })
});

// 定义
function testPromise(ready) {
    return new Promise(function(resolve,reject){
        if(ready) {
            resolve("hello world");
        }else {
            reject("No thanks");
        }
    });
};
// 方法调用
testPromise(true).then(function(msg){
    console.log(msg);
},function(error){
    console.log(error);
});

// Promise.all Promise.all可以接受一个元素为Promise对象的数组作为参数,当这个数组里面所有的promise对象都变为resolve时,该方法才会返回。
var promise1 = new Promise(function(resolve){
    setTimeout(function(){
        resolve(1);
    },3000);
});
var promise2 = new Promise(function(resolve){
    setTimeout(function(){
        resolve(2);
    },1000);
});
Promise.all([promise1,promise2]).then(function(value){
    console.log(value); // 打印[1,2]
});

// Promise.race
// `delay`毫秒后执行resolve
function timerPromise(delay){
    return new Promise(function(resolve){
        setTimeout(function(){
            resolve(delay);
        },delay);
    });
}
// 任何一个promise变为resolve或reject 的话程序就停止运行
Promise.race([
    timerPromise(1),
    timerPromise(32),
    timerPromise(64),
    timerPromise(128)
]).then(function (value) {
    console.log(value);    // => 1
});
111.png
  1. asyc 用同步的方式来写异步
function doubleAfter2seconds(num) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(2 * num)
        }, 2000);
    })
}

async function testResult () {
    console.log('内部调用前') // 2
    let result = await doubleAfter2seconds(30);
    console.log(result); // 4
    console.log('内部调用后') // 5
}

console.log('外部调用前') // 1
testResult();
console.log('外部调用后') // 3

// --- 依次输出
// 外部调用前
// 内部调用前
// 外部调用后
// --- 2s 之后输出
// 60
// 内部调用后

分析一下上面的执行顺序:
1、首先打印输出外部调用前,同步代码,顺序执行。
2、然后调用方法testResult(),打印输出内部调用前,同步代码,顺序执行。
3、再执行异步方法doubleAfter2seconds,
 1>如果没用await关键字,此后的执行顺序应该是
  内部调用后,外部调用后,2s 之后输出60
  因为异步方法不阻塞其他代码的执行,最后再输出60
 2>这里使用了await关键字,所以到这里后会等待异步返回结果,再往下执行。
4、当testResult函数内部await阻塞执行后,不会影响到testResult函数外面

async 函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个 Promise 对象中异步执行。

所以,在调用testResult函数后,会继续向下执行,打印输出外部调用后
5、当2s之后,异步函数doubleAfter2seconds执行完成,返回结果,
打印输出60
6、因为await将异步变成同步,所以在输出60后,同步执行,再输出内部调用后
222.png
333.png

五 ES6新技巧

1. 解构赋值

数组的解构

// 基本
let [a, b, c] = [1, 2, 3];
// a = 1
// b = 2
// c = 3

// 可忽略
let [a, , b] = [1, 2, 3];
// a = 1
// b = 3

// 嵌套解构
let [a, [[b], c]] = [1, [[2], 3]];
// a = 1
// b = 2
// c = 3

// 字符串解构
let [a, b, c, d, e] = 'hello';
// a = 'h'
// b = 'e'
// c = 'l'
// d = 'l'
// e = 'o'

对象的解构

// 基本
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
// foo = 'aaa'
// bar = 'bbb'

// 可嵌套可忽略
let obj = {p: ['hello', {y: 'world'}] };
let {p: [x, {  }] } = obj;
// x = 'hello'

// 不完全解构
let obj = {p: [{y: 'world'}] };
let {p: [{ y }, x ] } = obj;
// x = undefined
// y = 'world'

// 剩余运算符
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40};
// a = 10
// b = 20
// rest = {c: 30, d: 40}

2.模板字符串

// 包含普通变量
let w = 'World'
console.log(`Hello ${w}`)

// 包含函数
function fn() {
  return "Hello World";
}
`foo ${fn()} bar`

六 总结

ES6是对ES5功能的简化和扩展,es6的功能es5内的函数都可以实现。但是掌握了es6会在开发过程中让代码更加清晰和整洁。是需要掌握的一项技能。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351