本文翻译JavaScript Versions: How JavaScript has changed over the years
原文写于2020/12/18

文章目录

  • JavaScript版本变迁史
    • JavaScript之前的网站
    • JavaScript的开端
    • JavaScript的各种版本
    • ECMAScript
      • ECMAScript 1-2
      • ES3
      • ES4
      • ES5的更新细节
      • ES6的更新细节
    • 进一步了解JavaScript

JavaScript版本变迁史

  JavaScript是世界上最流行和广泛传播的编程语言之一 (其他几个大概是C, C++, Java, Python) 。这门语言诞生于1995年,之后几经变迁最终以JavaScript的名称而流传于世。

  JavaScript由Brendan Eich创造,在1997年成为一个ECMA标准。ECMAScript是这门语言的官方名称,ECMAScript版本包括ES1, ES2, ES3, ES5, ES6。

ECMA是一个国际标准化组织(Ecma International is an industry association dedicated to the standardization of information and communication systems)。JavaScript符合ECMA制定的ECMAScript标准(或者说ECMAScript就是JavaScript的官方称呼),具体来说符合ECMA-262和ECMA-402两个标准。这两个标准都经过了多次修订,具有多个版本。关于ECMAScript的标准变迁可以查看developer.mozilla.org的说明。

  在2020的末尾我们回顾JavaScript的变迁史,以便更好理解如何使用这门编程语言。我们将介绍

  • JavaScript之前的网站
  • JavaScript早期
  • JavaScript标准化
  • JavaScript的版本
  • ECMAScript5的详细介绍
  • ES6的具体变化
  • 进一步了解JavaScript

JavaScript之前的网站

  在JavaS诞生之前,Web页面是相较今天是非常静态的。列表、日期和链接都在HTML中硬编码,所有种类的动态功能都需要在HTML的head中定义。一个非常著名的仍然运行的非JavaScript的网站是San Francisco FogCam:

  这个网站于1994年创建,以”世界上最古老的网络摄像头“而闻名。这是人类能从网络上看到动态图像的开始。随着时间的流逝,这个网站并没有变。它仍然使用90年代的静态HTML和CSS。网站每20秒刷新一次(通过HTML文档头部的<meta>来实现)。在FogCam创建之时,JavaScript还未正式发行,但是我们已经能看到对于动态加载图片的需要。
  另一个在运行的未使用JavaScript的代表网站是创建于90年代后期参议员Bob Dole’s的总统竞选结果。

  该网站是一个静态网站,它使用HTML路由 (HTML routing) 进行页面之间的跳转。网站的一切都是硬编码的,Netscape Communicator注意到了这个问题并决定创建一种允许动画、表单创建以及其他动态交互的脚本语言。
这便是JavaScript的开始。

JavaScript的开端

  实际上JavaScript一开始叫做Mocha。创建这门语言的初衷在于作为设计师和非程序员使用的高层语言。(译注:这里表述不准确,大概意思是作为易学易用的语言)当Mocha随着Netscape Navigator 2.0被提供时,其名称改为LiveScript,并在之后的版本改为JavaScript(为了蹭Java的热度)。

随Netscape Navigator 2.0发布而首次公开发布的JavaScript

  Netscape与Sun Microsystems(美国一家出售计算机等产品的公司)在创建JavaScript的合作上引领了潮流。随着Netscape在浏览器领域取得了越来越多的成功,其他浏览器也需要提出一些新东西来跟上Netscape。
  由于法律原因,微软创造了他们自己的JavaScript版本并命名为JScript。这些新的语言提升了用户体验和用户与网站之间的交互。随着JScript的创建,微软的Internet explorer浏览器的市场份额逐渐增加。但对于JavaScript来说,这种语言分流使得标准化变得困难。即便如此,由于JavaScript在语法上和Java的相似性,JavaScript在”脚本语言的战争“中成为了赢家,随着Java越来越流行,JavaScript也成长了起来。

Java和JavaScript风马牛不相及。Java是使用虚拟机或者浏览器来执行代码的编译语言;而JavaScript则是面向浏览器的语言(在浏览器之外可以用Node.js来执行js代码)

JavaScript的各种版本

Version Official Name Description
ES1 ECMAScript 1(1997) First edition
ES2 ECMAScript 2 (1998) Editorial changes
ES3 ECMAScript 3 (1999) Added regular expressions & try/catch
ES4 ECMAScript 4 Not released
ES5 ECMAScript 5 (2009) Added "strict mode", JSON support, String.trim(), Array.isArray(), & Array iteration methods
ES6 ECMAScript 2015 Added let and const, default parameter values, Array.find(), & Array.findIndex()
ES6 ECMAScript 2016 Added exponential operator & Array.prototype.includes
ES6 ECMAScript 2017 Added string padding, Object.entries, Object.values, async functions, & shared memory
ES6 ECMAScript 2018 Added rest / spread properties, asynchronous iteration, Promise.finally(), & RegExp

ECMAScript

  Netscape Communicator在1997年向ECMA标准化组织提交了文档。在之后,ECMA结合Netscape的JavaScript和微软的JScript创建了一个标准,将之命名为ECMAScript(这是JavaScript和JScript共同的语言规范)。之所以命名为ECMAScript而非JavaScript的原因是JavaScript被当时的Sun Microsystems公司用作商标(之后的Oracle公司)。

ECMAScript 1-2

  ES1于1997年发行,在后一年ES2发行,两者之间差别不大。

ES3

  ES3于1999年发行,为JavaScript增加了许多新特性,这些特性在今天变成了JavaScript的标准组成部分。

  1. 严格相等: 自从ES3开始,严格相等操作符(===)作为等于操作符(==)的补充被添加到语言中。两者的区别是等于操作符不涉及类型只考虑值,严格相等操作符则与其他强类型语言的等于操作符类似(JavaScript是弱类型语言)

    const compareEypeAndValue = (num, str) => {return num === str;
    }
    console.log(compareTypeAndValue(8, '8')); //false
    console.log(compareTypeAndValue(8, 8)); //true
    
  2. 正则表达式: ES3加入了文字和构造器(literal and constructor)两种正则表达式。
  3. Literal Expressions:文字表达式在两个反斜杠中定义。(详细百度)
    /[^abc]/gim
    
  4. Constructor Expressions:构造器表达式是RegExp类的实例。
    const regex = new RegExp('[^abc]', 'gim');
    
  5. Switch Statement: JavaScript的switch-case-default组合与C语言几乎完全一致。
  6. Try/Catch Handling:try/catch允许你跳出“快速失败”的哲学,在程序运行异常后可以抛出异常且继续运行。
    const isValidKey = (val1) => {try {let obj;return obj.hasOwnProperty(val1);
    } catch (err) {throw new Error("not valid key");
    }
    }
    console.log(isValidKey(""))
    

ES3在发布后的十年内都是标准版本,直到2009年ES5发行

ES4

  TC39是ECMA International的免版税任务组,其主要工作是标准化ECMAScript。当需要更新和发布ES4标准时,任务组无法就规范达成共识。结果,ES4作为一个备受推崇的版本,却从未完全发布为实际标准。

ES5的更新细节

  ES5和ES6是现在为止最后发布的两个版本,这两个版本做出了很多重大的更新。在ES3发行十年后的2009年,ES5发行了,这个新版本是JavaScript创立以来的最大变化。一些新特性包括

  • “use strict”:在ES5之前,未声明变量(未使用var声明的变量)在任何情况下都可用。但自从加入"use strict"特性后,启动该特性会禁止使用未声明变量:

    "use strict"
    x = 5; //ReferenceError: x is not defined
    
  • 新的Array方法:ES5加入了一些新的array(内置类)的方法,这些方法包括
    • every():every方法检查数组中的每个变量是否满足条件

      var arr = [6, 4, 5, 6, 7, 7];
      arr.every(function(element) {return element % 2 === 0; //checks to see if even
      }); // false
      
    • filter():显然这个方法返回满足条件的子数组
      var arr = [6, 4, 5, 6, 7, 7];['
      arr.filter(function(element) {return element/2 > 3;
      })
      
    • forEach():这个方法与for循环很像。对于数组中的每个元素,forEach方法执行一个回调函数。
      var arr = [6, 4, 5, 6, 7, 7];
      arr.forEach(function(element) {console.log(element * 2);
      })
      
    • indexOf() and lastIndexOf():分别返回所查询元素首个和末个的索引
      var arr = [6, 4, 5, 6, 7, 7];
      console.log(arr.indexOf(4)); // 1
      console.log(arr.indexOf(2)); // -1
      console.log(arr.indexOf(7)); // 4
      console.log(arr.lastIndexOf(7)); // 5
      
    • isArray():查看对象是否为array
      var arr = [6, 4, 5, 6, 7, 7];
      var str = "Hello Educative.io";
      console.log(Array.isArray(arr));
      console.log(Array.isArray(str));
      
    • map():map方法和forEach()非常相似,区别是map返回一个新array,因此回调函数需要有返回值
      var arr = 6, 4, 5, 6, 7, 7];
      arr.map(function(element) {return element * 2;
      })
      
    • reduce() and recuceRight():与python的reduce类似,将某个操作连续应用到序列的元素上,累计之前的结果,把一系列值规约成一个值。区别是js的reduce可以指定一个参数作为额外的操作数。
      var arr = [6, 4, 5, 6, 7, 7];
      var reduced = arr.reduce(funciton(curr, next) {return curr + next;
      }, 0); # 0为额外的操作数
      var reducedRight = arr.reducedRight(function(curr, next) {return curr + next;
      }, 0)
      console.log(reduced);
      console.log(redecedRight);
      
    • some():与python的any相似,与arr.every()相反,every考虑是否所有元素满足条件而some考虑是否存在满足的元素。
  • JSON
      解析和字符串化JavaScript Object Notation(JSON)的功能在ES5标准中成为可能。JSON格式用于基本通过网络连接(通常是Web应用程序和API)传输某种结构化数据。当我们从一个应用程序传输数据时,它必须为字符串形式。使用JSON.stringify()将JavaScript对象转换为字符串,然后另一侧使用JSON.parse()将数据传输回JavaScript对象后进行转换。

    var arr = [6, 4, 5, 6, 7, 7];
    var obj = {author: "Christina Kopecky",title: "How to parse JSON objects",published: false
    }
    console.log("======== ARR EXAMPLE ==========");
    console.log("orig arr=====>", arr);
    console.log("stringified arr=====>", JSON.stringify(arr));
    console.log("proof of type=====>", typeof JSON.stringify(arr));
    console.log("parsed string=====>", JSON.parse(JSON.stringify(arr)));
    console.log("proof of type=====>", typeof JSON.parse(JSON.stringify(arr)), "\n\n");
    console.log("======== OBJ EXAMPLE ==========");
    console.log("orig obj=====>", obj);
    console.log("stringified obj=====>", JSON.stringify(obj));
    console.log("proof of type=====>", typeof JSON.stringify(obj));
    console.log("parsed string=====>", JSON.parse(JSON.stringify(obj)));
    console.log("proof of type=====>", typeof JSON.parse(JSON.stringify(obj)), "\n\n");
  • 新的Date方法
      ES5为Date类新加入两种方法Date.now()Date.valueOf(),它们都返回自1970年1月1日以来的当前时间(以毫秒为单位)。两个方法都返回自1970一月一日的毫秒值,区别是Date.valueOf()返回值是Date类的实例而Date.now()只是调用函数返回一个数值。(Date.valueOf()返回值和Date.now()并不同,也许作者意为刚加入时两者类似?)
  • getters and setters
    在ES5的更新中,存取器属性被加入语言(accessor properties)。get和set的唯一角色就是得到、设置值。在设置了get和set后,他们就像标准的类属性。

    let character = {first_name: "Darth",last_name: "Vader",get fullName() {return `${this.first_name} ${this.last_name}`;},set fullName(str) {[this.first_name, this.last_name] = str.split(" ");}
    };
    console.log(character.fullName); //Darth Vader
    character.fullName = "Luke Skywakker"
    console.log(character.first_name);
    console.log(character.last_name);
    

  ES5标准使JavaScript代码更具可读性。通过引入新的数组方法,解析和字符串化JSON的能力以及使代码创建更加严格,它使JavaScript更易于理解。

ES6的更新细节

ES5版本发布七年后,于2015年6月ES6成为新的标准。

  • Babel
    最大变化之一是ES6 JavaScript无法直接在浏览器中进行编译。我们需要使用一个名为Babel.js的编译器来生成兼容的JavaScript,这样旧的浏览器才可读取这些JavaScript。

    Babel允许您在项目中使用ES6功能和语法,然后将其转换为ES5,以便可以在生产中使用它。要在构建项目时使用Babel,您需要将package.json添加到您的项目中。这是项目的所有依赖项所在的位置。

    如果你安装了Node和npm(yarn可替代npm),那么在项目目录下打开shell键入npm init(或者yarn init),在回答问题后package.json将会自动生成。
    使用npm/yarn将babel加入项目依赖:

    npm install --save-dev babel-cli
    //or
    yarn add babel-cli --dev
    

    将babel加入项目依赖后,还需要配置babel,首先安装babel-preset-env到项目:

    npm install --save-dev babel-preset-env
    //or
    yarn add babel-preset-env --dev
    

    然后创建.babelrc文件,写入以下内容

    {"presets": ["env"]
    }
    

    现在,您可以通过运行构建命令来运行Babel。现在,目标文件夹应该看起来与原始文件夹完全一样,只是目标文件夹的内容是ES5代码而不是ES6。如果您碰巧使用了JavaScript库或create-react-app之类的框架,那么Babel很有可能已经为您配置了,您无需担心。

  • 使用=>创建函数
      在该功能加入JavaScript前,我们只能使用function关键字来创建函数。现在我们可以使用=>来创建函数,使用=>创建行间函数可能更加优雅(译注:为何不用lambda呢)

    function add(num1, num2) {return num1 + num2;
    }
    // ES6 (implicit return)
    const addImplicit = (num1, num2) => num1 + num2;
    console.log(add(3, 4));
    console.log(addImplicit(3, 4));
    

    =>具有隐式return。如果函数只有一行,不需要return关键字,这也意味着不需要花括号。如果函数多于一行,则需要花括号和return语句:

    //ES6 (explicit return)
    const addExplicitReturn = (num1, num2) => {let sum = num1 + num2;return sum;
    };
    console.log(addExplicitReturn(3, 4));
    

    还需要注意的是,当使用类时,箭头函数已绑定到“ this”关键字,因此无需实际使用bind()方法将函数绑定至类。

    如果使用function关键字,则需要使用bind()方法将该方法绑定到该类。

  • Classes
      在JavaScript的原型之上,类充当语法糖。它们代替原型继承,而是将古典继承与extends关键字一起使用。总体而言,它减少了一些代码量。

    class StarWarsCharacter{constructor(attributes) {this.name = attributes.name;this.age = attributes.age;this.homePlanet = attributes.homePlanet;}getCharacter = () => `${this.name} is ${this.age} years old and is from ${this.homePlanet}.`;
    }const luke = new StarWarsCharacter({ name: "Luke Skywalker", age: 23, homePlanet: "Tatooine"});luke.getCharacter();class Heroes extends StarWarsCharacter {constructor(attributes) {super(attributes);this.favoriteVehicle = attributes.favoriteVehicle;}getFavoriteVehicle = () => `${this.name} is ${this.age} and their favorite vehicle is the ${this.favoriteVehicle}`;
    }const hans = new Heroes({ name: "Hans Solo", age: 35, favoriteVehicle: "Millennium Falcon"});console.log(hans.getFavoriteVehicle());
    
  • Destructuring(析构)
      它允许我们unpack对象并将该解压缩后的值用作我们稍后在代码中引用的变量。

    const state = {name: "Luke Skywalker",age: 22,dark_side: false
    }
    console.log("before destructuring");
    console.log(state.name);
    console.log(state.age);
    console.log(state.dark_side);
    const { name, age, dark_side } = state;
    console.log("after destructuring");
    console.log(name);
    console.log(age);
    console.log(dark_side);
    

       我们可以通过拉出属性来对其进行结构分解,将其放在花括号中,然后将其设置为对象名称。**确保在花括号前使用const关键字,**它允许我们将这些属性作为变量访问,而不是在实际对象本身上使用点符号。

    Array的析构与上面的代码类似,不同的是使用花括号。

     const arr_state = [ "Luke Skywalker", 22, false];console.log("before destructuring");console.log(arr_state[0]);console.log(arr_state[1]);console.log(arr_state[2]);const [ name, age, dark_side ] = arr_state;console.log("after destructuring");console.log(name);console.log(age);console.log(dark_side);
    
  • let and const
      ES6加入了两个新的声明变量的关键字,他们一定程度上取代了var关键字。在ES6之前,JavaScript仅仅有函数作用域和全局作用域。加入let和const后,我们有了块作用域(有点类似python的闭包,但在if-else嵌套作用域是python没有的)

    let x = 5;
    function blockExample() {let x = 2;if (x >= 3) {let x = 10;console.log(x, "inside if block");} else {let x = 1;console.log(x, "inside else block")}console.log(x, "inside function");
    }
    blockExample();
    console.log(x, "global example");
    

    **let关键字暗含作用域,在同一作用域下重新声明相同变量将引发语法错误(使用var看起来不报错)。

    var x = 3;
    var x = 120; // no errors
    

    使用let报错

    let x = 5;
    let x = 120; // syntax error
    

    const在声明不变量时很有用。尝试将const变量赋值将引发错误。

  • Promises
      Promises处理异步JavaScript编程更加优雅,在ES6以前,异步调用是通过使用回调函数进行的,这可能会使代码非常复杂并令人费解。

    注意:Promises将异步逻辑包装在net程序包中以使代码更具可读性。

    console.log("before promise")
    let promise = new Promise((resolve, reject) => {let resolvedFlag = false;//this is just a flag so we can intentionally throw the response to test logicconsole.log("this is eventually going to be an API call");resolvedFlag = true;//flip resolved to true once all console logs are doneif (resolvedflag) {//if resolved is true invoke the resolve functionresolve("Promise resolved THIS IS THE RESPONSE");} else {// else invoke the reject function with a new Error object with messagereject(new Error("Promise failed"));console.log("after promise");}
    });
    promise.then(resp => {console.log(resp);//promise response
    });
    
  • rest和spread操作符(译注:即…操作符,用作unpack)
      rest运算符和spread运算符语法相同,但用途不同。在函数参数之前使用rest运算符来指示应将多个参数分配给该参数。(译注:这里类似python的*符号)

    function restExample(a, ...b) {console.log(a);ocnsole.log(b);
    }
    restExample(1, 2, 3, 4, 5, 6);
    

    spread运算符由array使用(译注:与python的*符号类似,拆包),用法见下面的例子:

    function spreadExample(arr) {let newArr = [2, 4, 6, 8];console.log("arr", arr);let combinedArr = [...newArr, ...arr]let arrWithOtherContents = ["a", ...newArr, {b: "c", d: "e"}, true, ...arr];console.log(arrWithOtherContents);console.log("combined", combinedArr);
    }
    console.log(spreadExample([1, 3, 5, 7, 9]))
    

    上面代码的运行结果:

  • 模板文字Template Literals
      在ES6中,我们不再需要使用+操作符连接文字、空格和变量来构成一个大的字符串,使用template literals来构造表达式将变量嵌入字符串是更优雅的做法(译注:与python的format格式化显示异曲同工)

    let name = "Jane";
    let holiday = "Christmas";
    //pre-ES6:
    console.log(name + "'s favorite holiday is " + holiday);
    //ES6+:
    console.log(`${name}'s favorite holiday is ${holiday}`);
    

进一步了解JavaScript

  自ES6发布以来,该标准化每年都在进行更新。您可以随时关注ECMA International的ECMA-262标准,以了解JavaScript的新功能。这些标准具有可免费在线阅读的PDF格式的标准。
  学习JavaScript,你还需要了解下面这些概念:

  • Map
  • Set
  • Generators
  • async/await

JavaScript版本变迁历史相关推荐

  1. JavaScript的发展历史

    JavaScript的发展历史 JavaScript的发展历史 JavaScript与Java的关系 JavaScript的版本 JavaScript的发展历史 JavaScript的诞生 JavaS ...

  2. 第一讲 《javascript 浏览器发展历史》

    javascript 浏览器发展历史 web 发展历史: mosaic                     (马萨克) 是互联网历史上第一个普遍使用 和 能够显示图片 的 网页浏览器 1993年问 ...

  3. 版本变迁_一本书遍览古今中外红楼梦版本变迁

    四百种版本,近千幅彩图,全景描绘<红楼梦>版本演化史 <红楼梦版本图说> 一本书遍览古今中外<红楼梦>版本变迁 <红楼梦>自乾隆年间成书以来影响巨大,是 ...

  4. 大油井隐藏的箱子_魔兽世界:历经版本变迁的5大隐藏boss!全部都经历过的才是大神...

    魔兽世界14年的资料片版本成功塑造经典的同时也给玩家带去了无数美好的回忆,魔兽世界除了留给玩家难忘的瞬间之外还有很多遗憾.在历代资料片中就有5大隐藏boss被大家错过,这些boss要么大家从来没有听说 ...

  5. 介绍一种在ABAP内核态进行内表高效拷贝的方法,和对应的Java和JavaScript版本的伪实现

    内表操作是ABAP开发人员几乎在每个ABAP程序里都会遇到的. 看一个例子:有两个行结构不一样的内表,每个内表的行结构有三列,除了name这一列名字一致外,其他两列的名称都不同,下图用红色和蓝色标注出 ...

  6. [.net 面向对象程序设计深入](4)MVC 6 —— 谈谈MVC的版本变迁及新版本6.0发展方向...

    [.net 面向对象程序设计深入](4)MVC 6 --谈谈MVC的版本变迁及新版本6.0发展方向 1.关于MVC 在本篇中不再详细介绍MVC的基础概念,这些东西百度要比我写的全面多了,MVC从1.0 ...

  7. php版本7历史,php的版本发展历史(1995-2020)

    PHP一直作为Web开发中的统治力量而存在,在WEB服务端开发领域,全球份额始终保持在78%以上. PHP快速,非常强大,生态好,而且免费,是一个为WEB而生的编程语言,自从诞生起PHP就被大多数开发 ...

  8. 【Git、GitHub、GitLab】四 Git文件重命名的简单方法以及使用git log查看版本演变历史

    上一篇文章学会了使用GIT四次提交建立一个有模有样的仓库.点击链接查看:[Git.GitHub.GitLab]三 Git基本命令之创建仓库并向仓库中添加文件. 本片文章记录git的文件重命名的简单方法 ...

  9. 集装箱编号校验码规则(JavaScript版本)

    集装箱编号校验码规则(JavaScript版本) 最近需要用到校验集装箱号是正确,网上搜了搜箱号的校验规则,写了份demo 贴上具体的计算方法, 参考点这里 懒的点的可以看我复制粘贴然后整理的的部分 ...

最新文章

  1. iphone如何信任软件_你还在用大众点评吗?评价软件失去信任还如何活下去
  2. 程序员饭碗不保了?GPT-3 最强应用发布,动动手指就自动写代码的神器来了!...
  3. Spring官网阅读(三)自动注入
  4. 对象之function
  5. Shell中的while语句
  6. Java | 设计模式-适配器模式
  7. [转载] JAVA 构造函数及其重载
  8. python爬虫接口_python爬虫之百度API调用方法
  9. 如何在升级数据表的同时保留原数据
  10. Bzoj3894文理分科
  11. a5m2使用方法 mysql_反転
  12. python修改快捷键_Pycharm快捷键设置 更换或者增添快捷键 设置字体放大缩小快捷键...
  13. 0321 预习笔记直播笔记
  14. Java 中continue基础用法
  15. 用python写跑酷游戏脚本,用Python写一个天天酷跑
  16. 一步一步教你VMWare安装苹果Mac OS X
  17. STM32cubeMX将STM32F767+LAN8720+LwIP+FreeRTOS的以太网实现
  18. 人体内脏分布图:人体五脏六腑位置图详细介绍
  19. 联想ghost重装系统_一键ghost怎么用|一键ghost重装系统教程|一键重装系统步骤
  20. 基于asp.net748警官学院物资管理系统

热门文章

  1. Android Studio中虚拟机显示比例不正确(已解决)
  2. 东华oj-挑战题第96题-摆花
  3. Python的getter和setter的方法使用详解
  4. for in和Object.keys和for-of
  5. U盘文件文件系统格式转换
  6. git 免密登录设置
  7. 高通平台开机logo制作方法
  8. 2021年塔式起重机司机考试报名及塔式起重机司机模拟考试题
  9. VMware虚拟机 安装Ubuntu22.04 详细教程
  10. 5G来临,射频芯片与基带技术演进和产业链。