欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JavaScript简史和ECMAScript(ES6,ES7,ES8)特性

程序员文章站 2022-06-12 21:40:31
...

我相信理论知识是先于实践的,一直忙于coding而没有去把这方面的知识稳固下,周末抽空看了些文章整理下,希望和大家一起进步。

ECMAScript是JavaScript的一个子集。 JavaScript的核心基本上是ECMAScript,但是基于它。诸如ActionScript,JavaScript,JScript等语言都使用ECMAScript作为其核心。作为比较,AS / JS / JScript类似3种不同的汽车,尽管它们的外观各不相同,并且进行了多次修改以使其独特,但它们都使用相同的引擎......。

历史上,Brendan Eich创建了Mocha,后来成为LiveScript,再后来成为JavaScript。 Netscape向Ecma International展示了JavaScript,后者开发了标准,并将其更名为ECMA-262又名ECMAScript。

另外要注意的,Brendan Eich的“JavaScript”与ECMAScript的方言不一样。他构建了核心语言,该语言被重新命名为ECMAScript,它不同于现在的浏览器供应商实现的JavaScript,下面讲讲javascript为何被创建,以及它如何演变。

Javascript的诞生:

这一切都发生在1995年5月至12月的六个月内。Netscape Communications Corporation在年轻网络中占有重要地位。它的浏览器Netscape Communicator作为第一个流行的网络浏览器NCSA Mosaic的竞争对手而获得了广泛的关注。 Netscape是由90年代初参与马赛克开发的人组成的,现在,他们拥有金钱和独立性,他们有必要*地寻求进一步扩展网络的方法。这正是生成JavaScript的原因。

javascript的历史:

Netscape Communications的创始人,前Mosaic团队的一员Marc Andreessen认为,网络需要一种变得更加活跃的方式。动画,互动和其他形式的小型自动化应该成为未来网络的一部分。因此,网络需要一种可以与DOM交互的小型脚本语言(它并不像现在这样僵硬)。但是,这是当时一个重要的战略要求,这种脚本语言不应该面向那些有着软件工程方面经验的大手笔开发人员和人员。 Java也在增长,Java applet很快就会成为现实。因此,网络的脚本语言需要迎合不同类型的观众:设计师。事实上,网络是静态的。对于非开发人员来说,HTML还很年轻,很简单。因此,非程序员可以访问浏览器中的任何内容,以使Web更具动态性。所以Mocha的想法诞生了。 Mocha成为了网络的脚本语言。对于非开发人员来说,简单,动态并且易于访问。

javascript的实现:

当Sun和Netscape完成交易将Mocha / LiveScript的名称更改为JavaScript时,引发了一个大问题:替代实现会发生什么?事实上,虽然当时Netscape迅速成为首选浏览器,但微软也在开发Internet Explorer。从第一天起,JavaScript在用户体验方面就有了如此巨大的差异,竞争的浏览器别无选择,只能提出一个可行的解决方案,即实现JavaScript的运行。目前(并且很长一段时间),网络标准并不强大。因此,Microsoft实现了他们自己的JavaScript版本,称为JScript。保持名称中的“Java”避免了可能的商标问题。但是,JScript不仅仅是名称上的不同。执行方面的细微差别,特别是某些DOM功能方面的差异,会导致未来多年仍会感受到的涟漪。 JavaScript战争不仅仅是名称和时间表战争,更多的战争只是这些战争的伤口。 JScript的第一个版本包含在1996年8月发布的Internet Explorer 3.0中。

JAVA-like语法

虽然保持语法接近Java不是JavaScript背后的原始想法,但营销力量改变了这一点。回顾过去,虽然对于某些特性来说,不同的语法可能更加方便,但不可否认的是,熟悉的语法很容易帮助JavaScript获得推广。

比较这个Java示例:

public class Sample {
  public static void main(String [] args){
    System.out.println("Hello world!");
    try {
      final MissileSilo silo = new MissileSilo("silo.weapons.mil");
      silo.launchMissile(args[0]);
    } catch(Exception e){
      System.out.println("意外的异常:"+ e);
    }
  }
}

以这个(现代)JavaScript为例:

console.log('Hello world');
try {
  const silo = new MissileSilo('silo.weapons.mil');
  silo.launchMissile(process.argv [0]);
} catch(e){
  console.log('Unexpected exception'+ e);
}

函数是第一类对象

在JavaScript中,函数只是一种对象类型。它们可以像任何其他元素一样传递。它们可以绑定到变量,而在更高版本的JavaScript中,它们甚至可以作为异常引发。此种特性可能是Scheme在JavaScript发展中的强大影响力的结果。

var myFunction = function(){
  的console.log( '你好');
}
otherFunction(myFunction的);
myFunction.property ='1';

通过使函数成为第一类对象,使得某些函数式编程模式成为可能。例如,更高版本的JavaScript使用某些函数式模式:

var a = [1,2,3];
a.forEach(function(e){
  console.log(E);
});

这些模式已被许多库所利用,如下划线和immutable.js。

ECMAScript作为标准:

ECMAScript:

Sun(现在的Oracle)拥有"JavaScript"这个名字的商标(这导致微软称其JavaScript方言为"JScript")。因此,当谈到标准化的语言时,必须使用不同的名称。相反,因为相应的标准由Ecma International托管,选择了"ECMAScript"作为命名。实际上,术语"ECMAScript"和"JavaScript"是可以互换的,可以说前者是后者的方言。术语“ECMAScript”也经常用于表示语言版本(如ECMAScript 5)。

ECMA-262:

Ecma International(一家标准组织)创建了ECMA-262标准,该标准是ECMAScript语言的官方规范。
Ecma的技术委员会39(TC39):是开发ECMA-262标准的一群人(Brendan Eich等人)。

ECMAScript 3(1999年12月)。

这是目前大多数浏览器支持的ECMAScript版本。它引入了许多已成为该语言固有部分的功能:

  • 正则表达式,
  • 更好的字符串处理,
  • 新的控制语句,
  • try / catch异常处理,
  • 更严格的错误定义,
  • 格式化数字输出和其他增强。

ECMAScript 4(2008年7月放弃)。

ECMAScript 4是作为JavaScript的下一个版本开发的,其原型用ML编写。但是,TC39无法就其功能集达成一致。为了防止僵局,委员会于2008年7月底举行会议并达成协议,总结为四点:

  1. 开发ECMAScript的增量更新[成为ECMAScript 5。
  2. 开发一个主要的新版本,比ECMAScript 4更适度,但范围比ECMAScript 3之后的版本大得多。由于会议的性质,该版本的代号为Harmony。
  3. 来自ECMAScript 4的特性将被删除:包,命名空间,前链接。
  4. 其他想法将与TC39的所有内容达成共识。
  • 因此:ECMAScript 4开发者同意让Harmony比ECMAScript 4更加激进,TC39的其余成员同意继续前进。
  • ECMAScript 5(2009年12月)。该版本为标准库带来了一些增强功能,甚至通过严格模式更新了语言语义。
  • 目前浏览器仅支持ES5。

ECMAScript 6(2015)

ES6是JavaScript的下一代,ecma技术委员会39管理ecma规范,他们发现了javascript的新功能。

ES6不能直接在浏览器中编译,因此需要从ES6到ES5的编译器,对于使用babel进行编译,它会产生与浏览器兼容的javascript。

ES6包括以下新功能:

  • 箭头函数
// 表达体
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);
var pairs = evens.map(v => ({even: v, odd: v + 1}));

// 申明体
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});

// 词法 this
var bob = {
  _name: "Bob",
  _friends: [],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
}
  • 类class
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();
  }
}
  • 增强的对象字面量
var obj = {
    // __proto__
    __proto__: theProtoObj,
    // 'handler: handler'缩写
    handler,
    // 方法
    toString() {
     // Super 调用
     return "d " + super.toString();
    },
    // 计算(动态)属性名称
    [ 'prop_' + (() => 42)() ]: 42
};
  • 模板字符串
// 基本字符串字面量创建
`In JavaScript '\n' is a line-feed.`

// 多行字符串
`In JavaScript this is
 not legal.`

// 字符串插值
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// 构建HTTP请求
POST`http://foo.org/bar?a=${a}&b=${b}
     Content-Type: application/json
     X-Credentials: ${credentials}
     { "foo": ${foo},
       "bar": ${bar}}`(myOnReadyStateChangeHandler);
  • 解构
  • 默认值+rest参数+扩展运算符
  • 新的变量申明方式 let + const
  • 迭代器 Iterators + for..of
let fibonacci = {
  [Symbol.iterator]() {
    let pre = 0, cur = 1;
    return {
      next() {
        [pre, cur] = [cur, pre + cur];
        return { done: false, value: cur }
      }
    }
  }
}

for (var n of fibonacci) {
  // truncate the sequence at 1000
  if (n > 1000)
    break;
  console.log(n);
}
  • 生成器Generators
var fibonacci = {
  [Symbol.iterator]: function*() {
    var pre = 0, cur = 1;
    for (;;) {
      var temp = pre;
      pre = cur;
      cur += temp;
      yield cur;
    }
  }
}

for (var n of fibonacci) {
  if (n > 1000)
    break;
  console.log(n);
}
  • Unicode

"????".match(/./u)[0].length == 2

"\u{20BB7}"=="????"=="\uD842\uDFB7"
  • 模块Modules
  • 模块加载器

模块加载器支持:

  • 动态加载
  • 状态隔离
  • 全局命名空间隔离
  • 编译钩子
  • 嵌套虚拟化
// 动态加载 – ‘System’ 是默认加载器
System.import('lib/math').then(function(m) {
  alert("2π = " + m.sum(m.pi, m.pi));
});

// 创建执行沙箱 - 新的加载器
var loader = new Loader({
  global: fixup(window) // 代替 ‘console.log’
});
loader.eval("console.log('hello world!');");

// 直接操作模块缓存
System.get('jquery');
System.set('jquery', Module({$: $})); // WARNING: not yet finalized
  • map + set + weakmap + weakset
// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;

// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;

// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined

// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// 因为添加的对象没有其他引用,所以它不会被保存在集合中
  • 代理Proxies
// 代理一个常规对象
var target = {};
var handler = {
  get: function (receiver, name) {
    return `Hello, ${name}!`;
  }
};

var p = new Proxy(target, handler);
p.world === 'Hello, world!';
// 代理一个函数
var target = function () { return 'I am the target'; };
var handler = {
  apply: function (receiver, ...args) {
    return 'I am the proxy';
  }
};

var p = new Proxy(target, handler);
p() === 'I am the proxy';
  • 符号Symbols
var MyClass = (function() {

  // module scoped symbol
  var key = Symbol("key");

  function MyClass(privateData) {
    this[key] = privateData;
  }

  MyClass.prototype = {
    doStuff: function() {
      ... this[key] ...
    }
  };

  return MyClass;
})();

var c = new MyClass("hello")
c["key"] === undefined
  • 可分类的内置插件
// Array的伪代码
class Array {
    constructor(...args) { /* ... */ }
    static [Symbol.create]() {
        // Install special [[DefineOwnProperty]]
        // to magically update 'length'
    }
}

// Array 的子类
class MyArray extends Array {
    constructor(...args) { super(...args); }
}

// 'new'的两个阶段
// 1) Call @@create to allocate object
// 2) Invoke constructor on new instance
var arr = new MyArray();
arr[1] = 12;
arr.length == 2
  • Math + Number + String + Array + Object APIs
Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false

Math.acosh(3) // 1.762747174039086
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.from(document.querySelectorAll('*')) // Returns a real Array
Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior
[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() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"

Object.assign(Point, { origin: new Point(0,0) })
  • Promises
function timeout(duration = 0) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, duration);
    })
}

var p = timeout(1000).then(() => {
    return timeout(2000);
}).then(() => {
    throw new Error("hmm");
}).catch(err => {
    return Promise.all([timeout(100), timeout(200)]);
})
  • 二进制和八进制字面量
0b111110111 === 503 // true
0o767 === 503 // true
  • Reflect API
  • 尾调用
function factorial(n, acc = 1) {
    'use strict';
    if (n <= 1) return acc;
    return factorial(n - 1, n * acc);
}

// 今天大多数实现中出现堆栈溢出,
// 但在ES6中的任意输入安全
factorial(100000)

ECMAScript 7(2016)

他们决定从2015年开始每年发布一个新版本的ECMAScript。年度更新意味着没有像ES6这样的大版本。

ECMAScript 2016(ES7)仅引入了两个新功能:

  • Array.prototype.includes()
  • 指数运算符

ECMAScript 8(2017)

在2017年1月的TC39会议上,ECMAScript 2017的最后一个功能是“Shared memory and atomics” 。

主要新功能:

次要新功能:

概要:

  1. ECMAScript是JavaScript语言的“标准”。
  2. EcmaScript是JavaScript的“官方”名称。它最终被放弃,ES3.1成为ES5,这是在“HTML5”世界中使用的JavaScript版本。

参考文章