ES6初学

初读ES6标准入门,

这本书也买了许久,一直放在家里睡觉,个人喜欢纸质书多一点,这算是一本开源书籍,免费阅读网址http://eses6.ruanyifeng.com
书讲的知识点还是挺细致的

这里先给大家试着总结下
菜鸟题目分享中,有一题说后面会给大家分享简单的 做法

 for(let i = 0; i < 6; i++ ) {
            setTimeout(function timer () {
                console.log(i);        
            }, i*1000);
        }

把var 换成 let 是不是简单很多,为什么这样写呢?
通过var定义的变量,作用域是整个封闭函数,在全局范围内都有效,所以全局只有一个变量i;通过let定义的变量,作用域是在块级或是子块中。
更进一步的说,每轮循环的时候let声明的i都是一个新的变量。for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域


(一)let和const命令

这里给大家分享下我总结的var 和 let 区别
  • 1、通过var定义的变量,作用域是整个封闭函数,是全域的 。通过let定义的变量,作用域是在块级或是子块中。更进一步的说。每轮循环的时候let声明的i都是一个新的变量。var声明的i不会变,都是同一个变量。
for (let i = 0; i < 10; i++) {
  // ...
}
console.log(i);
块级作用域
function f1() {
  let n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5  这表示外层代码块不受内层代码块的影响,如果两次都使用var定义变量n,最后输出的值才是 10
}
ES6 允许块级作用域的任意嵌套。
{{{{{let insane = 'Hello World'}}}}};//使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量
{{{{
  {let insane = 'Hello World'}
  console.log(insane); // 报错
}}}};
{{{{
  let insane = 'Hello World';
  {let insane = 'Hello World'}
}}}};//内层作用域可以定义外层作用域的同名变量。
计数器i只在for循环体内有效,在循环体外引用就会报错。
  • 2、 let声明变量不能被预解析,let命令所声明的变量一定要在声明后使用,否则报错。
console.log(a)
var a=5     =>undifined 变量a用var命令声明,会发生变量提升,即脚本开始运行时,变量a已经存在了,但是没有值,所以会输出undefined。

console.log(b)
let b=6    =>b is not defined let在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。
  • 3、暂时性死区(变量let声明前都不能访问,为防止先调用在声明这个现象)只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
console.log(b)
let b=6    
console.log(b)  //在let声明变量前,对tmp赋值会报错
typeof x; // ReferenceError“暂时性死区”也意味着typeof不再是一个百分之百安全的操作。
let x;  //变量x使用let命令声明,所以在声明之前,都属于x的“死区”,只要用到该变量就会报错。因此,typeof运行时就会抛出一个ReferenceError。
typeof undeclared_variable // "undefined"  作为比较,如果一个变量根本没有被声明,使用typeof反而不会报错。
  • 4、在相同作用域内,let不能重复声明一个变量
var a=5
console.log(a)
var a=6
console.log(a)

let a=5
console.log(a)
let a=6
console.log(a) //报错:Identifier 'a' has already been declared(a已经存在)

const用法:const声明一个常量,一旦声明后就不能修改了
  • 1、如果声明后再去修改的话就会报错
const PI = 3.1415;
PI // 3.1415
PI = 3; // TypeError: Assignment to constant variable.
  • 2、只能先声明后使用,不会被提前解析
if (true) {
  console.log(MAX); // ReferenceError   常量MAX声明之前就调用,结果报错。
  const MAX = 5;
}
  • 3、只声明不赋值也会报错
const foo;
// SyntaxError: Missing initializer in const declaration
  • 4、不能重复声明一个常量
var message = "Hello!";
let age = 25;

// 以下两行都会报错
const message = "Goodbye!";
const age = 30;

注意:const声明的对象中属性是可以修改的


let和const区别

通过以上我们不难发现,let 和 const只在声明所在的块级作用域内有效,同时存在暂时性死区,只能在声明的位置后面使用,并且都不可重复声明,那么,他们之间有什么不同的地方呢?

  • let声明的变量可以改变,值和类型都可以改变;const声明的常量不可以改变,这意味着,const一旦声明,就必须立即初始化,不能以后再赋值。但是如果const声明的常量是个对象或者数组,那么这个常量的属性还是能够改变的,因为这个常量保存的是内存地址,实际数据在堆内存里,因此const声明的对象还是能改变属性,如果不想被改变可以用object.freeze()进行冻结,这个我在前面菜鸟题目中也有分享


(二)变量的解构赋值

默认值
解构赋值允许指定默认值
let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

let [x = 1] = [undefined];  //只有当一个数组成员严格等于undefined,默认值才会生效
x // 1
let [x = 1] = [null]; //一个数组成员是null,默认值就不会生效,因为null不严格等于undefined
x // null

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined  因为x用y做默认值时,y还没有声明

不能使用圆括号的情况

1、变量声明语句

// 全部报错
let [(a)] = [1];

let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};

let { o: ({ p: p }) } = { o: { p: 2 } };//它们都是变量声明语句,模式不能使用圆括号

2、函数参数

// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }

3、赋值语句的模式

// 全部报错
({ p: a }) = { p: 42 };  将整个模式放在圆括号之中,导致报错。
([a]) = [5];
可以使用圆括号的情况
只有一种情况:赋值语句的非模式部分,可以使用圆括号
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确

解构赋值的用途

1、交换变量的值

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

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

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

// 返回一个对象
function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

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

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

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

4、提取 JSON 数据

let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]

5、函数参数的默认值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};
//指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || 'default foo';这样的语句。

6、遍历 Map 结构

//任何部署了 Iterator 接口的对象,都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

//如果只想获取键名,或者只想获取键值,可以写成下面这样。
// 获取键名
for (let [key] of map) {
  // ...
}

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

7、输入模块的指定方法

const { SourceMapConsumer, SourceNode } = require("source-map");


(三)字符串的扩展

字符串的遍历器接口 (Iterator)

//遍历器我在上文也有简单介绍过
for (let codePoint of 'foo') {
  console.log(codePoint)
}
// "f"
// "o"
// "o"

模板字符串

//es5中输出模版一般这样写:
$('#result').append(
  'There are <b>' + basket.count + '</b> ' +
  'items in your basket, ' +
  '<em>' + basket.onSale +
  '</em> are on sale!'
);

//es6 引入了模板字符串
$('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

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

// 普通字符串
`In JavaScript '\n' is a line-feed.`

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

console.log(`string text line 1
string text line 2`);

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

使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中

$('#list').html(`
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`);

//如果你不想要这个换行,可以使用trim方法消除它。
$('#list').html(`
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`.trim());

模板字符串中嵌入变量,需要将变量名写在${}之中。

function authorize(user, action) {
  if (!user.hasPrivilege(action)) {
    throw new Error(
      // 传统写法为
      // 'User '
      // + user.name
      // + ' is not authorized to do '
      // + action
      // + '.'
      `User ${user.name} is not authorized to do ${action}.`);
  }
}

大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。

let x = 1;
let y = 2;

`${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

如果模板字符串中的变量没有声明,将报错。

// 变量place没有声明
let msg = `Hello, ${place}`;
// 报错

模板字符串的变量之中,嵌入了另一个模板字符串

const tmpl = addrs => `
  <table>
  ${addrs.map(addr => `
    <tr><td>${addr.first}</td></tr>
    <tr><td>${addr.last}</td></tr>
  `).join('')}
  </table>//addrs 是函数tmpl的形参
`;
//使用方法:
const data = [
    { first: '<Jane>', last: 'Bond' },
    { first: 'Lars', last: '<Croft>' },
];

console.log(tmpl(data));
// <table>
//
//   <tr><td><Jane></td></tr>
//   <tr><td>Bond</td></tr>
//
//   <tr><td>Lars</td></tr>
//   <tr><td><Croft></td></tr>
//
// </table>

如需引用模板字符串本身,在需要时执行,可以这样写

// 写法一
let str = 'return ' + '`Hello ${name}!`';
let func = new Function('name', str);
func('Jack') // "Hello Jack!"

// 写法二
let str = '(name) => `Hello ${name}!`';
let func = eval.call(null, str);
func('Jack') // "Hello Jack!"  eval是个特殊的语法解析器,它能把字符串解析成js代码,所以str明明是个字符串但是却能当函数执行。

includes(), startsWith(), endsWith()
这三个方法跟JavaScript中的indexOf方法相似

  • includes():返回布尔值,表示是否找到了参数字符串。
  • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
  • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true

此外这三个方法都支持第二个参数,表示开始搜索的位置

let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

注意:endWith使用第二参数n时与其他两个方法有所不同,它针对前n个字符,而其他两个针对从第n个位置直到字符串结束


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

'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""

'na'.repeat(2.9) // "nana"  参数如果是小数,会被取整。
'na'.repeat(Infinity) // RangeError  repeat的参数是负数或者Infinity,会报错。
'na'.repeat(-1) // RangeError  

'na'.repeat(-0.9) // ""  参数是 0 到-1 之间的小数,则等同于 0,这是因为会先进行取整运算。0 到-1 之间的小数,取整以后等于-0,repeat视同为 0。
'na'.repeat(NaN) // "" 参数NaN等同于 0。

'na'.repeat('na') // ""
'na'.repeat('3') // "nanana"  repeat的参数是字符串,则会先转换成数字。

padStart(),padEnd() padStart()用于头部补全,padEnd()用于尾部补全

'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'

'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'

padStart()和padEnd()一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。

'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'  原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。

'abc'.padStart(10, '0123456789') // '0123456abc'  用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串。

'x'.padStart(4) // '   x'
'x'.padEnd(4) // 'x   '  省略第二个参数,默认使用空格补全长度。

'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"  padStart()的常见用途是为数值补全指定位数。下面代码生成 10 位的数值字符串。

一个用途是提示字符串格式。

'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
今天有被师傅批评,因为好多例子都是从原书上搬过来的,自己也没有去尝试写,只是过一遍,也没有去深究,以后不会再这样了,很多东西想变成自己的就得付出努力,我很抱歉偷懒了,我会找时间把这篇文章修整下,保持本心,坚持不放弃,既然选择前端这条路,就别回头,愿所有在这条路上的人,能不被时光辜负😄
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容