ホームページ >よくある問題 >es5とes6とは何ですか

es5とes6とは何ですか

青灯夜游
青灯夜游オリジナル
2022-11-21 17:43:483734ブラウズ

es5 の正式名は「ECMAScript 5」で、ECMAScript 標準の第 5 版です。既存の JavaScript メソッドにステートメントを追加し、ネイティブ ECMAScript オブジェクトをマージすることで標準化を実現しています。ES5 では、ECMAScript の厳密なバリアントも導入されています。 「厳密モード」と呼ばれる構文。 es6 の正式名称は ECMAScript6 で、2015 年 6 月に正式にリリースされた JS 言語の標準であり、その目標は、JS 言語を複雑な大規模アプリケーションの作成に使用でき、エンタープライズレベルの開発言語にすることです。

es5とes6とは何ですか

このチュートリアルの動作環境: Windows 7 システム、ECMAScript バージョン 6、Dell G3 コンピューター。

正式名は「ECMAScript」です。

ECMAScript は、Ecma International (旧欧州コンピュータ製造者協会として知られていました) によって開発された言語です。 Computer Manufactures Association) ECMA-262 によって標準化されたスクリプト プログラミング言語。この言語は World Wide Web で広く使用されており、JavaScript または JScript と呼ばれることが多いため、JavaScript の標準として理解できますが、実際には、後の 2 つは ECMA-262 標準の実装および拡張です。

ECMAScript は、ホスト環境で計算を実行し、計算可能なオブジェクトを操作できるオブジェクトベースのプログラミング言語です。 ECMAScript は、Web ページの動的なプレゼンテーションをサポートし、Web ベースのクライアント/サーバー アーキテクチャにサーバー側のコンピューティング機能を提供する Web スクリプト言語として最初に設計されました。しかし、ECMAScript はスクリプト言語としては他のスクリプト言語と同じ性質、つまり「既存のシステムが提供する機能を操作、カスタマイズ、自動化するために使用される」という性質を持っています。

es5 とは

es5 の正式名は「ECMAScript 5」で、ECMAScript2009 とも呼ばれます。 HTML5 と同じ ECMAScript 標準 仕様プロセスは基本的に似ており、ES5 では既存の JavaScript メソッドにステートメントを追加し、ネイティブ ECMAScript オブジェクトとマージすることで標準化されています。 ES5 では、「strict モード」と呼ばれる構文の厳密なバリアントも導入されています。

es5 の新機能:

これらは 2009 年にリリースされた新機能です:

  • 「use strict」ディレクティブ

  • #String.trim()

  • Array.isArray()

  • Array.forEach( )

  • Array.map()

  • ##Array.filter()
  • Array.reduce ()
  • Array.reduceRight()
  • Array.every()
  • Array.some( )
  • ##Array.indexOf()
  • Array.lastIndexOf()
  • JSON .parse( )
  • JSON.stringify()
  • Date.now()
  • プロパティ ゲッターとSetters
  • 新しいオブジェクト プロパティ メソッド
  • ES5 の strict モード 'use strict'

     给作者提供了选择一个限制性更强语言变种的方式
        1. 消除不安全之处,保证安全运行
        2. 提升编译效率
        3. 未来发展趋势
      规则:
        1)变量先定义在使用
        2)不允许变量重名
          var a=1;
          function a(){}
        3)不允许使用eval
        4)不允许delete
        4)不允许with语句
          var sMessage = "hello";
          with(sMessage) {alert(toUpperCase());}

es5 とは

# es6 の正式名は ECMAScript6 (ECMAScript の 6 番目のバージョン) で、2015 年 6 月に正式にリリースされた JavaScript 言語標準です。 2015 (ES2015)。その目標は、JavaScript 言語を使用して複雑な大規模アプリケーションを作成できるようにし、エンタープライズ レベルの開発言語になることです。

ES6 は、プログラムを作成できるようにする JavaScript 言語の大幅な機能強化です。 ES6 は複雑なアプリケーションに適しています。 ES5 と ES6 には本質的にいくつかの類似点がありますが、両者の間には多くの違いもあります。

es5 と es6 の違い

## ES5 と ES6 の比較リストは次のとおりです。

#比較項目ES5ES6定義ES5 は、ECMA International によって定義された商標登録されたスクリプト言語仕様である ECMAScript の第 5 版です。 ES6 は、ECMA International によって定義された商標登録されたスクリプト言語仕様である ECMAScript の 6 番目のバージョンです。 公開 2009年に発売されました。 2015年に発売されました。 データ型ES5 は、文字列、数値、ブール値、Null 値、未定義 (ES6 では、JavaScript データ型にいくつかの追加が行われました。一意の値をサポートするために、新しいプリミティブ データ型 変数の定義ES5 では、変数は ES6 では、パフォーマンスES5 は ES6 よりも古いため、一部の機能が存在しないため、パフォーマンスは ES6 よりも低くなります。 ES6 は、新機能と短縮ストレージの実装により、ES5 よりも高いパフォーマンスを備えています。 サポート多くのコミュニティがサポートしています。 コミュニティ サポートも豊富ですが、ES5 より小規模です。 #オブジェクト操作アロー関数functionfunctionループforfor?of

代码转换

到目前为止,还没有完全支持ES6功能的浏览器。 但是,我们可以使用转译将ES6代码转换为ES5代码。

有两个主要的编译器Babel和Traceur,用于在构建过程中将ES6代码转换为ES5代码。

扩展运算符(…)

它在ES6中引入,使合并数组和对象变得容易。

ES6常用特性:

一、let和const命令

1、let:

(1)基本用法

ES6 新增了let命令,用来声明变量。类似于var,但是所声明的变量,只在let命令所在的代码块内有效。{

   let a = 10;
   var b = 1;
}
a // ReferenceError: a is not defined.
b // 1

(2)let在for循环中使用

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[2](); // 10
a[6](); // 10

这个例子中,i 由 var 声明,在全局范围有效,a 的所有组员里面的 i 都是指向同一个 i,导致所有组员运行输出的都是最后一轮的 i 的值。

var a = [];
for (let i = 0; i < 10; i++) {
    a[i] = function () {
        console.log(i);
    }
}
a[2](); // 2
a[6](); // 6

这个例子中, i 由 let 声明,当前的 i 只在本轮循环有效,所有每次循环的 i 其实都是一个新的变量。
Tips: 每轮循环的 i 都是重新声明的,JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的 i 时,就在上一轮循环的基础上进行计算

(3)for循环的特别之处

在 for 循环中,设置循环变量的那部分是一个父作用域,而循环内部是一个单独的子作用域

for (let i = 0; i < 3; i++) {
    let i = &#39;abc&#39;;  // 和上一行for循环计数器的i不在同一作用域,所以可以声明成功。类比下面要讲的function(arg){let arg;}会报错,就是作用域问题
    console.log(i);
}
// abc
// abc
// abc

(4)不能重复声明

let 不允许在相同作用域内,重复声明同一个变量。

function func() {
  var a = 10;
  let a = 1;
}
func(); //Identifier &#39;a&#39; has already been declared

function func() {
  let a = 10;
  let a = 1;
}
func(); //Identifier &#39;a&#39; has already been declared
 
function func(arg) {
  let arg; 
}
func(); //Identifier &#39;arg&#39; has already been declared
 
function func(arg) {
  {
    let arg; 
  }
}
func(); //不报错

(5)不存在变量提升

var 命令会发生“变量提升”现象,即变量可以在声明之前使用,值为 undefined。 let 命令改变了语法行为,它所声明的变量一定要在声明后使用,否则会报错。

console.log(foo); //undefined
var foo = 2;
console.log(bar); // ReferenceError: bar is not defined
let bar =  2;

(6)暂时性死区

ES6规定,如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前使用这些变量,就会报错。这在语法上称为 “暂时性死区”。

var tmp = 123;
if(true){
    tmp = &#39;abc&#39;; // ReferenceError: tmp is not defined
    let tmp;
}

Tips:“暂时性死区”的本质就是:只要一进入当前作用域,所要使用的变量就已经存在了,但不可获取(否则报错),只有等到声明的那一行代码出现,才可以获取和使用。

2、const:

const命令的用法和let相似,最大不同点就是:const声明一个只读的常量。一旦声明,常量的值就不能改变。

Tips:这个不可改变的是指针,所以对于const声明的对象和数组还是可以改变的。如果真的想将对象冻结,应该使用Object.freeze方法。

3、let和const部分补充:

ES5 只有两种声明变量的方法:var命令和function命令。

ES6 除了添加let和const命令,另外两种声明变量的方法:import命令和class命令。所以,ES6 一共有 6 种声明变量的方法。

顶层对象:在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。

ES6为了保持兼容性,规定:a. var 命令和 function 命令声明的全局变量,依旧是顶层对象的属性。b. let,const,class 命令声明的全局变量,不属于顶层对象的属性。

var a = 1;
window.a; // 1
let b = 2;
window.b; // undefined

二、变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

1、数组的解构赋值

(1)基本用法

// 之前,为变量赋值,可以直接指定值
let a = 1;
let b = 2;
let c = 3;

// ES6中允许这样
let [a, b, c] = [1, 2, 3];  // 可以从数组中提取值,按照对应位置,对变量赋值。

本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
 
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
 
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
 
let [x, y, ...z] = [&#39;a&#39;];
x // "a"
y // undefined  - 如果解构不成功,变量的值就等于 undefined。
z // []

 如果解构不成功,变量的值就等于undefined

上面一种情况是解构不成功的;另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

上面两个例子,都属于不完全解构,但是可以成功。

如果等号的右边不是数组,那么将会报错。

let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

(2)默认值

解构赋值允许指定默认值。例如:

let [foo = true] = [];
foo;// true
 
let [x, y = &#39;b&#39;] = [&#39;a&#39;];
x;//&#39;a&#39;
y;//&#39;b&#39;

Tips:ES6 内部使用严格相等运算符(===)去判断一个位置是否有值所以,只有当一个数组成员严格等于 undefined ,默认值才会生效。例如:

let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null - 默认值就不会生效,因为null不严格等于undefined

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

let [x = 1, y = x] = [1, 2];
x;//1
y;//2
 
let [x = y, y = 1] = [];// ReferenceError: y is not defined -- let的暂时性死区
let [x = y, y = 1] = [1, 2];
2、对象的解构赋值

(1)基本用法

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined

对象的解构与数组的解构,一个重要的不同点在于: 数组元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量名与属性同名,才能取到正确的值。

如果没有与变量名对应的属性名,导致取不到值,最后等于undefined。

如果变量名和属性名不一样,必须写才下面这样:

let { foo: baz } = { foo: &#39;aaa&#39;, bar: &#39;bbb&#39; };
baz // "aaa"

let obj = { first: &#39;hello&#39;, last: &#39;world&#39; };
let { first: f, last: l } = obj;
f // &#39;hello&#39;
l // &#39;world&#39;

这实际上说明,对象的解构赋值是下面形式的简写:

let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };

 也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined

 上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo

(2)默认值

对象的解构也可以指定默认值。默认值生效的条件是对象的属性值严格等于 undefined。

let {x, y = 5} = {x: 1};
x;// 1
y;// 5

let { message: msg = &#39;Something went wrong&#39; } = {};
msg;//"Something went wrong"

Tips:如果要将一个已经声明的变量用于解构赋值,需要注意:

let x;
{x} = {x:1};
//上面的代码会报错,因为JavaScript引擎会将 {x} 理解为一个代码块,从而发生语法错误。只有不将大括号写在行首,避免JavaScript将其解释为代码块,才能解决这个问题。
 
//正确的写法,将需要解构的部分用括号()包起来
let x;
({x} = {x:1});
3、字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

const [a, b, c, d, e] = &#39;hello&#39;;
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

类似数组的对象都有一个 length 属性,因此还可以对这个属性解构赋值。

let {length: len} = &#39;hello&#39;;
len;// 5
4、数值和布尔值的解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转化为对象:

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

上面代码中,数值和布尔值的包装对象都有 toString 属性,因此变量 s 都可以取到值。

解构赋值的规则是:只要等号右边的值不是对象或数组,就先将其转化为对象。 由于 undefined 和 null 无法转化为对象,所以对他们进行解构赋值都会报错。

5、函数参数的解构赋值
function add([x, y]){
   return x + y;
}
 
add([1, 2]); // 3
 
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]

 上面代码中,函数 add 的参数看似是一个数组,但在传入参数时,数组参数就解构为变量 x 和 y。对于函数内部代码来说,参数就是 x 和 y。

函数参数的解构也可以使用默认参数:

function move({x=0, y=0}={}) {
  return [x, y];
}
move({x:3,y:8});// [3, 8]
move({x:3});// [3, 0]
move({});// [0, 0]
move();// [0, 0]

上例中,函数 move 的参数是一个对象,通过对这个对象进行解构,得到变量 x 和 y 的值。如果解构失败,x 和 y 等于默认值。

再看下面这种写法:

function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}
 
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]

上面的代码是为函数 move 的参数指定默认值,而不是为变量 x 和 y 指定默认值。

6、解构的用途

(1)交换变量的值

let x = 1;
let y = 2;
[x, y] = [y, x];
x;// 2
y;// 1

(2)从函数返回多个值
函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里面返回。有了解构赋值,取出这些值就非常方便。

//返回一个数组
function example() {
    return [1, 2, 3];
}
let [a, b, c] = example();
a;//1
b;//2
c;//3
 
//返回一个对象
function example(){
    return {
        foo: 1,
        bar: 2
    }
}
let {foo, bar} = example();
foo;//1
bar;//2

(3)函数参数的定义
解构赋值可以方便的将一组参数与变量名对应起来。

//参数是一组有序值
function f([x, y, z]) {}
f([1, 2, 3]);
 
//参数是一组无序值
function f({x, y, z}) {}
f({x: 1, y: 2, z: 3});

(4)提取JSON数据

let data = {
    id: 1,
    status: &#39;ok&#39;,
    data: [867, 5612]
};
let {id, status, data:number} = data;
console.log(id, status, number);// 1 "ok"  [867, 5612]

 (5)遍历Map解构

const map = new Map();
map.set(&#39;first&#39;,&#39;hello&#39;);
map.set(&#39;second&#39;,&#39;world&#39;);
for (let [key, value] of map) {
    console.log(key + &#39; is &#39; + value );
}
//first is hello
//second is world

// 获取键名
for (let [key] of map) {}
 
// 获取键值
for (let [,value] of map) {}

三、函数的默认参数

1、基本用法

ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。

function log(x, y) {
  y = y || &#39;World&#39;;
  console.log(x, y);
}

log(&#39;Hello&#39;) // Hello World
log(&#39;Hello&#39;, &#39;China&#39;) // Hello China
log(&#39;Hello&#39;, &#39;&#39;) // Hello World

上面代码检查函数log的参数y有没有赋值,如果没有,则指定默认值为World。这种写法的缺点在于,如果参数y赋值了,但是对应的布尔值为false,则该赋值不起作用。就像上面代码的最后一行,参数y等于空字符,结果被改为默认值。

为了避免这个问题,通常需要先判断一下参数y是否被赋值,如果没有,再等于默认值。

if (typeof y === &#39;undefined&#39;) {
  y = &#39;World&#39;;
}

ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

function log(x, y = &#39;World&#39;) {
  console.log(x, y);
}

log(&#39;Hello&#39;) // Hello World
log(&#39;Hello&#39;, &#39;China&#39;) // Hello China
log(&#39;Hello&#39;, &#39;&#39;) // Hello -- 上面说过,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于 undefined ,默认值才会生效。
2、与解构赋值默认值结合使用
function foo({x, y = 5}) {
  console.log(x, y);
}

foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property &#39;x&#39; of undefined

上面代码只使用了对象的解构赋值默认值,没有使用函数参数的默认值。只有当函数foo的参数是一个对象时,变量x和y才会通过解构赋值生成。

如果函数foo调用时没提供参数,变量x和y就不会生成,从而报错。

通过提供函数参数的默认值,就可以避免这种情况。

function foo({x, y = 5} = {}) {
  console.log(x, y);
}

foo() // undefined 5

下面是另一个解构赋值默认值的例子:

function fetch(url, { body = &#39;&#39;, method = &#39;GET&#39;, headers = {} }) {
  console.log(method);
}

fetch(&#39;http://example.com&#39;, {})
// "GET"

fetch(&#39;http://example.com&#39;)
// 报错

上面代码中,如果函数fetch的第二个参数是一个对象,就可以为它的三个属性设置默认值。

这种写法不能省略第二个参数,如果结合函数参数的默认值,就可以省略第二个参数。这时,就出现了双重默认值。

function fetch(url, { body = &#39;&#39;, method = &#39;GET&#39;, headers = {} } = {}) {
  console.log(method);
}

fetch(&#39;http://example.com&#39;)
// "GET"

上面代码中,函数fetch没有第二个参数时,函数参数的默认值就会生效,然后才是解构赋值的默认值生效,变量method才会取到默认值GET。

因此,与解构赋值默认值结合使用时,切记,函数要定义默认参数,防止函数不传参时报错。

四、模板字符串

模板字符串是增强版的字符串,用反引号 (`) 标识。它可以当普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

1、基本用法
let greeting = `\`Yo\` World!`;  // `Yo` World -- 使用反斜杠转义反引号

// 多行字符串
$(&#39;#result&#39;).append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

Tips:
a. 如果在模板字符串中需要使用反引号,则前面需要使用反斜杠转义。
b. 如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。

2、在模板字符串使用变量

(1) 在模板字符串中嵌入变量,需要将变量名写在 ${} 之中。
(2) 大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。
(3) 模板字符串之中还能调用函数。
(4) 如果大括号中的值不是字符串,将按照一般的规则转为字符串。如: 如果大括号中是一个对象,将默认调用对象的 toString 方法。
(5) 如果模板字符串中的变量没有声明将会报错。
(6) 如果大括号内部是一个字符串,将原样输出。

//普通字符串
`In JavaScript &#39;\n&#39; is a line-feed.`;
 `Hello ${&#39;World&#39;}`; // "Hello World"

//字符串中嵌入变量
let name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`); //  Hello Bob, how are you today?

//字符串中嵌入 JavaScript 表达式
`${x} + ${y} = ${x + y}`;// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`;// "1 + 4 = 5"

let obj = {x: 1, y: 2};
`${obj.x + obj.y}`;// "3"

// 字符串中嵌入函数
function fn(){
    return "hello world"
}
`foo ${fn()} bar`;// "foo hello world bar"

// 字符串中嵌入对象
`${obj}`;// "[object Object]"

// 字符串中嵌入未声明的变量
 `Hello, ${place}`;// ReferenceError: place is not defined

五、箭头函数

 ES6 允许使用 “箭头” (=>)定义函数。

1、基本用法
var f = v => v;
//等同于
var f = function (v) {
    return v;
}

=> 前面的部分是函数的参数,=> 后面的部分是函数的代码块。

(1)如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

var f = () => 5;
//等同于
var f = function (v) {
    return 5
};

var sum = (num1, num2) =>  num1 + num2;
//等同于
var sum = function(num1, num2){
    return num1 + num2;
}

(2)如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用 return 语句返回。

var sum = (num1,num2) => { return num1 + num2; }

(3)由于大括号会被解释为代码块,所以如果箭头函数直接返回一个对象,就必须在对象外面加上括号,否则会报错。

// 报错
let getTempItem = id => { id: id, name: "Temp" };

// 不报错
let getTempItem = id => ({ id: id, name: "Temp" });
getTempItem(1);//{id: 1, name: "Temp"}

let getTempItem = id => {
    return { id: id, name: "Temp" };
}
getTempItem(1);// {id: 1, name: "Temp"}

(4)箭头函数内部,可以嵌套箭头函数

function insert (value) {
    return {into: function (array){
            return {after: function (afterValue) {
                        array.splice(array.indexOf(ahterValue)+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;
        }
    })
});
2、箭头函数与变量解构结合使用
const full = ({ first, last }) => first + &#39; &#39; + last;
full({first: 1, last: 2});// "1 2"
// 等同于
function full(person) {
  return person.first + &#39; &#39; + person.last;
}
full({first: 1, last: 2});// "1 2"
3、rest 参数与箭头函数结合
const numbers = (...nums) => nums;
numbers(1,2,3,4);//  [1, 2, 3, 4]

const headAndTail = (head, ...tail) => [head, tail];
headAndTail(1,2,3,4);// [1,[2,3,4]]
4、箭头函数的优点

(1)简化代码

const isEven = n => n%2 == 0;
isEven(3);// false
isEven(4);// true

(2)简化回调函数

[1, 2, 3].map( x => x*x ); //[1, 4, 9]
[3,2,5].sort((a, b) => a - b); // [2, 3, 5]
5、箭头函数的注意点——this

ES5中 this 的指向是可变的,但是箭头函数中 this 指向固定化。

var  handler = {
    id: &#39;123&#39;,
    init: function () {
        document.addEventListener(&#39;click&#39;, 
            event => this.doSomethisng(event.type), false);
    },
    doSomethisng: function (type) {
        console.log(&#39;Handling &#39; + type + &#39; for &#39; + this.id);
    }
};
handler.init();  //Handling click for 123  -- this指向handle  -- this是属于函数的一个对象,谁调用指向谁(es5中)

 this 指向的固定化,并不是因为箭头函数内部有绑定 this 的机制,实际原因是箭头函数内部根本没有自己的this,导致内部的this 就是外层代码块的 this 。

 箭头函数的this是比较难理解的,但只要能想象到他是如何从ES5转化来的,就可以完全理解它的作用对象。 箭头函数转成 ES5 的代码如下:

// ES6
function foo() {
  setTimeout(() => {
    console.log(&#39;id:&#39;, this.id);
  }, 100);
}

// ES5
function foo() {
  var _this = this;

  setTimeout(function () {
    console.log(&#39;id:&#39;, _this.id);
  }, 100);
}

Tips:

(1) 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。
(2) 不可以当构造函数,即不可以使用 new 命令,因为它没有 this,否则会抛出一个错误。
(3) 箭头函数没有自己的 this,所以不能使用 call()、apply()、bind() 这些方法去改变 this 指向。
(4) 不可以使用arguments 对象,该对象在函数体内不存在。如果要用,可以使用rest参数代替。

六、数组的扩展(扩展运算符) 

 1、扩展运算符

(1)基本用法

  扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

console.log(...[1, 2, 3])  // 1 2 3
console.log(1, ...[2, 3, 4], 5)  // 1 2 3 4 5
[...document.querySelectorAll(&#39;div&#39;)]  // [<div>, <div>, <div>]

  该运算符主要用于函数调用。扩展运算符与正常的函数参数可以结合使用,非常灵活。function push(array, ...items) {

  array.push(...items);
}

function add(x, y) {
  return x + y;
}

const numbers = [4, 38];
add(...numbers) // 42

function f(v, w, x, y, z) { }
const args = [0, 1];
f(-1, ...args, 2, ...[3]);

如果扩展运算符后面是一个空数组,则不产生任何效果。 [...[], 1] // [1] 

注意,扩展运算符如果放在括号中,JavaScript 引擎就会认为这是函数调用,否则就会报错。(...[1,2])

// Uncaught SyntaxError: Unexpected number

console.log((...[1,2]))
// Uncaught SyntaxError: Unexpected number

console.log(...[1,2])  // 不会报错
2、替代函数的apply方法

由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了。

// ES5 的写法
function f(x, y, z) {
  // ...
}
var args = [0, 1, 2];
f.apply(null, args);

// ES6的写法
function f(x, y, z) {
  // ...
}
let args = [0, 1, 2];
f(...args);

3、扩展运算符引用

(1)复制数组

数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针(浅拷贝),而不是克隆一个全新的数组。

如何实现深拷贝呢?下面看看ES5和ES6的实现:

// ES5
const a1 = [1, 2];
const a2 = a1.concat();

// ES6
const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;

a2[0] = 2;
a1 // [1, 2]

(2)合并数组

const arr1 = [&#39;a&#39;, &#39;b&#39;];
const arr2 = [&#39;c&#39;];
const arr3 = [&#39;d&#39;, &#39;e&#39;];

// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ &#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39; ]

// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ &#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39; ]

不过,这两种方法都是浅拷贝,使用的时候需要注意。如果修改了原数组的成员,会同步反映到新数组。

const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];

const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];

a3[0] === a1[0] // true
a4[0] === a1[0] // true

(3)与解构赋值结合

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]

const [first, ...rest] = [];
first // undefined
rest  // []

const [first, ...rest] = ["foo"];
first  // "foo"
rest   // []

注意:如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。

const [...butLast, last] = [1, 2, 3, 4, 5]; // 报错

const [first, ...middle, last] = [1, 2, 3, 4, 5]; // 报错

(4)字符串

扩展运算符可以将字符串和函数参数arguments转成真正的数组

[...&#39;hello&#39;]  // [ "h", "e", "l", "l", "o" ]

function (){
   let arr = [...arguments];
}

七、对象的扩展

1、属性的简洁表示法

ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

const foo = &#39;bar&#39;;
const baz = {foo};
baz // {foo: "bar"}

// 等同于
const baz = {foo: foo};

上面代码表明,ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值

属性简写:

function f(x, y) {
  return {x, y};
}

// 等同于
function f(x, y) {
  return {x: x, y: y};
}

f(1, 2) // Object {x: 1, y: 2}

方法简写:

const o = {
  method() {
    return "Hello!";
  }
};

// 等同于
const o = {
  method: function() {
    return "Hello!";
  }
};

 CommonJS 模块输出一组变量,就非常合适使用简洁写法。

let ms = {};

function getItem (key) {
  return key in ms ? ms[key] : null;
}

function setItem (key, value) {
  ms[key] = value;
}

function clear () {
  ms = {};
}

module.exports = { getItem, setItem, clear };
// 等同于
module.exports = {
  getItem: getItem,
  setItem: setItem,
  clear: clear
};

2、属性名表达式

JavaScript 定义对象的属性,有两种方法。 

// 方法一
obj.foo = true;

// 方法二
obj[&#39;a&#39; + &#39;bc&#39;] = 123;

上面代码的方法一是直接用标识符作为属性名,方法二是用表达式作为属性名,这时要将表达式放在方括号之内。

但是,如果使用字面量方式定义对象(使用大括号),在 ES5 中只能使用方法一(标识符)定义属性。

var obj = {
  foo: true,
  abc: 123
};

ES6 允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。

let propKey = &#39;foo&#39;;

let obj = {
  [propKey]: true,
  [&#39;a&#39; + &#39;bc&#39;]: 123
};

表达式还可以用于定义方法名。比如我们熟悉的Vuex定义Mutation就是推荐这种方式:

// mutation-types.js
export const SOME_MUTATION = &#39;SOME_MUTATION&#39;

// store.js
import Vuex from &#39;vuex&#39;
import { SOME_MUTATION } from &#39;./mutation-types&#39;

const store = new Vuex.Store({
  state: { ... },
  mutations: {
    // 我们可以使用 ES2015 风格的计算属性命名功能来使用一个常量作为函数名
    [SOME_MUTATION] (state) {
      // mutate state
    }
  }
})
var test = {            
  &#39;attr0&#39; : &#39;attr1&#39;,            
  &#39;attr1&#39; : &#39;attr2&#39;,            
  &#39;attr2&#39; : &#39;attr3&#39;,            
  &#39;attr3&#39; : &#39;I&#39;m here&#39;,          
}                  
// 输出: I&#39;m here  , 方括号可以接受任何JS语句,最后都被转化为字符串。利用这个字符串在key-value集合中寻址。
console.log(test[test[test[test[&#39;attr0&#39;]]]]);

八、Array 的扩展方法

 扩展运算符(展开语法):扩展运算符可以将数组或者对象转为用逗号分隔的参数序列

let ary = [1, 2, 3];
...ary // 1, 2, 3console.log(...ary); // 1 2 3,相当于下面的代码console.log(1,2,3);

扩展运算符可以应用于合并数组

// 方法一 let ary1 = [1, 2, 3];
let ary2 = [3, 4, 5];
let ary3 = [...ary1, ...ary2];// 方法二 ary1.push(...ary2);

构造函数方法:Array.from()

将伪数组或可遍历对象转换为真正的数组

//定义一个集合let arrayLike = {&#39;0&#39;: &#39;a&#39;,&#39;1&#39;: &#39;b&#39;,&#39;2&#39;: &#39;c&#39;,
length: 3}; 
//转成数组let arr2 = Array.from(arrayLike); // [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]

方法还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组

let arrayLike = { 
"0": 1,"1": 2,"length": 2}
let newAry = Array.from(arrayLike, item => item *2)//[2,4]注意:如果是对象,那么属性需要写对应的索引

实例方法:find()

用于找出第一个符合条件的数组成员,如果没有找到返回undefined

let ary = [{
id: 1,
name: &#39;张三&#39;}, { 
id: 2,
name: &#39;李四&#39;}]; 
let target = ary.find((item, index) => item.id == 2);//找数组里面符合条件的值,当数组中元素id等于2的查找出来,注意,只会匹配第一个

实例方法:findIndex()

用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1

let ary = [1, 5, 10, 15];
let index = ary.findIndex((value, index) => value > 9); 
console.log(index); // 2

 实例方法:includes()

判断某个数组是否包含给定的值,返回布尔值。

[1, 2, 3].includes(2) // true [1, 2, 3].includes(4) // false

arr.splice(index,len,[item])

表示从数组中删除或者添加元素,返回新数组保存所有删除的元素
index表示要操作的索引位置,len表示要删除的个数,如果len的值为0表示不删除,item表示要添加的元素,可以是多个

let ary = [10, 20, 50]; // 把20给删除
 // ary.splice(1, 1);
 // console.log(ary);
 // 把20删除,替换成30
 // ary.splice(1, 1, 30);
 // console.log(ary);
 // 在20前面加上15
 // ary.splice(1, 0, 15);
 // console.log(ary);
 // 在50前面加上30,40ary.splice(2, 0, 30, 40);
console.log(ary);

arr.filter()

返回数组,包含了符合条件的所有元素。如果没有符合条件的元素则返回空数组

// 返回数组,包含了符合条件的所有元素。如果没有符合条件的元素则返回空数组
 // let result = ary.filter(item => item > 150);
 // console.log(result)

String 的扩展方法

实例方法:repeat()

repeat方法表示将原字符串重复n次,返回一个新字符串

&#39;x&#39;.repeat(3) // "xxx" &#39;hello&#39;.repeat(2) // "hellohello"

Set 数据结构

ES6 提供了新的数据结构  Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

Set本身是一个构造函数,用来生成  Set  数据结构

const s = new Set();

Set函数可以接受一个数组作为参数,用来初始化。

const set = new Set([1, 2, 3, 4, 4]);//{1, 2, 3, 4}

 实例方法

add(value):添加某个值,返回 Set 结构本身

delete(value):删除某个值,返回一个布尔值,表示删除是否成功

has(value):返回一个布尔值,表示该值是否为 Set 的成员

clear():清除所有成员,没有返回值

const s = new Set();
s.add(1).add(2).add(3); // 向 set 结构中添加值 s.delete(2) // 删除 set 结构中的2值 s.has(1) // 表示 set 结构中是否有1这个值 返回布尔值 s.clear() // 清除 set 结构中的所有值//注意:删除的是元素的值,不是代表的索引

 遍历

Set 结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。

s.forEach(value => console.log(value))

【推荐学习:javascript视频教程

未定義) などのプリミティブ データ型をサポートします。 symbol が導入されています。
var キーワードを使用してのみ定義できます。 let 変数と const 変数を定義する 2 つの新しい方法があります。
ES5 は ES6 よりも時間がかかります。 ES6 では、分割演算子と速度演算子のおかげでオブジェクト操作がよりスムーズに処理されます。
ES5 では、関数の定義に キーワードと return キーワードが使用されます。 アロー関数は ES6 で導入された新機能で、関数を定義するために キーワードは必要ありません。
ES5 では、要素を走査するために ループが使用されます。 ES6 では、反復可能なオブジェクトの値に対して反復を実行するための ループの概念が導入されました。

以上がes5とes6とは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。