ES6基础练习第二篇
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ES6day02练习</title> <script type="text/javascript"> // 六. 函数 // 1.函数参数的扩展 //基本用法 // function fn(name,age){ // console.log(name+","+age); // }fn("Amy",18); // Amy,18 // fn("Amy",""); // Amy, // 参数默认值 // 示例一 // function log(x, y = 'World') { // console.log(x, y); // } // log('Hello') // Hello World // log('Hello', 'China') // Hello China // log('Hello', '') // Hello // 示例二 // function Point(x = 0, y = 0) { // this.x = x; this.y = y; // } // let p = new Point(); // console.log(p);// Point {x: 0, y: 0} // p = new Point(1,2); // console.log(p); //Point {x: 1, y: 2} // 参数是一组有序的值,array 解构赋值 // function f([x, y, z]) { ... } // f([1, 2, 3]); // 参数是一组无序的值,object 解构赋值 // function f({x, y, z}) { ... } // f({z: 3, y: 2, x: 1}); // 2.不定参数(rest参数) // ES6引入rest参数(形式为“...变量名”),用于获取函数的多个参数。 // rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。 // function f01(...values) { // let sum = 0; // for (var val of values) { // sum += val; // } // return sum; // } // let result = f01(2, 5, 8) // console.log(result);//15 // 注意:rest参数只能放在参数组的最后,并且有且只有一个 不定参数。 //function f(a, ...b, c) { // ... } // 函数的length属性代表函数的参数个数。 // length属性,不包括已指定默认值的参数 // length属性,不包括rest参数。 // let len = (function(a) {}).length; // 1 // console.log(len); // len = (function (a = 5) {}).length; // 0 // console.log(len); // len =(function (a, b, c = 5) {}).length; // 2 // console.log(len); // len =(function(...a) {}).length; // 0 // console.log(len); // len = (function(a, ...b) {}).length ; // 1 // console.log(len); // 3.箭头函数 // ES6允许使用“箭头”(=>)定义函数。 // 参数 => 函数体 // v => v; // let f = v => v; // 该函数等同于: // let f = function(v) { // return v; // }; // f(1); //1 // 通过对比发现,上述定义的箭头函数是拥有一个参数、一个返回语句的函数 // 箭头函数是函数式编程的一种体现,将更多的关注点放在输入和输出的关系,省去过程中的一些因素。 // 箭头函数相当于匿名函数。 // 如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。 // let f = () => 5; // // 等同于 // let f = function () { return 5 }; // let sum = (num1, num2) => num1 + num2; // // 等同于 // let sum = function(num1, num2) {return num1 + num2; }; // 如果箭头函数的代码块不仅只有return语句,就要使用语句 块将它们括起来。 // let sum = (num1, num2) => { // console.log(num1 + num2); // return num1 + num2; // }; // 由于大括号在箭头函数中被解释为代码块, // 所以如果箭头函数返回一个对象,必须在对象外面加上括号。 // let getTempItem = id => ({ id: id, name: "Temp" }); // // 等同于 // let getTempItem = function (id) { // return { id: id, name: "Temp" } // }; // // 箭头函数可以与解构赋值结合使用。 // const full = ({ first, last }) => first + ' ' + last; // // 等同于 // function full(person) { // return person.first + ' ' + person.last; // } // 箭头函数中的 this // 普通函数中this对象的指向是可变的,但是在箭头函数中, 它是固定的。 // 如果是普通函数,执行时this应该指向全局对象。 // var Person = { // 'age': 18, // 'sayHello': function() { // setTimeout(function() { // console.log(this.age); // }); // } }; // var age = 20; // Person.sayHello(); // 20 //箭头函数内的this对象,就是定义时所在的对象。 // var Person1 = { // 'age': 18, // 'sayHello': function() { // setTimeout(() => { // console.log(this.age); // }); } }; // var age = 20; // Person1.sayHello(); // 18 // 箭头函数的使用场景(了解) // 箭头函数使得表达更加简洁。 // const isEven = n => n % 2 == 0; // const square = n => n * n; // 上面代码只用了两行,就定义了两个简单的工具函数。 // 如果不用箭头函数,可能就要占用多行,而且还不如现在这样 写醒目。 // 箭头函数简化回调函数。 // 正常函数写法 // [1,2,3].map(function (x) { // return x * x;//[1,4,9] // }); // 箭头函数写法 // [1,2,3].map(x => x * x); // rest参数、扩展运算符、箭头函数结合。 // const numbers = (...nums) => nums; // let result = numbers(1, 2, 3, 4, 5); // console.log(result); // [1,2,3,4,5] // result = numbers(...[6, 7, 8, 9, 0]); // console.log(result); // [6, 7, 8, 9, 0] // const headAndTail = (head, ...tail) => [head, tail]; // result = headAndTail(1, 2, 3, 4, 5); // console.log(result); // [1,[2,3,4,5]] // 七. 字符串模板 // 传统的JavaScript语言,输出模板通常是这样写的。 // $('#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`); // 字符串中嵌入变量 // var name = "Bob", // time = "today"; // `Hello ${name}, how are you ${time}?` // 如果在模板字符串中需要使用反引号,则前面要用反斜杠转 义。 //var greeting = `\`Yo\` World!`; // 八. 扩展运算符 // 扩展运算符(spread)是三个点(...)。 // 它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。 // console.log(...[1, 2, 3]);// 1 2 3 // console.log(1, ...[2, 3, 4], 5);// 1 2 3 4 5 // console.log([...document.querySelectorAll('body ')]);// [<body>] // 该运算符主要用于向函数传递实际参数。 // (rest参数定义函数的形式参数;扩展运算符提供实际参数) // function f02(...values) { // let sum = 0; // for (var val of values) { // sum += val; // } // return sum; // } //普通参数 // let result = f02(2, 5, 8) // 15 // console.log(result); //扩展运算符参数 // result = f02(...[3,6,9]) // 18 // console.log(result); //普通参数与扩展运算符参数结合使用 // result = f02(666, ...[1,4,7]) // 678 // console.log(result); // 1. 复制数组 // const a1 = [1, 2]; // const a2 = [...a1]; // 写法一 // const [...a3] = a1;// 写法二 // 2. 合并数组 // 扩展运算符提供了数组合并的新写法。 // let arr1 = ['a', 'b']; // let arr2 = ['c']; // let arr3 = ['d', 'e']; // ES5的合并数组 // let result = arr1.concat(arr2, arr3); // [ 'a', 'b', 'c', 'd', 'e' ] // ES6的合并数组 // result = [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ] // 3. 解构赋值结合 // 扩展运算符可以与解构赋值结合起来,用于生成数组。 // const [first, ...rest] = [1, 2, 3, 4, 5]; // console.log([first, ...rest]); //[1, 2, 3, 4, 5] // 扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。 // const [...first, last] = [1, 2, 3, 4, 5]; // console.log([...first, last]); //Rest element must be last element // const [first, ...middle, last] = [1, 2, 3, 4, 5]; // console.log([first, ...middle, last]);//Rest element must be last element // 4. 字符串 // 扩展运算符还可以将字符串转为真正的数组。 // let arr = [...'hello'] // console.log(arr); // [ "h", "e", "l", "l", "o" ] //5. 转为真正的数组 // 任何Iterator接口的对象,都可以用扩展运算符转为真正数组。 // 下面代码中,querySelectorAll方法返回的是一个 nodeList对象。 // 它不是数组,而是一个类似数组的对象。 // var nodeList = document.querySelectorAll('body'); // var array = [...nodeList]; // console.log(array);//[] // 这时,扩展运算符可以将其转为真正的数组,原因就在于 NodeList对象实现了Iterator接口。 // 对于那些没有部署Iterator接口的类似数组的对象,扩展运 算符就无法将其转为真正的数组。 // let arrayLike = { // '0': 'a', '1': 'b', '2': 'c', // length: 3 , // }; // let array = [...arrayLike]; // object is not iterable (cannot read property Symbol(Symbol.iterator)) // console.log(array); // 上面代码中,arrayLike是一个类似数组的对象,但是没有部署Iterator接口,扩展运算符就会报错。 // 这时,可以改为使用Array.from方法将arrayLike转为真的数组。 // 6. Map和Set结构 // 扩展运算符内部调用的是数据结构的Iterator接口, // 因此只要具有Iterator接口的对象,都可以使用扩展运算符 // Map结构: // let map = new Map( // [ [1, 'one'], // [2, 'two'], // [3, 'three'], // ]); // let keyArray = [...map.keys()]; // console.log(keyArray);//(3)[1, 2, 3] // let valueArray = [...map.values()]; // console.log(valueArray);//(3) ["one", "two", "three"] // 九. Iterator和for...of循环 //Iterator(遍历器)的概念 // JavaScript原有的表示“集合”的数据结构, // 主要是数组(Array)和对象(Object), // ES6又添加了Map和Set。这样就有了四种数据集合, // 用户还可以组合使用它们,定义自己的数据结构,比如数组 // 的成员是Map,Map的成员是对象。 // 这样就需要一种统一的接口机制,来处理所有不同的数据结 // 构。 // 遍历器(Iterator)就是这样一种机制。它是一种接口,为各 // 种不同的数据结构提供统一的访问机制。任何数据结构只要 // 部署Iterator接口,就可以完成遍历操作(即依次处理该数据 // 结构的所有成员)。 // 有些数据结构原生具备Iterator接口(比如数组),即不 // 用任何处理,就可以被for...of循环遍历,有些就不行(比如 // 对象)。原因在于,这些数据结构原生部署了 // Symbol.iterator属性,另外一些数据结构没有。凡是部署了 // Symbol.iterator属性的数据结构,就称为部署了遍历器接 // 口。调用这个接口,就会返回一个遍历器对象。 // console.log(Array.prototype); //Array(0) //含有Symbol(Symbol.iterator): ƒ values() //console.log(Object.prototype);//object // console.log(Map.prototype); //Map //含有Symbol(Symbol.iterator): ƒ values() // console.log(Set.prototype);//set //含有Symbol(Symbol.iterator): ƒ values() // ES6规定,默认的Iterator接口部署在数据结构的Symbol.iterator属性, // 或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。 // 调用Symbol.iterator方法,就会得到当前数据结构默认的遍历器生成函数。 // Symbol.iterator本身是一个表达式,返回Symbol对象的 iterator属性, //这是一个预定义好的、类型为Symbol的特殊值,所以要放在方括号内。 // const arr = ['red', 'green', 'blue']; // let iterator = arr[Symbol.iterator](); // for...of循环 // ES6借鉴C++、Java、C#和Python语言,引入了for...of 循环,作为遍历所有数据结构的统一的方法。 // 一个数据结构只要部署了Symbol.iterator属性,就被视为 具有iterator接口,就可以用for...of循环遍历它的成员。 // 也就是说,for...of循环内部调用的是数据结构的 Symbol.iterator方法。 // for...of循环可以使用的范围包括数组、Set和Map结构、 某些类似数组的对象( //比如arguments对象、DOM NodeList对 象)、Generator对象,以及字符串。 // 数组原生具备iterator接口,for...of循环本质上就是调 用这个接口产生的遍历器 // const arr = ['red', 'green', 'blue']; // let iterator = arr[Symbol.iterator](); // for (let v of iterator) { // console.log(v); // } // for (let v of arr) { // console.log(v); // } // JavaScript原有的for...in循环,遍历获得对象的键名。 {name:123,pass:456} // ES6提供for...of循环,遍历获得键值。 // var arr = ['a', 'b', 'c', 'd']; // for (let a in arr) { // console.log(a); // } // for (let a of arr) { // console.log(a); // } // 类似数组的对象 // 类似数组的对象包括好几类。 // 下面是for...of循环用于字符串、DOM NodeList对象、 arguments对象的例子。 // 字符串 // let str = "hello"; // for (let s of str) { // console.log(s); // } // DOM NodeList对象 //let container = document.querySelector(".parent");// Cannot read property 'querySelectorAll' of null // 获取tabs // let tabs = container.querySelectorAll(".tab"); // for (let tab of tabs) { // tab.style.color = "blue"; // } // arguments对象 // function printArgs() { // for (let x of arguments) { // console.log(x); // } // } // printArgs('a', 'b');//a b // 十. Promise对象 // Promise的含义 // Promise是异步编程的一种解决方案,比传统的解决方案 // ——回调函数和事件——更合理和更强大。 // 它由社区最早提出和实现,ES6将其写进了语言标准,统一了 // 用法,原生提供了Promise对象。 // 所谓Promise, // 简单说就是一个容器,里面保存着某个未来才会结束的事件 // (通常是一个异步操作)的结果。 // 从语法上说,Promise是一个对象,从它可以获取异步操作的 // 消息。 // // DOM NodeList对象 let container = document.querySelector(".parent"); // 获取tabs let tabs = container.querySelectorAll(".tab"); for (let tab of tabs) { tab.style.color = "blue"; }// arguments对象 function printArgs() { for (let x of arguments) { console.log(x); } }printArgs('a', 'b'); // Promise对象有以下两个特点。 // (1)对象的状态不受外界影响,由异步操作的状态决定。 // Promise对象代表一个异步操作,有三种状态:Pending(进 // 行中)、Resolved(已完成)和Rejected(已失败)。 // 只有异步操作的结果,可以决定当前是哪一种状态,任何其 // 他操作都无法改变这个状态。 // 这也是Promise这个名字的由来,它的英语意思就是“承诺”, // 表示其他手段无法改变。 // (2)一旦状态改变,就不会再变,任何时候都可以得到 // 这个结果。 // Promise对象的状态改变,只有两种可能:从Pending变为 // Resolved和从Pending变为Rejected。 // 只要这两种情况发生,状态就凝固了,不会再变了,会一直 // 保持这个结果。 // 就算改变已经发生了,你再对Promise对象添加回调函数,也 // 会立即得到这个结果。 // 这与事件(Event)完全不同,事件的特点是,如果你错过了 // 它,再去监听,是得不到结果的。 // 基本用法 // ES6规定,Promise对象是一个构造函数,用来生成 Promise实例。 // let promise = new Promise(function (resolve, reject) { // // ... some code // if (/*异步操作成功*/ ) { // resolve(value); // } else { reject(error); // } // }); // Promise构造函数接受一个函数作为参数,该函数的两个参 数分别是resolve和reject。 // 它们是两个函数,由JavaScript引擎提供,不用自己部署。 // resolve函数的作用是,将Promise对象的状态从“未完 成”变为“成功”(即从Pending变为Resolved), // 在异步操作成 功时调用,并将异步操作的结果,作为参数传递出去; // reject函数的作用是,将Promise对象的状态从“未完成”变 为“失败”(即从Pending变为Rejected), // 在异步操作失败时 调用,并将异步操作报出的错误,作为参数传递出去。 // Promise实例生成以后,可以用then方法分别指定 Resolved状态和Reject状态的回调函数。 // promise.then( function(value) { // // success code // }, // function(error) { // // failure code // }); // then方法可以接受两个回调函数作为参数。 // 第一个回调函数是Promise对象的状态变为Resolved时调 用, // 第二个回调函数是Promise对象的状态变为Reject时调用。 // 其中,第二个函数是可选的,不一定要提供。这两个函数都接 受Promise对象传出的值作为参数。 // 一般来说,不要在then方法里面定义Reject状态的回调函数 (即then的第二个参数), // 而是使用catch方法来捕获异常。 // promise.then( function(value) { // // success code // }).catch( // function(error) { // // failure code // } ); // 实例:加载图片文件显示到页面上 // 加载图片 // return promise function imgLoad(src) { // return new Promise(function(resolve, reject) { // let img = document.createElement('img'); // img.className = 'm-img'; // img.src = src; // img.onload = function(){ // resolve(img); // } // img.onerror = function(err){ // reject(err); // } // }); // } // // 将单个图片添加到界面上 // function showImg(img){ // let p = document.createElement('p'); // p.appendChild(img); // document.body.appendChild(p); // } // // 调用,使用then处理结果(应该还使用catch捕获异常,这 里省略) // imgLoad('http://qpzo4o916.hn- bkt.clouddn.com/dog.jpg').then(showImg); // imgLoad('http://qpzo4o916.hn- bkt.clouddn.com/ha.jpg').then(showImg); // imgLoad('http://qpzo4o916.hn- bkt.clouddn.com/panda.jpg').then(showImg); // 扩展: // 1. Promise.all() // 以上面的实例为基础,了解Promise.all()的用法 // 添加多个图片到文件 // function showImgs(imgs){ // imgs.forEach(img=>{ // document.body.appendChild(img); // }) // } // // 所有图片加载完成后再添加到界面 // Promise.all([ imgLoad('http://qpzo4o916.hn- bkt.clouddn.com/dog.jpg'), // imgLoad('http://qpzo4o916.hn- bkt.clouddn.com/ha.jpg'), // imgLoad('http://qpzo4o916.hn- bkt.clouddn.com/panda.jpg') ]).then(showImgs); // 2. Promise.race() // 以上面的实例为基础,了解Promise.race()的用法 // 一个图片加载完成后就添加到界面 // Promise.race([ imgLoad('http://qpzo4o916.hn- bkt.clouddn.com/dog.jpg'), // imgLoad('http://qpzo4o916.hn- bkt.clouddn.com/ha.jpg'), // imgLoad('http://qpzo4o916.hn- bkt.clouddn.com/panda.jpg') ]).then(showImg); // 十一. Module // 在 ES6 之前,社区制定了一些模块加载方案,最主要的 // 有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏 // 览器。ES6 在语言标准的层面上,实现了模块功能,而且实现 // 得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为 // 浏览器和服务器通用的模块解决方案。ES6 模块不是对象,而 // 是通过export命令显式指定输出的代码,再通过import命 // 令输入。 // 模块功能主要由两个命令构成:export和import。 export命令用于规定模块的对外接口,import命令用于输 // 入其他模块提供的功能。 // 在HTML网页中,ES5 脚本的常规用法 <!-- 页面内嵌JavaScript脚本 --> // <script type="application/javascript"/> <!--引入外部JavaScript脚本 --> <!-- <script type="application/javascript" src="path/myModule.js"></scrip> --> <!-- export命令&import命令 --> // // 1.导出变量 // export let A = 123; // // 2.导出方法 // export let test = function(){ // console.log('test'); // }; // // 3.导出对象 // export const student = { name: 'Megan', age: 18 }; // // or 先命名变量、方法、对象,再导出 // let A = 123; // let test = function(){ // console.log('test') // }; // const student = { name: 'magan', age: 18 } // export {A,test,student}; // export {A as x, test as y, student as c}; // ES6模块不是对象,而是通过export命令显式指定输出的代 码,输入时也采用静态命令的形式。 // 页面内嵌ES6模块 // // 引入变量,方法,对象 // import {A,test,student} from '../xxx.js' // // 引入 的名称和导出的名称要一致 // // 引入部分(按需引入) // import {A} from '../xxx.js' // // 引入全部 // import * as Test from '../xxx.js' // 从前面的例子可以看出,使用import命令的时候,用户需要知道 所要加载的变量名或函数名,否则无法加载。 // 如果用户希望快速上手,不愿意阅读文档,去了解模块有哪些属 性和方法。 为了给用户提供方便,让他们不 // 用阅读文档就能加载模块,就要 用到export default命令,为模块指定默认输出。 // 本质上,export default就是输出一个叫做default的变量或 方法,然后系统允许你为它取任意名字 // 例一 // let A = 123; // let test = function(){ // console.log('test') // }; // const student = { name: 'Megan', age: 18 } // export default{ A,test, student } // 这种写法,引入的时候不需要跟导出的名称一样,它将导出的 对象命名的权力交给了引入方 // import Test1 from '../xxx.js'; // console.log(Test1.A); // console.log(Test1.test); // console.log(Test1.Hello); // 例二 // export default function foo03() { // console.log(" foo03() "); // } // import x from '../xxx.js' // x(); // 注意: // 1. export语句,要写在最顶层,不可写在函数或者代码块内部 // function foo() { // console.log(" -- foo() -- "); // // export {foo}; // -- Error Unexpected token export // } // export {foo}; // 2. 在一个文件或模块中,export、import 可以有多个, // export default 仅有一个。通过 export 向外暴露的成 // 员,在导入时需要对应的变量名,并且必需要加{ }, // 通过 export default 向外暴露的成员,在导入时可以 // 使用任意变量来接收,不能加{ } // let a = 123; // export a; // --Error // // 正确写法 // export {a}; // export default function foo03() { // console.log(" foo03() "); // } // import {x} from '../xxx.js' // -- Error 会去模块 中查找名称为x的变量 // // 正确写法 // import x from '../xxx.js' // 3. import语句可以与export语句写在一起 // export {foo01, foo02} from '../xxx.js'; /* 约等于下面两段语句, 不过上面的导入导出复合写法,模块中没有导入 foo01 与 foo02上面代码中,export和import语句结合在一起,写成一 行。 但是从可读性考虑,不建议采用这种写法,而应该采用标 准写法。 */ // import {foo01, foo02} from "./xxx.js"; // export {foo01, foo02}; export * from '../xxx.js'; // 这里会忽略xxx.js中的default方法 </script> </head> <body> </body> </html>