ECMAScript6 新特性整理

AdelaCadle 2年前
   <p>ECMAScript6(ECMAScript 2015 ,ES5,ES2016)技术已经在前端圈子很流行了,他给前端开发人员带来了很多惊喜,提供的语法糖使复杂的操作变得简单。</p>    <p>本文没有详细描述这些新特性,因为网上都已经有很多相关的介绍了。主要针对ES6 新特性收集了相关范例代码,他可以让你快速了解这个新的javascript规范。</p>    <h3>箭头函数</h3>    <p>function() 函数的简写表示法,但它不绑定 this。</p>    <p>ES6 代码:</p>    <pre>  <code class="language-javascript">var odds = evens.map(v => v + 1);  // no parentes and no brackets  var nums = evens.map((v, i) => v + i);  var pairs = evens.map(v => ({even: v, odd: v + 1}));     // Statement bodies  nums.forEach(v => {    if (v % 5 === 0)      fives.push(v);  });</code></pre>    <h3>this 是如何工作的?</h3>    <p>ES6 代码:</p>    <pre>  <code class="language-javascript">var object = {      name: "Name",       arrowGetName: () => this.name,      regularGetName: function() { return this.name },      arrowGetThis: () => this,      regularGetThis: function() { return this }  }  console.log(object);  console.log(object.name)  console.log(object.arrowGetName());  console.log(object.arrowGetThis());  console.log(this);  console.log(object.regularGetName());  console.log(object.regularGetThis());</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">console.log(object);  =>  Object {      name: "Name",      arrowGetName: function,      regularGetName: function,      arrowGetThis: function,      regularGetThis: function  }    console.log(object.name) =>   Name    console.log(object.arrowGetName());  =>  undefined    console.log(object.arrowGetThis());  =>  [object Window]   Window {      stop: function,      open: function,      alert: function,      confirm: function,      prompt: function,      ...  }    console.log(this);  => 同上    console.log(object.regularGetName());   =>  Name    console.log(object.regularGetThis());  =>  Object {      name: "Name",      arrowGetName: function,      regularGetName: function,      arrowGetThis: function,      regularGetThis: function  }</code></pre>    <h3>我们知道“真正”语言中的类(Classes)。在 ES6 中类(Classes)其实是原型继承的语法糖。</h3>    <p>ES6 代码:</p>    <pre>  <code class="language-javascript">class SkinnedMesh extends THREE.Mesh {    constructor(geometry, materials) {      super(geometry, materials);         this.idMatrix = SkinnedMesh.defaultMatrix();      this.bones = [];      this.boneMatrices = [];      //...    }    update(camera) {      //...      super.update();    }    get boneCount() {      return this.bones.length;    }    set matrixType(matrixType) {      this.idMatrix = SkinnedMesh[matrixType]();    }    static defaultMatrix() {      return new THREE.Matrix4();    }  }</code></pre>    <h3>增强的对象字面量</h3>    <p>ES6 代码:</p>    <pre>  <code class="language-javascript">var theProtoObj = {    toString: function() {      return "The ProtoOBject To string"    }  }  var handler = () => "handler"  var obj = {      // __proto__      __proto__: theProtoObj,      // Shorthand for ‘handler: handler’      handler,      // Methods      toString() {       // Super calls       return "d " + super.toString();      },      // Computed (dynamic) property names      [ "prop_" + (() => 42)() ]: 42  };     console.log(obj.handler)  console.log(obj.handler())  console.log(obj.toString())  console.log(obj.prop_42)</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">obj.handler -> () => "handler"  obj.handler() -> handler  obj.toString() -> d The ProtoOBject To string  obj.prop_42 ->   (() => 42)()  是一个立即执行函数 (() => 42)() 相当于  (function() {      return 42;  })()  42</code></pre>    <h3>字符串插值</h3>    <pre>  <code class="language-javascript">var name = "Bob", time = "today";     var multiLine = `This Line Spans Multiple Lines`;     console.log(`Hello ${name},how are you ${time}?`)  console.log(multiLine)</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">Hello ${name},how are you ${time}?` -> Hello Bob,how are you today?  multiLine -> This Line Spans Multiple Lines</code></pre>    <h3>解构 Destructuring</h3>    <pre>  <code class="language-javascript">// list "matching"  var [a, , b] = [1,2,3];  console.log(a);  console.log(b);</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">a -> 1  b -> 3</code></pre>    <p>对象也能很好的解构</p>    <pre>  <code class="language-javascript">nodes = () => { return {op: "a", lhs: "b", rhs: "c"}}  var { op: a, lhs: b , rhs: c } = nodes()  console.log(a)  console.log(b)  console.log(c)</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">a -> a  b -> b  c -> c</code></pre>    <h3>使用速记表示法。</h3>    <pre>  <code class="language-javascript">nodes = () => { return {lhs: "a", op: "b", rhs: "c"}}     // binds `op`, `lhs` and `rhs` in scope  var {op, lhs, rhs} = nodes()     console.log(op)  console.log(lhs)  console.log(rhs)</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">op -> b  lhs -> a  rhs -> c</code></pre>    <h3>可在参数位置使用</h3>    <pre>  <code class="language-javascript">function g({name: x}) {    return x  }     function m({name}) {    return name  }     console.log(g({name: 5}))  console.log(m({name: 5}))</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">g({name: 5}) -> 5  m({name: 5}) -> 5</code></pre>    <h3>故障弱化解构</h3>    <pre>  <code class="language-javascript">var [a] = []  var [b = 1] = []  var c = [];  console.log(a)  console.log(b);  console.log(c);</code></pre>    <h3>结果:</h3>    <pre>  <code class="language-javascript">a -> undefined  b -> 1  c -> []</code></pre>    <h3>参数默认值(Default)</h3>    <pre>  <code class="language-javascript">function f(x, y=12) {    return x + y;  }     console.log(f(3))  console.log(f(3,2))</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">f(3) -> 15  f(3,2) -> 5</code></pre>    <h3>扩展(Spread)</h3>    <p>在函数中:</p>    <pre>  <code class="language-javascript">function f(x, y, z) {    return x + y + z;  }  // 传递数组的每个元素作为参数  console.log(f(...[1,2,3]))</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">f(...[1,2,3]) -> 6</code></pre>    <h3>在数组中:</h3>    <pre>  <code class="language-javascript">var parts = ["shoulders", "knees"];  var lyrics = ["head", ...parts, "and", "toes"];      console.log(lyrics)</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">lyrics -> ["head","shoulders","knees","and","toes"]</code></pre>    <h3>扩展 + 对象字面量</h3>    <p>我们可以使用这个创造很酷的对象。</p>    <pre>  <code class="language-javascript">let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };  console.log(x); // 1  console.log(y); // 2  console.log(z); // { a: 3, b: 4 }     // Spread properties  let n = { x, y, ...z };  console.log(n); // { x: 1, y: 2, a: 3, b: 4 }  console.log(obj)  可惜的是它还不支持:    npm install --save-dev babel-plugin-transform-object-rest-spread</code></pre>    <h3>Rest</h3>    <p>我们可以使用 rest 操作符来允许无限参数。</p>    <pre>  <code class="language-javascript">function demo(part1, ...part2) {      return {part1, part2}  }     console.log(demo(1,2,3,4,5,6))</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">demo(1,2,3,4,5,6) -> {"part1":1,"part2":[2,3,4,5,6]}</code></pre>    <h3>Let</h3>    <p>let是新的var。 因为它有块级作用域。</p>    <pre>  <code class="language-javascript">{     var globalVar = "from demo1"  }     {     let globalLet = "from demo2";  }     console.log(globalVar)  console.log(globalLet)</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">globalVar -> from demo1  globalLet -> ReferenceError: globalLet is not defined</code></pre>    <p>但是,它不会向window分配任何内容:</p>    <pre>  <code class="language-javascript">let me = "go";  // 全局作用域  var i = "able"; // 全局作用域     console.log(window.me);   console.log(window.i);</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">window.me -> undefined  window.i -> able</code></pre>    <p>不能使用let重新声明一个变量:</p>    <pre>  <code class="language-javascript">let me = "foo";  let me = "bar";   console.log(me);</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">SyntaxError: Identifier 'me' has already been declared</code></pre>    <pre>  <code class="language-javascript">var me = "foo";  var me = "bar";   console.log(me)</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">me -> bar</code></pre>    <h3>Const</h3>    <p>const 是只读变量。</p>    <pre>  <code class="language-javascript">const a = "b"  a = "a"</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">TypeError: Assignment to constant variable.</code></pre>    <p>应该注意,const 对象仍然可以被改变的。</p>    <pre>  <code class="language-javascript">const a = { a: "a" }  a.a = "b"  console.log(a)</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">a -> {"a":"b"}</code></pre>    <h3>For..of</h3>    <p>迭代器的新类型,可以替代for..in。 <strong>它返回的是值而不是keys</strong> 。</p>    <pre>  <code class="language-javascript">let list = [4, 5, 6];  console.log(list)  for (let i in list) {     console.log(i);  }</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">list -> [4,5,6]  i -> 0  i -> 1  i -> 2</code></pre>    <pre>  <code class="language-javascript">let list = [4, 5, 6];  console.log(list)  for (let i of list) {     console.log(i);   }</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">list -> [4,5,6]  i -> 4  i -> 5  i -> 6</code></pre>    <h3>迭代器(Iterators)</h3>    <p>迭代器是一个比数组更动态的类型。</p>    <pre>  <code class="language-javascript">let infinite = {    [Symbol.iterator]() {      let c = 0;      return {        next() {          c++;          return { done: false, value: c }        }      }    }  }     console.log("start");     for (var n of infinite) {    // truncate the sequence at 1000    if (n > 10)      break;    console.log(n);  }</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">"start" -> start  n -> 1  n -> 2  n -> 3  n -> 4  n -> 5  n -> 6  n -> 7  n -> 8  n -> 9  n -> 10</code></pre>    <p>使用Typescript,我们可以看到它接口的样子:</p>    <pre>  <code class="language-javascript">Typescript 代码:  interface IteratorResult {    done: boolean;    value: any;  }  interface Iterator {    next(): IteratorResult;  }  interface Iterable {    [Symbol.iterator](): Iterator  }</code></pre>    <h3>生成器(Generators)</h3>    <p>生成器创建迭代器,并且比迭代器更具动态性。他们不必以相同的方式跟踪状态 并不支持 done 的概念。</p>    <pre>  <code class="language-javascript">var infinity = {    [Symbol.iterator]: function*() {      var c = 1;      for (;;) {           yield c++;      }    }  }     console.log("start")  for (var n of infinity) {    // truncate the sequence at 1000    if (n > 10)      break;    console.log(n);  }</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">"start" -> start  n -> 1  n -> 2  n -> 3  n -> 4  n -> 5  n -> 6  n -> 7  n -> 8  n -> 9  n -> 10</code></pre>    <p>使用Typescript 再次显示接口:</p>    <p>Typescript 代码:</p>    <pre>  <code class="language-javascript">interface Generator extends Iterator {      next(value?: any): IteratorResult;      throw(exception: any);  }</code></pre>    <h3>function* Iterators and generator</h3>    <p>一个产量的例子*</p>    <pre>  <code class="language-javascript">function* anotherGenerator(i) {    yield i + 1;    yield i + 2;    yield i + 3;  }     function* generator(i) {    yield i;    yield* anotherGenerator(i);    yield i + 10;  }     var gen = generator(10);     console.log(gen.next().value);   console.log(gen.next().value);   console.log(gen.next().value);   console.log(gen.next().value);   console.log(gen.next().value);</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">gen.next().value -> 10  gen.next().value -> 11  gen.next().value -> 12  gen.next().value -> 13  gen.next().value -> 20</code></pre>    <h3>Unicode</h3>    <p>ES6 为Unicode 提供了更好的支持。</p>    <pre>  <code class="language-javascript">var regex = new RegExp('\u{61}', 'u');     console.log(regex.unicode)  console.log("\uD842\uDFD7")  console.log("\uD842\uDFD7".codePointAt())</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">regex.unicode -> true  "" ->   "".codePointAt() -> 134103</code></pre>    <h3>模块和模块加载器</h3>    <p>原生支持模块。</p>    <pre>  <code class="language-javascript">import defaultMember from "module-name";  import * as name from "module-name";  import { member } from "module-name";  import { member as alias } from "module-name";  import { member1 , member2 } from "module-name";  import { member1 , member2 as alias2 , [...] } from "module-name";  import defaultMember, { member [ , [...] ] } from "module-name";  import defaultMember, * as name from "module-name";  import "module-name";</code></pre>    <pre>  <code class="language-javascript">export { name1, name2, …, nameN };  export { variable1 as name1, variable2 as name2, …, nameN };  export let name1, name2, …, nameN; // also var  export let name1 = …, name2 = …, …, nameN; // also var, const     export expression;  export default expression;  export default function (…) { … } // also class, function*  export default function name1(…) { … } // also class, function*  export { name1 as default, … };     export * from …;  export { name1, name2, …, nameN } from …;  export { import1 as name1, import2 as name2, …, nameN } from …;  Import Export</code></pre>    <h3>Set</h3>    <p>Set 为数学对应,其中所有项目都是唯一的。对于知道SQL的人来说,这相当于distinct。</p>    <pre>  <code class="language-javascript">var set = new Set();  set.add("Potato").add("Tomato").add("Tomato");  console.log(set.size)  console.log(set.has("Tomato"))     for(var item of set) {     console.log(item)  }</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">set.size -> 2  set.has("Tomato") -> true  item -> Potato  item -> Tomato</code></pre>    <h3>WeakSet</h3>    <p>WeakSet对象允许您在集合中存储弱持有的对象。没有引用的对象将被垃圾回收。</p>    <pre>  <code class="language-javascript">var item = { a:"Potato"}  var set = new WeakSet();  set.add({ a:"Potato"}).add(item).add({ a:"Tomato"}).add({ a:"Tomato"});  console.log(set.size)  console.log(set.has({a:"Tomato"}))  console.log(set.has(item))     for(let item of set) {     console.log(item)  }</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">set.size -> undefined  set.has({a:"Tomato"}) -> false  set.has(item) -> true  TypeError: set[Symbol.iterator] is not a function</code></pre>    <h3>Map</h3>    <p>Map 也称为词典。</p>    <pre>  <code class="language-javascript">var map = new Map();  map.set("Potato", 12);  map.set("Tomato", 34);     console.log(map.get("Potato"))        for(let item of map) {     console.log(item)  }        for(let item in map) {     console.log(item)  }</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">map.get("Potato") -> 12  item -> ["Potato",12]  item -> ["Tomato",34]</code></pre>    <p>可以使用除字符串之外的其他类型。</p>    <pre>  <code class="language-javascript">var map = new Map();  var key = {a: "a"}  map.set(key, 12);    console.log(map.get(key))  console.log(map.get({a: "a"}))</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">map.get(key) -> 12  map.get({a: "a"}) -> undefined</code></pre>    <h3>WeakMap</h3>    <p>使用键的对象,并且只保留对键的弱引用。</p>    <pre>  <code class="language-javascript">var wm = new WeakMap();    var o1  = {}  var o2  = {}  var o3  = {}  wm.set(o1, 1);  wm.set(o2, 2);  wm.set(o3, {a: "a"});  wm.set({}, 4);     console.log(wm.get(o2));  console.log(wm.has({}))     delete o2;     console.log(wm.get(o3));     for(let item in wm) {     console.log(item)  }        for(let item of wm) {     console.log(item)  }</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">wm.get(o2) -> 2  wm.has({}) -> false  wm.get(o3) -> {"a":"a"}  TypeError: wm[Symbol.iterator] is not a function</code></pre>    <h3>代理(Proxy)</h3>    <p>代理可以用来改变对象的行为。 它们允许我们定义 trap 。</p>    <pre>  <code class="language-javascript">var obj = function ProfanityGenerator() {      return {         words: "Horrible words"          }  }()     var handler = function CensoringHandler() {          return {          get: function (target, key) {              return target[key].replace("Horrible", "Nice");          },      }     }()     var proxy = new Proxy(obj, handler);     console.log(proxy.words);</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">proxy.words -> Nice words</code></pre>    <h3>提供以下 trap :</h3>    <pre>  <code class="language-javascript">var handler =  {    get:...,    set:...,    has:...,    deleteProperty:...,    apply:...,    construct:...,    getOwnPropertyDescriptor:...,    defineProperty:...,    getPrototypeOf:...,    setPrototypeOf:...,    enumerate:...,    ownKeys:...,    preventExtensions:...,    isExtensible:...  }</code></pre>    <p>Symbols 是一个新类型。 可用于创建匿名属性。</p>    <pre>  <code class="language-javascript">var typeSymbol = Symbol("type");     class Pet {       constructor(type) {         this[typeSymbol] = type;       }    getType() {       return this[typeSymbol];    }     }        var a = new Pet("dog");  console.log(a.getType());  console.log(Object.getOwnPropertyNames(a))        console.log(Symbol("a") === Symbol("a"))</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">a.getType() -> dog  Object.getOwnPropertyNames(a) -> []  Symbol("a") === Symbol("a") -> false</code></pre>    <h3>可继承内置函数</h3>    <p>我们现在可以继承原生类。</p>    <pre>  <code class="language-javascript">class CustomArray extends Array {     }     var a = new CustomArray();     a[0] = 2  console.log(a[0])</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">a[0] -> 2</code></pre>    <h3>不能使用数组的代理(Proxy)来覆盖getter函数。</h3>    <h3>新类库</h3>    <h3>各种新的方法和常量</h3>    <pre>  <code class="language-javascript">console.log(Number.EPSILON)  console.log(Number.isInteger(Infinity))  console.log(Number.isNaN("NaN"))     console.log(Math.acosh(3))  console.log(Math.hypot(3, 4))  console.log(Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2))     console.log("abcde".includes("cd") )  console.log("abc".repeat(3) )        console.log(Array.of(1, 2, 3) )  console.log([0, 0, 0].fill(7, 1) )  console.log([1, 2, 3].find(x => x == 3) )  console.log([1, 2, 3].findIndex(x => x == 2))   console.log([1, 2, 3, 4, 5].copyWithin(3, 0))   console.log(["a", "b", "c"].entries() )  console.log(["a", "b", "c"].keys() )  console.log(["a", "b", "c"].values() )     console.log(Object.assign({}, { origin: new Point(0,0) }))</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">Number.EPSILON -> 2.220446049250313e-16  Number.isInteger(Infinity) -> false  Number.isNaN("NaN") -> false  Math.acosh(3) -> 1.7627471740390859  Math.hypot(3, 4) -> 5  Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) -> 2  "abcde".includes("cd") -> true  "abc".repeat(3) -> abcabcabc  Array.of(1, 2, 3) -> [1,2,3]  [0, 0, 0].fill(7, 1) -> [0,7,7]  [1, 2, 3].find(x => x == 3) -> 3  [1, 2, 3].findIndex(x => x == 2) -> 1  [1, 2, 3, 4, 5].copyWithin(3, 0) -> [1,2,3,1,2]  ["a", "b", "c"].entries() -> {}  ["a", "b", "c"].keys() -> {}  ["a", "b", "c"].values() -> TypeError: ["a","b","c"].values is not a function  Object.assign({}, { origin: new Point(0,0) }) -> ReferenceError: Point is not defined  文档: Number, Math, Array.from, Array.of, Array.prototype.copyWithin, Object.assign</code></pre>    <h3>二进制和八进制</h3>    <p>二进制和八进制数字的字面量。</p>    <pre>  <code class="language-javascript">console.log(0b11111)  console.log(0o2342)     console.log(0xff); // also in es5</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">ES6 代码:  0b11111 -> 31  0o2342 -> 1250  0xff -> 255</code></pre>    <h3>Promises</h3>    <p>异步编程。</p>    <pre>  <code class="language-javascript">var p1 = new Promise((resolve, reject) => {    setTimeout(() => resolve("1"), 101)  })  var p2 = new Promise((resolve, reject) => {    setTimeout(() => resolve("2"), 100)  })     Promise.race([p1, p2]).then((res) => {     console.log(res)  })     Promise.all([p1, p2]).then((res) => {     console.log(res)  })</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">res -> 2  res -> ["1","2"]</code></pre>    <h3>快速的 Promise</h3>    <pre>  <code class="language-javascript">var p1 = Promise.resolve("1")  var p2 = Promise.reject("2")     Promise.race([p1, p2]).then((res) => {     console.log(res)  })</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">res -> 1</code></pre>    <h3>快速失败</h3>    <p>如果一个 promise 失败,all和race也将 reject(拒绝)。</p>    <pre>  <code class="language-javascript">var p1 = new Promise((resolve, reject) => {    setTimeout(() => resolve("1"), 1001)  })  var p2 = new Promise((resolve, reject) => {    setTimeout(() => reject("2"), 1)  })     Promise.race([p1, p2]).then((res) => {     console.log("success" + res)  }, res => {     console.log("error " + res)  })     Promise.all([p1, p2]).then((res) => {     console.log("success" + res)  }, res => {     console.log("error " + res)  })</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">"error " + res -> error 2  "error " + res -> error 2</code></pre>    <h3>反射(Reflect)</h3>    <p>新类型的元编程与新的API现有的还有一些新的方法。</p>    <pre>  <code class="language-javascript">var z = {w: "Super Hello"}  var y = {x: "hello", __proto__: z};     console.log(Reflect.getOwnPropertyDescriptor(y, "x"));  console.log(Reflect.has(y, "w"));  console.log(Reflect.ownKeys(y, "w"));     console.log(Reflect.has(y, "x"));  console.log(Reflect.deleteProperty(y,"x"))  console.log(Reflect.has(y, "x"));</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">Reflect.getOwnPropertyDescriptor(y, "x") -> {"value":"hello","writable":true,"enumerable":true,"configurable":true}  Reflect.has(y, "w") -> true  Reflect.ownKeys(y, "w") -> ["x"]  Reflect.has(y, "x") -> true  Reflect.deleteProperty(y,"x") -> true  Reflect.has(y, "x") -> false</code></pre>    <h3>尾调用(Tail Call)优化</h3>    <p>尾调用的概念非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。</p>    <p>ES6可以确保尾调用不会造成堆栈溢出。 (不是所有的实现工作)。</p>    <pre>  <code class="language-javascript">function factorial(n, acc = 1) {      if (n <= 1) return acc;       return factorial(n - 1, n * acc);  }  console.log(factorial(10))  console.log(factorial(100))  console.log(factorial(1000))  console.log(factorial(10000))  console.log(factorial(100000))  console.log(factorial(1000000))</code></pre>    <p>结果:</p>    <pre>  <code class="language-javascript">factorial(10) -> 3628800  factorial(100) -> 9.332621544394418e+157  factorial(1000) -> Infinity  factorial(10000) -> Infinity  factorial(100000) -> RangeError: Maximum call stack size exceeded  factorial(1000000) -> RangeError: Maximum call stack size exceeded</code></pre>    <p> </p>    <p>来自:http://www.cnblogs.com/raocheng/articles/6614133.html</p>    <p> </p>