ECMAScript 6入门(2)

上篇文章我们介绍了ES6的多行字符串表示方法,map,set,for...of循环,rest参数以及let和const,这次我们接着来看看ES6有哪些过人之处。

ECMAScript 6为数组增添的新方法:map(),reduce(),filter()

①map()

语法:arr.map(函数);

功能:相当于让arr的每个数据执行了一次()中的方法,例:

function add(a){
    return  b =a*a;
}
var arr = [1,2,3,4];
var newArr = arr.map(add);
console.log( newArr);
image

②reduce()

语法:arr.reduce(函数);

功能:把一个函数作用在arr的每一个元素上,它必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算。例:要把[1,2,3,4,5,6]变换成整数123456,就可以用reduce()做到

function changeNumber(x,y){
      return  x * 10 + y;
 }
var arr = [1,2,3,4,5,6];
var newArr = arr.reduce(changeNumber);
console.log(newArr);

③filter()

语法:arr.filter(函数);

功能:用于把Array的某些元素过滤掉,然后返回剩下的元素,和map()类似,Array的filter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。例:利用filter()删除数组中的偶数项

function deleteOushu(x){
     return x % 2 !== 0;
}
var arr = [1,2,3,4,5,6,7,8,9,10];
var newArr = arr.filter(deleteOushu);
console.log(newArr);
image

filter()接收的回调函数可以有多个参数。第一个参数表示Array的某个元素。另外两个参数,表示元素的位置和数组本身:

var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
    console.log(element); 
    // 依次打印'A', 'B', 'C'
    console.log(index); 
    // 依次打印0, 1, 2
    console.log(self); 
    // self就是变量arr
    return true;
});

我们还可以利用filter()巧妙的去除数组的重复项:

var arr = ["a","b","c","b","a","d"];
var newArr = arr.filter(function(element,index,self){
    return self.indexOf(element)===index;
});
y.png

箭头函数

ES6标准新增了一种新的函数:Arrow Function(箭头函数)

x => x * x;

这个箭头函数等价于

function (x){
    return  x * x ;
}

箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }和return:

x => { 
    if(x>0) {
        return x * x;
    } 
    else{
        return -x * x;
    } 
}; 

如果参数不是一个,就需要用括号()括起来:

(x,y) => x * x + y * y;

无参数时就用():

() => 1;

可变参数:

(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum += rest[i];
    }
    return sum;
}

如果要返回一个对象就要注意,如果是单表达式,这么写的话会报错:

x => { foo: x }    // SyntaxError

因为和函数体的{ ... }有语法冲突,所以要改为:

x => ({ foo: x })

箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj。由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,this取决于箭头函数在哪定义,this不可变,在函数内部这个执行环境中相当于常量。
箭头函数没有arguments,不能通过arguments对象访问传入参数,只能使用显示命名或者其他特性完成。
箭头函数不能使用new关键字来实例化对象,不然会报错。

箭头函数跟普通函数的区别,什么是匿名函数
(1)不需要function
(2)省略return
(3)继承当前上下文的关键字(定义时所在对象)
( 4)不能用作构造函数
(5)不能用yeild
(6)this固有化
(7)不能使用call,apply,bind去改变

匿名函数:没有名字的函数表达式,可以实现动态编程。

generator(生成器)

一个generator看上去像一个函数,但可以返回多次。函数执行过程中,如果没有遇到return语句(函数末尾如果没有return,就是隐含的return undefined;),控制权无法交回被调用的代码。generator跟函数很像,定义如下:

function* foo(x) { 
    yield x + 1;
    yield x + 2;
    return x + 3;
}

和函数不同的是generator由function定义(注意多出的号),并且除了return语句,还可以用yield返回多次。例:编写一个产生斐波那契数列的函数,可以这么写:

function fib(max) {
    var t=0; 
    var a=0;
    var b=1;
    var arr=[0, 1];
    while (arr.length < max) { 
        t = a + b;
        a = b;
        b = t;
        arr.push(t);
    }
    return arr;
}
fib(5);      // 测试结果[0, 1, 1, 2, 3]

函数只能返回一次,必须返回一个Array。generator就可以一次返回一个数,不断返回多次。用generator改写如下:

function* fib(max) {
    var t=0;
    var a=0;
    var b=1;
    var n=1;
    while (n < max) {
        yield a;
        t = a + b;  
        a = b;
        b = t;
        n++;
    }
    return a;
}
fib(5);    // fib{[[GeneratorStatus]]: "suspended",[[GeneratorReceiver]]:Window}

fib(5)仅仅是创建了一个generator对象,还没有去执行它
调用generator对象有两个方法,一是不断地调用next()方法:

var f = fib(5);
f.next();    // {value: 0, done: false}
f.next();    // {value: 1, done: false}
f.next();    // {value: 1, done: false}
f.next();    // {value: 2, done: false}
f.next();    // {value: 3, done: true}

value就是yield的返回值,done表示这个generator是否已经执行结束了。为true时value就是return的返回值,并且generator对象就已经全部执行完毕,不要再继续调用next()了。
第二个方法是直接用for ... of循环迭代generator对象,这种方式不需要我们自己判断done:

for (var x of fib(5)) {
    console.log(x);    // 依次输出0, 1, 1, 2, 3
}       

class继承

继承中我们看到了JavaScript的对象模型是基于原型实现的,特点是简单,缺点是理解起来比传统的类-实例模型要困难,最大的缺点是继承的实现需要编写大量代码,并且需要正确实现原型链。新的关键字class从ES6开始正式被引入到JavaScript中。class的目的就是让定义类更简单。
我们先回顾用函数实现Student的方法:

function Student(name) {
    this.name = name;
} 
Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
}

如果用新的class关键字来编写Student,可以这样写:

class Student {
    constructor(name) {
        this.name = name;
    } 
    hello() {
        alert('Hello, ' + this.name + '!');
    }
}

比较一下就可以发现,class的定义包含了构造函数constructor和定义在原型对象上的函数hello()(注意没有function关键字),这样就避免了Student.prototype.hello = function () {...}这样分散的代码。
最后,创建一个Student对象

var xiaoming = new Student('小明'); 
xiaoming.hello();

用class定义对象的另一个巨大的好处是继承更方便了。想一想我们从Student派生一个PrimaryStudent需要编写的代码量。现在,原型继承的中间对象,原型对象的构造函数等等都不需要考虑了,直接通过extends来实现:

class PrimaryStudent extends Student { 
    constructor(name, grade) { 
        super(name); 
        // 记得用super调用父类的构造方法! 
        this.grade = grade; 
    } 
    myGrade() {
    alert('I am at grade ' + this.grade);
    }
}

注意PrimaryStudent的定义也是class关键字实现的,而extends则表示原型链对象来自Student。子类的构造函数可能会与父类不太相同,例如,PrimaryStudent需要name和grade两个参数,并且需要通过super(name)来调用父类的构造函数,否则父类的name属性无法正常初始化。
PrimaryStudent已经自动获得了父类Student的hello方法,我们又在子类中定义了新的myGrade方法。
ES6引入的class和原有的JavaScript原型继承有什么区别呢?实际上它们没有任何区别,class的作用就是让JavaScript引擎去实现原来需要我们自己编写的原型链代码。简而言之,用class的好处就是极大地简化了原型链代码。

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

推荐阅读更多精彩内容

  • 三,字符串扩展 3.1 Unicode表示法 ES6 做出了改进,只要将码点放入大括号,就能正确解读该字符。有了这...
    eastbaby阅读 1,539评论 0 8
  • 本文为阮一峰大神的《ECMAScript 6 入门》的个人版提纯! babel babel负责将JS高级语法转义,...
    Devildi已被占用阅读 1,988评论 0 4
  • 一、let 和 constlet:变量声明, const:只读常量声明(声明的时候赋值)。 let 与 var 的...
    dadage456阅读 763评论 0 0
  • 孩子虽然因你而来,但是并不属于你。今天早晨被《游戏力》第二章带读末尾这样一句近乎残酷的话触动,内心激起千层浪! 孩...
    喀秋莎宝阅读 253评论 0 0
  • 过了两天(真的是两天)“房奴”的生活,晚上挣扎了下把刚到手的工资转到房贷里,夜里醒了还是转了回来。 感受不太好。 ...
    起噫步走阅读 246评论 0 0