JavaScript 版本:这些年来 JavaScript 的变化

编辑页面封面

JavaScript 是世界上最流行和最广泛的编程语言之一。自 1995 年诞生以来,最终被称为 JavaScript 的语言经历了多次迭代和版本。

JavaScript 由 Brendan Eich 发明,并于 1997 年成为 ECMA 标准。ECMAScript 是官方语言名称。ECMAScript 版本包括 ES1、ES2、ES3、ES5 和 ES6。

临近年底,让我们回顾一下 JavaScript 所经历的所有变化,以更好地了解如何使用这种语言。

我们将回顾:

学习如何编写现代 JavaScript

这是您作为前端开发人员开始旅程的理想场所。您将深入学习 HTML、CSS 和 JavaScript。

JavaScript 之前的网站

在 JavaScript 出现之前,网页是非常静态的。列表、日期和链接都被硬编码到你的 HTML 中,任何类型的动态功能都被编码在 HTML 文档的头部作为标题。

仍然存在的网页设计前 JavaScript 的最著名示例之一是 San Francisco FogCam:

小部件

旧金山 FogCam 大约创建于 30 年前,被誉为世界上最古老的网络摄像头之一。这是我们可以在互联网上看到“实时”图片的最早方式。

随着时代的变化,该网站没有。它仍然使用 1990 年代创建的静态 HTML 和 CSS。该页面使用<meta>文档标题中的信息每 20 秒刷新一次。

在创建 FogCam 时,JavaScript 还没有正式发布,但我们已经见证了对可以动态加载图像的东西的需求。

另一个 JavaScript 之前网页的架构示例是 90 年代后期为参议员鲍勃·多尔 (Bob Dole) 竞选总统而构建的 Dole/Kemp '96 页面。

小部件

这个网站仍然是一个静态网站,但它使用 HTML 路由从一个页面到另一个页面。这个网站上的一切都是硬编码的。Netscape Communicator 的工程师看到了这个问题,并决定创建一种脚本语言,允许动画、表单构建和更动态的交互。

这就是 JavaScript 诞生的起点。

JavaScript 开始

JavaScript 的第一次迭代实际上根本不称为 JavaScript。它被称为摩卡。这种语言被创建为设计人员和非程序员等的高级语言。

当 Mocha 与 Netscape Navigator 2.0 一起发布时,它的产品名称变成了 LiveScript,然后在以后的版本中变成了 JavaScript。

JavaScript 的第一个公开版本被集成到 Netscape Navigator 2.0 (1995) 中

JavaScript 的第一个公开版本被集成到 Netscape Navigator 2.0 (1995) 中

Netscape 与 Sun Microsystems 在创建 JavaScript 方面的合作无疑处于领先地位。随着 Netscape 获得越来越多的浏览器份额,其他浏览器需要想出一些办法来跟上 Netscape 的成功。

由于法律原因,微软创建了自己的 JavaScript 版本,称为 JScript。这些“方言”的主要任务是增加网站的用户体验和用户交互。

起初,Netscape 赢得了这些战争,但是随着 JScript 的创建,Microsoft 的 Internet Explorer 正在增加其浏览器份额。

这使得标准化非常困难。由于其与 Java 语法的相似性,JavaScript 在脚本语言战争中逐渐领先。随着 Java 变得越来越流行,JavaScript 也获得了更多的支持。

注意: Java 不等于 JavaScript。Java 是一种编译语言,它使用虚拟机或浏览器来执行代码。

JavaScript 是一种脚本语言,它在生产中的浏览器中大放异彩,并在浏览器之外的 Node.js 中使用。

JavaScript 版本

版本官方名字描述
ES1ECMAScript 1 (1997)第一版
ES2ECMAScript 2 (1998)编辑更改
ES3ECMAScript 3 (1999)添加了正则表达式 & try/catch
ES4ECMAScript 4未发布
ES5ECMAScript 5 (2009)添加了“严格模式”、JSON 支持、String.trim()、Array.isArray() 和数组迭代方法。
ES6ECMAScript 2015添加了 let 和 const、默认参数值、Array.find() 和 Array.findIndex()
ES6ECMAScript 2016添加指数运算符 & Array.prototype.includes
ES6ECMAScript 2017添加了字符串填充、Object.entries、Object.values、异步函数和共享内存
ES6ECMAScript 2018添加了休息/传播属性、异步迭代、Promise.finally() 和 RegExp

ECMAScript

Netscape Communicator 于 1997 年向 ECMA International 提交了文件,ECMA International 是一家标准化信息和通信系统的公司。

ECMA International 使用 Netscape 的 JavaScript 和 Microsoft 的 JScript 创建了一个称为 ECMAScript 的标准化,这是两种语言都基于的语言规范。ECMA 不能称为 JavaScript,因为 JavaScript 是 Sun Microsystems(后来成为 Oracle)持有的商标。

ECMAScript 1-4

ECMAScript 1 (ES1) 于 1997 年与第二年的 ES2 一起发布。两个版本之间没有太大变化。

ES3

ES3 于 1999 年发布,并增加了对许多新事物的支持,这些事物今天已成为该语言的标准部分:

  • **严格相等:**从 ES3 开始,严格相等运算符 ( ===) 成为除相等运算符 ( ==)之外的一个选项。两者之间的区别是比较类型和数量的问题。严格相等认为相同但类型不同的值是不相等的。
const compareTypeAndValue = (num, str) => {
 return num === str;
}

console.log(compareTypeAndValue(8, '8')); //false
console.log(compareTypeAndValue(8, 8)); //true

  • 正则表达式: ES3 中提供了两种类型的正则表达式:文字和构造函数。

  • **文字表达式:**文字正则表达式在两个反斜杠之间表示。实际表达式在斜杠和全局之间,忽略大小写,多行标志可以在最后一个反斜杠之后打开或关闭。

/[^abc]/gim

  • **构造函数表达式:**构造函数正则表达式是作为 RegExp 对象实例创建的那些表达式。实际的正则表达式是传递给 RegExp 构造函数的第一个参数。如果需要,第二个是您想要使用的标志。
const regex = new RegExp(‘[^abc]’, ‘gim’);

  • Switch 语句: switch 语句是一种控制流语句,它基本上将许多 if 条件链接在一起,而不必使用 else if 语句。switch 语句使用一个参数并将该参数与每个 case 语句进行比较。如果该参数与案例匹配,则执行该块中的逻辑。
const fizzBu​​zz = (num) => {
switch(num) {
 case 1:
   console.log(num);
   break;
 case 2:
   console.log(num);
   break;
 case 3:
   console.log("fizz");
   break;
 case 4:
   console.log(num);
   break;
 case 5:
   console.log("buzz");
   break;
 case 6:
   console.log("fizz");
   break;
 case 7:
   console.log(num);
   break;
 case 8:
   console.log(num);
   break;
 case 9:
   console.log("fizz");
   break;
 case 10:
   console.log(num);
   break;


}
}

console.log(fizzBu​​zz(3))
  • **Try/Catch 处理:**如果 try 块由于任何原因失败,try/catch 处理程序将抛出错误。下面,尝试失败,因为从未定义 obj。执行 catch 块并抛出一个新的 Error 对象异常。
const isValidKey = (val1) => {
try {
let obj;

return obj.hasOwnProperty(val1);

} catch (err) {
throw new Error("not valid key");
}
}
console.log(isValidKey(""))</pre>

ES3 是近十年来 ECMAScript 规范的最后一次重大更新,直到 2009 年使用 ES5。

ES4

TC39 是 ECMA International 的一个免版税任务组,其主要工作是标准化 ECMAScript。当需要更新和发布 ES4 标准时,任务组确实无法就规范达成一致。结果,ES4 作为一个版本被保留了下来,但从未完全作为实际标准发布。

ECMAScript 5 详细更新

ES5 和 ES6 是最新发布的规范,变化最多。

ES3 发布十年后的 2009 年,ECMAScript 的新版本发布。该标准是 JavaScript 自成立以来最大的变化。一些新功能包括:

严格使用

在 ES5 之前,允许使用未声明的变量(最初引入时不使用 var 关键字的变量)。当“使用严格”功能打开时,会引发引用错误。

"use strict"

x = 5; // ReferenceError: x is not defined

新的数组方法

ES5 中引入了几种新的数组方法,它们使处理数组的工作变得更加轻松。此处按字母顺序显示了新的数组方法:

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()

将过滤器方法视为具有 if 语句的 for 循环。如果元素通过测试,则将该元素推送到新数组。这就是filter()引擎盖下的工作方式。

map(),本节中提到的另一个数组方法,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()lastIndexOf()

如果需要搜索数组中的特定元素,可以使用indexOf()和 来完成lastIndexOf()indexOf()如果找到,则返回搜索参数的第一个索引,否则返回-1.

在 中lastIndexOf(),它为我们提供了数组中搜索元素的最后一个索引。同样,如果没有找到,它将返回-1

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()

此方法检查传递给它的对象是否为数组。返回一个布尔值。

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()在于它返回一个全新的数组。这允许在不影响原始数组的情况下操作数据。

回调函数必须有一个 return 语句。这是将进入新数组的特定索引的新值。

var arr = [6, 4, 5, 6, 7, 7];

arr.map(function(element) {
 return element * 2;
})

reduce()reduceRight()

这些reduce 方法中的每一个都将回调函数应用于数组中的每个元素。reduce()reduceRight()方法的特别之处在于它将数组缩减为单个元素。

reduceRight()方法就像reduce()是从右到左而不是从左到右迭代。

var arr = [6, 4, 5, 6, 7, 7];

var reduced = arr.reduce(function(curr, next) {
 return curr + next;
}, 0);

var reducedRight = arr.reduceRight(function(curr, next) {
 return curr + next;
}, 0)

console.log(reduced);

console.log(reducedRight);

some()

some()方法几乎与该every()方法完全相同,不同之处在于它会检查是否至少有一个元素满足您为其设置的条件。

var arr = [6, 4, 5, 6, 7, 7];

arr.some(function(element) {
 return element % 2 === 0; //checks to see if even
}); //true

JSON

解析和字符串化 JavaScript 对象表示法 (JSON) 的能力在 ES5 标准中成为可能。JSON 格式基本上用于通过网络连接传输某种结构化数据,通常是 Web 应用程序和 API。

当我们从一个应用程序传输数据时,它必须采用字符串的形式。我们JSON.stringify()用来将 JavaScript 对象转换为字符串。

然后我们JSON.parse()在另一端使用,将传输后的数据转换回 JavaScript 对象,以便我们可以使用它。

console.log("======== ARR 示例 ==========");
console.log("原始 arr====>", arr);
console.log("stringified arr====>", JSON.stringify(arr));
console.log("类型证明======>", typeof JSON.stringify(arr));
console.log("解析后的字符串======>", JSON.parse(JSON.stringify(arr)));
console.log("proof of type ======>", typeof JSON.parse(JSON.stringify(arr)), "\n\n");

console.log("======== 对象示例 ==========");
console.log("原始对象======>", obj);
console.log("stringified obj====>", JSON.stringify(obj));
console.log("类型证明======>", typeof JSON.stringify(obj));
console.log("解析后的字符串======>", JSON.parse(JSON.stringify(obj)));
console.log("proof of type =====>", typeof JSON.parse(JSON.stringify(obj)), 

新日期方法

ES5 中引入了两个新的 Date 对象方法,它们在功能上是等效的。它们都以毫秒为单位返回自 1970 年 1 月 1 日以来的当前时间。它们是Date.now()和 new Date().valueOf()

console.log(Date.now());

console.log(new Date().valueOf());

这两种方法最大的区别在valueOf()于是Date对象实例上的方法,是Date对象Date.now()的静态函数。

注意: Internet Explorer 可能不支持Date.now(),因此如果您担心,您可能需要在代码中处理它。

吸气剂和吸气剂

在 ES5 中,我们引入了访问器属性的概念。这些函数的唯一目的是获取或设置值。当您调用它们时,它们看起来像标准属性:

let character = {
first_name: "Darth",
last_name: "Vader",

获取 fullName() {
return `${this.first_name} ${this.last_name}`;
},
set fullName(str) {
[this.first_name, this.last_name] = str.split(" ");
}

};

console.log(character.fullName); // 达斯维达

character.fullName = "卢克·天行者"

console.log(character.first_name);
console.log(character.last_name);

ES5 标准真正开始为提高 JavaScript 代码的可读性铺平道路。随着新数组方法的引入、解析和字符串化 JSON 的能力以及使代码创建更加严格,它确实有助于使 JavaScript 更易于理解。

继续学习。

无需浏览视频或文档即可学习现代 JavaScript。Educative 的基于文本的学习路径易于浏览并具有实时编码环境,使学习变得快速高效。

小部件

ES6 详细更新

从 ES5 的完成版本到ES6的发布,已经过去了七年。它于 2015 年 6 月成为标准。

通天塔

ES5 的最大变化之一是 ES6 JavaScript 不能直接在浏览器中编译。我们需要使用一个被调用的转译器Babel.js来生成旧浏览器可以读取的兼容 JavaScript。

Babel 允许您在项目中使用 ES6 特性和语法,然后将其转换为 ES5,以便您可以在生产中使用它。

要在构建项目时使用 Babel,您需要将 package.json 添加到您的项目中。这是您项目的所有依赖项的存放位置。

确保您已安装 Node 和 npm(如果您更喜欢使用 Yarn,则安装 Node 和 Yarn),然后在终端中输入npm inityarn init命令。回答出现的问题,然后package.json将预先填写这些值。

使用 npm/yarn 通过以下命令将 babel 添加到您的依赖项中:

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

您将使用脚本中的字段package.json通过 Babel 设置构建命令。实际命令将根据您构建的文件夹和您想要构建的位置而有所不同。

最后,在项目的根文件夹(所在的位置package.json)中,创建一个.babelrc文件。这是一个 Babel 配置文件,它会告诉 Babel 将您的代码转换为 ES5。安装预设:

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 关键字来创建函数。现在,我们可以使用大箭头=>, 来编写函数。它可以使代码看起来更优雅,因为我们可以创建单行粗箭头函数。

//pre ES-6

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));

ES6 one-liner 有一个隐式返回。如果函数只有一行,我们就不需要 return 关键字。这也意味着不需要花括号。如果函数不止一行,我们需要花括号和 return 语句:

//ES6 (explicit return)

const addExplicitReturn = (num1, num2) => {
 let sum = num1 + num2;
 return sum;
};

console.log(addExplicitReturn(3, 4));

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

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

班级

类充当 JavaScript 原型之上的语法糖。他们没有使用Prototypal Inheritance,而是使用带有关键字的Classical Inheritanceextends。总的来说,它只是减少了代码量,并稍微修饰了一下。

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());

解构

对象解构是减少代码混乱以使其更可口的好方法。它允许我们“解包”一个对象,并将解包后的值用作我们稍后在代码中引用的变量。

const state = {
 name: "Luke Skywalker",
 age: 22,
 dark_side: false
}
 
console.log("before destructuring");
 
console.log(state.name); // notice the prefixed object name prior to each property
console.log(state.age);  // destructuring gets rid of this
console.log(state.dark_side);
 
 
const { name, age, dark_side } = state;
 
console.log("after destructuring");
console.log(name); // we can access using just the property name now!
console.log(age); 
console.log(dark_side);

在“解构之前”部分,除了要访问该属性的属性之外,我们还必须使用对象名称。我们可以通过拉出属性来解构它,将它放在一组花括号中并将其设置为对象名称。

确保在大括号前使用 const 关键字。它允许我们将这些属性作为变量访问,而不是在实际对象本身上使用点符号。

数组解构以非常相似的方式完成,但使用方括号而不是花括号。

const arr_state = [ "Luke Skywalker", 22, false];

console.log("before destructuring");

console.log(arr_state[0]); // notice the index number in bracket notation
console.log(arr_state[1]);  // destructuring gets rid of this
console.log(arr_state[2]);

console.log("\n\n\n")
const [ name, age, dark_side ] = arr_state; // assign a variable to each of the indexes in the array

console.log("after destructuring");
console.log(name); // we can access using just the variable name we created now!
console.log(age); 
console.log(dark_side);

letconst

在 ES6 中,我们有一些新的变量关键字,它们基本上取代了 var 关键字。在 ES6 之前,JavaScript 只有函数作用域和全局作用域。通过添加letconst,我们现在有了块作用域。

let x = 5;
 
function blockExample() {
 let x = 2 //this is function scope;
 if(x >= 3) {
   let x = 10; // this is block scope
   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关键字的改进,您可以在其中使用另一个值重新声明变量。当我们有相同的变量名和不同的值时,这被证明是有问题的,这会产生意外的错误。

// pre-ES6: 
var x = 5;
var x = 120; //produces no errors

// ES6: 
let x = 5;
let x = 120; // produces a syntax error

const当您有一个不想重新分配的变量时,该关键字很有用。如果您尝试将 const 变量重新分配给另一个值,它将引发错误。

承诺

Promise 是一种以更好的方式处理异步 JavaScript 编程的方法。以前,异步调用是通过使用回调函数进行的,这会使代码很快变得复杂和混乱。

注意: Promise 将异步逻辑包装在一个 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 logic
  console.log("this is eventually going to be an API call");
  resolvedFlag = true; //flip resolved to true once all console logs are done
 
  if(resolvedFlag) { //if resolved is true invoke the resolve function   
      
resolve("Promise resolved THIS IS THE RESPONSE");
 
  } else { // else invoke the reject function with a new Error object with message
    reject(new Error("Promise failed"));
    console.log("after promise");
  }
});
 
promise.then(resp => {
  console.log(resp); //promise response
})

休息和传播运算符

rest 和 spread 运算符本质上是相同的语法,但服务于不同的目的。在函数参数之前使用 rest 运算符来指示应将多个参数分配给该参数。

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

restExample(1, 2, 3, 4, 5, 6);

展开运算符使用相同的语法,但由数组使用。它本质上获取数组的内容,复制它,以便它可以传播到新结构中。我们可以使用扩展运算符作为向数组添加内容的一种方式,而无需使用push()unshift()

function spreadExample(arr) {
 let newArr = [2, 4, 6, 8];
 console.log("arr", arr);
 let combinedArr = [...newArr, ...arr]; //this pushes the contents of newArr and the contens of arr into a one-dimensional combined array.
 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]))

当您需要处理数组但不想操作数组的实际内容时,展开运算符非常有用。您可以使用扩展运算符基本上创建一个要使用的副本。

模板文字

在 ES6 中,我们不再需要将字符串、空格和变量连接在一起以形成更大的字符串。我们使用模板文字来创建表达式,允许我们在字符串中嵌入变量。

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}`);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是不会选择做一个普通人的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值