ES6中的新特性

本人最近学习es6一些方法,难免有些手痒,想着能不能将这些方法总结下,如下

1、数组的扩展

1)首先什么是伪数组

无法直接调用数组方法或期望length属性有什么特殊的行为,但仍可以对真正数组遍历方法来遍历它们,例如:函数的argument参数,调用getElementsByTagName,document.childNodes等等

2、函数扩展

document.querySelectorAll('元素') 相当于 document.getElementsByTagName('元素') 一样 

合并数组

// 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' ]

 字符串

es6默认都是属于严格模式下,“...”为扩展运算符

let str = 'x\uD83D\uDE80y';
str.split('').reverse().join('')
// 'y\uDE80\uD83Dx'
[...str].reverse().join('')
// 'y\uD83D\uDE80x'

name属性

函数的name属性,返回该函数的函数名。

function fn() {}
fn.name // "fn"

箭头函数

// 嵌套的箭头函数
function insert(value) { return {into: function (array) { return {after: function (afterValue) { array.splice(array.indexOf(afterValue) + 1, 0, value); return array; }}; }}; } insert(2).into([1, 3]).after(1); //[1, 2, 3] // 使用箭头函数 let insert = (value) => ({into: (array) => ({after: (afterValue) => { array.splice(array.indexOf(afterValue) + 1, 0, value); return array; }})}); insert(2).into([1, 3]).after(1); //[1, 2, 3]

现在问题来了,什么是链式调用?

解答:其实,上面的代码可以说是一种链式调用,使用面向对象写,里面写几个方法,就像如下代码一样,jquery中ajax使用promise一样,将异步用同步流程表达出来。

var Lianshi = function(){ }
Lianshi.prototype = {
       css:function(){
             console.log("设置css样式");
              return this;  
       },
       show:function(){
               console.log("将元素显示");
               return this;
       },
       hide:function(){
              console.log("将元素隐藏");
       }
  };
var lianshi = new Lianshi();
lianshi.css().css().show().hide();

箭头函数注意的四点:

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

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

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

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

 绑定this

箭头函数可以绑定this,显示绑定this的写法(call、apply、bing),call、apply的作用就是能够改变this的指向

递归函数

// 斐波拉切数列 也是递归的一种  传的值过大,容易造成堆栈溢出 内存泄漏
function Fibonacci (n) {
  if ( n <= 1 ) {return 1};
  return Fibonacci(n - 1) + Fibonacci(n - 2);
}

Fibonacci(10); // 89
// 尾调递归  
function
factorial(n, total = 1) { if (n === 1) return total; return factorial(n - 1, n * total); } factorial(5) // 120

只要在严格模式下,才能使尾调递归函数优化,(由于递归就是使用栈太多,造成溢出,想要优化,就只能减少栈的使用,故使用循环来进行递归)

额外说点:造成内存泄漏的原因:1)使用了递归; 2)使用了小数点,如:0.0000000001;3)setTimeout第一个参数是字符串

// 优化尾调递归函数
function trampoline(f) {
  while (f && f instanceof Function) {
    f = f();
  }
  return f;
}
function sum(x, y) {
  if (y > 0) {
    return sum.bind(null, x + 1, y - 1);
  } else {
    return x;
  }
}
trampoline(sum(1, 100000))
// 100001
// 使用蹦床函数也可以优化尾调函数
function tco(f) {
  var value;
  var active = false;
  var accumulated = [];

  return function accumulator() {
    accumulated.push(arguments);
    if (!active) {
      active = true;
      while (accumulated.length) {
        value = f.apply(this, accumulated.shift());
      }
      active = false;
      return value;
    }
  };
}

var sum = tco(function(x, y) {
  if (y > 0) {
    return sum(x + 1, y - 1)
  }
  else {
    return x
  }
});

sum(1, 100000)
// 100001

原理:tco函数是尾递归优化的实现,它的奥妙就在于状态变量active。默认情况下,这个变量是不激活的。一旦进入尾递归优化的过程,这个变量就激活了。然后,每一轮递归sum返回的都是undefined,所以就避免了递归执行;而accumulated数组存放每一轮sum执行的参数,总是有值的,这就保证了accumulator函数内部的while循环总是会执行。这样就很巧妙地将“递归”改成了“循环”,而后一轮的参数会取代前一轮的参数,保证了调用栈只有一层。

额外说点:

继承:原型继承、原型链继承、call/apply继承

ES6 模块之中,顶层的this指向undefined,即不应该在顶层代码使用this

import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。

require是运行时加载模块,import命令无法取代require的动态加载功能。

importexport命令只能在模块的顶层,不能在代码块之中(比如,在if代码块之中,或在函数之中)。

posted @ 2017-04-07 20:59  shirleyYing  阅读(402)  评论(0编辑  收藏  举报