-
2019-01-05 18:17:46
import()函数
简介
前面介绍过,
import
命令会被 JavaScript 引擎静态分析,先于模块内的其他模块执行(叫做”连接“更合适)。所以,下面的代码会报错。// 报错
if (x === 2) {
import MyModual from './myModual';
}
上面代码中,引擎处理
import
语句是在编译时,这时不会去分析或执行if
语句,所以import
语句放在if
代码块之中毫无意义,因此会报句法错误,而不是执行时错误。也就是说,import
和export
命令只能在模块的顶层,不能在代码块之中(比如,在if
代码块之中,或在函数之中)。这样的设计,固然有利于编译器提高效率,但也导致无法在运行时加载模块。在语法上,条件加载就不可能实现。如果
import
命令要取代 Node 的require
方法,这就形成了一个障碍。因为require
是运行时加载模块,import
命令无法取代require
的动态加载功能。const path = './' + fileName;
const myModual = require(path);
上面的语句就是动态加载,
require
到底加载哪一个模块,只有运行时才知道。import
语句做不到这一点。因此,有一个提案,建议引入
import()
函数,完成动态加载。import(specifier)
上面代码中,
import
函数的参数specifier
,指定所要加载的模块的位置。import
命令能够接受什么参数,import()
函数就能接受什么参数,两者区别主要是后者为动态加载。ES6 import()
返回一个 Promise 对象。下面是一个例子。const main = document.querySelector('main');
import(`./section-modules/${someVariable}.js`)
.then(module => {
module.loadPageInto(main);
})
.catch(err => {
main.textContent = err.message;
});
import()
函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,也会加载指定的模块。另外,import()
函数与所加载的模块没有静态连接关系,这点也是与import
语句不相同。import()
类似于 Node 的require
方法,区别主要是前者是异步加载,后者是同步加载。适用场合
下面是
import()
的一些适用场合。(1)按需加载。
import()
可以在需要的时候,再加载某个模块。button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
上面代码中,
import()
方法放在click
事件的监听函数之中,只有用户点击了按钮,才会加载这个模块。(2)条件加载
import()
可以放在if
代码块,根据不同的情况,加载不同的模块。if (condition) {
import('moduleA').then(...);
} else {
import('moduleB').then(...);
}
上面代码中,如果满足条件,就加载模块 A,否则加载模块 B。
(3)动态的模块路径
import()
允许模块路径动态生成。import(f())
.then(...);
上面代码中,根据函数
f
的返回结果,加载不同的模块。注意点
import()
加载模块成功以后,这个模块会作为一个对象,当作then
方法的参数。因此,可以使用对象解构赋值的语法,获取输出接口。import('./myModule.js')
.then(({export1, export2}) => {
// ...·
});
上面代码中,
export1
和export2
都是myModule.js
的输出接口,可以解构获得。如果模块有
default
输出接口,可以用参数直接获得。import('./myModule.js')
.then(myModule => {
console.log(myModule.default);
});
上面的代码也可以使用具名输入的形式。
import('./myModule.js')
.then(({default: theDefault}) => {
console.log(theDefault);
});
如果想同时加载多个模块,可以采用下面的写法。
Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
])
.then(([module1, module2, module3]) => {
···
});
import()
也可以用在 async 函数之中。async function main() {
const myModule = await import('./myModule.js');
const {export1, export2} = await import('./myModule.js');
const [module1, module2, module3] =
await Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
]);
}
main();
更多相关内容 -
「经典题」ES6新特性有哪些?
2022-05-09 20:17:49在es6中通常用let和const来声明,let表示变量、const表示常量。 特点: let 和 const 都是块级作用域。以{}代码块作为作用域范围 只能在代码块里面使用。 不存在变量提升,只能先声明再使用,否则会报错。在代码...目录
(3)、Object.keys()方法,获取对象的所有属性名或方法名(不包括原形的内容),返回一个数组。
(4)、Object.assign (),assign方法将多个原对象的属性和方法都合并到了目标对象上面。可以接收多个参数,第一个参数是目标对象,后面的都是源对象。
1、新增声明命令let和const
在es6中通常用
let
和const
来声明,let
表示变量、const
表示常量。特点:
- let 和 const 都是块级作用域。以{}代码块作为作用域范围 只能在代码块里面使用。
- 不存在变量提升,只能先声明再使用,否则会报错。在代码块内,在声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
- 在同一个代码块内,不允许重复声明。
- const声明的是一个只读常量,在声明时就需要赋值。(如果 const 的是一个对象,对象所包含的值是可以被修改的。抽象一点儿说,就是对象所指向的地址不能改变,而变量成员是可以修改的。)
2、模板字符串(Template String)
用一对反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,也可以在字符串中嵌入变量,js表达式或函数,变量、js表达式或函数需要写在${ }中。
var str = `abc def gh`; console.log(str); let name = "小明"; function a() { return "ming"; } console.log(`我的名字叫做${name},年龄${17+2}岁,性别${'男'},游戏ID:${a()}`);
3、函数的扩展
(1)、函数的默认参数
ES6为参数提供了默认值。在定义函数时便初始化了这个参数,以便在参数没有被传递进去时使用。
function A(a,b=1){ console.log(a+b); } A(1); //2 A(2+3); //5
(2)、箭头函数
在es6中,提供了一种简洁的函数写法,我们称作“箭头函数”。
写法:函数名=(形参)=>{……} 当函数体中只有一个表达式时,{}和return可以省略,当函数体中形参只有一个时,()可以省略。
特点:箭头函数中的this始终指向箭头函数定义时的离this最近的一个函数,如果没有最近的函数就指向window。
//省略写法 var people = name => 'hello' + name; var getFullName = (firstName, lastName) => { var fullName = firstName + lastName; return fullName; }
4、对象的扩展
(1)、属性的简写。
ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值。
var foo = 'bar'; var baz = {foo}; //等同于 var baz = {foo: foo};
(2)、方法的简写。省略冒号与function关键字。
var o = { method() { return "Hello!"; } }; // 等同于 var o = { method: function() { return "Hello!"; } };
(3)、Object.keys()方法,获取对象的所有属性名或方法名(不包括原形的内容),返回一个数组。
var obj={name: "john", age: "21", getName: function () { alert(this.name)}}; console.log(Object.keys(obj)); // ["name", "age", "getName"] console.log(Object.keys(obj).length); //3 console.log(Object.keys(["aa", "bb", "cc"])); //["0", "1", "2"] console.log(Object.keys("abcdef")); //["0", "1", "2", "3", "4", "5"]
(4)、Object.assign (),assign方法将多个原对象的属性和方法都合并到了目标对象上面。可以接收多个参数,第一个参数是目标对象,后面的都是源对象。
var target = {}; //目标对象 var source1 = {name : 'ming', age: '19'}; //源对象1 var source2 = {sex : '女'}; //源对象2 var source3 = {sex : '男'}; //源对象3,和source2中的对象有同名属性sex Object.assign(target,source1,source2,source3); console.log(target); //{name : 'ming', age: '19', sex: '男'}
5、for...of 循环
是遍历所有数据结构的统一的方法。for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、Generator 对象,以及字符串。
var arr=["小林","小吴","小佳"]; for(var v of arr){ console.log(v); } //小林 //小吴 //小佳
6、import和export
ES6标准中,JavaScript原生支持模块(module)了。这种将JS代码分割成不同功能的小块进行模块化,将不同功能的代码分别写在不同文件中,各模块只需导出公共接口部分,然后通过模块的导入的方式可以在其他地方使用。
export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口。
import用于在一个模块中加载另一个含有export接口的模块。
import和export命令只能在模块的顶部,不能在代码块之中。
//导入部分 //全部导入 import Person from './example' //将整个模块所有导出内容当做单一对象,用as起别名 import * as example from "./example.js" console.log(example.name) console.log(example.getName()) //导入部分 import { name } from './example' //导出部分 // 导出默认 export default App // 部分导出 export class User extend Component {};
7、Promise对象
Promise是异步编程的一种解决方案,将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
它有三种状态,分别是pending-进行中、resolved-已完成、rejected-已失败。
Promise 构造函数包含一个参数和一个带有 resolve(解析)和 reject(拒绝)两个参数的回调。在回调中执行一些操作(例如异步),如果一切都正常,则调用 resolve,否则调用 reject。对于已经实例化过的 promise 对象可以调用 promise.then() 方法,传递 resolve 和 reject 方法作为回调。then()方法接收两个参数:onResolve和onReject,分别代表当前 promise 对象在成功或失败时。
var promise = new Promise((resolve, reject) => { var success = true; if (success) { resolve('成功'); } else { reject('失败'); } }).then( (data) => { console.log(data)}, (data) => { console.log(data)} )
promise的执行过程
setTimeout(function() { console.log(0); }, 0); var promise = new Promise((resolve, reject) => { console.log(1); setTimeout(function () { var success = true; if (success) { resolve('成功'); } else { reject('失败'); } },2000); }).then( (data) => { console.log(data)}, (data) => { console.log(data)} ); console.log(promise); //<pending> 进行中 setTimeout(function () { console.log(promise); //<resolved> 已完成 },2500); console.log(2); //1 //Promise {<pending>} //2 //0 //成功 //Promise {<resolved>: undefined}
8、解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
(1)、数组的解构赋值
数组中的值会自动被解析到对应接收该值的变量中,数组的解构赋值要一一对应 如果有对应不上的就是undefined
var [name, pwd, sex]=["小周", "123456", "男"]; console.log(name) //小周 console.log(pwd)//123456 console.log(sex)//男
(2)、对象的解构赋值
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
var obj={name:"小周", pwd:"123456", sex:"男"} var {name, pwd, sex}=obj; console.log(name) //小周 console.log(pwd)//123456 console.log(sex)//男 //如果想要变量名和属性名不同,要写成这样 let { foo: foz, bar: baz } = { foo: "aaa", bar: "bbb" }; console.log(foz) // "aaa" console.log(foo) // error: foo is not defined
9、set数据结构
Set数据结构,类似数组。所有的数据都是唯一的,没有重复的值。它本身是一个构造函数。
属性和方法:
size 数据的长度
add() 添加某个值,返回 Set 结构本身。
delete() 删除某个值,返回一个布尔值,表示删除是否成功。
has() 查找某条数据,返回一个布尔值。
clear() 清除所有成员,没有返回值。
应用:数组去重。var arr = [1,1,2,2,3]; var s = new Set(arr); console.log(s); //{1, 2, 3} console.log(s.size); //3 console.log(s.add(4)); //{1, 2, 3, 4} console.log(s.delete(4)); //true console.log(s.has(4)); //false s.clear();
10、Spread Operator 展开运算符(...)
(1)、将字符串转成数组
var str="abcd"; console.log([...str]) // ["a", "b", "c", "d"]
(2)、将集合转成数组
var sets=new Set([1,2,3,4,5]) console.log([...sets]) // [1, 2, 3, 4, 5]
(3)、两个数组的合并
var a1=[1,2,3]; var a2=[4,5,6]; console.log([...a1,...a2]); //[1, 2, 3, 4, 5, 6]
(4)、在函数中,用来代替arguments参数
rest参数 …变量名称
rest 参数是一个数组 ,它的后面不能再有参数,不然会报错
function func(...args){ console.log(args);//[1, 2, 3, 4] } func(1, 2, 3, 4); function f(x, ...y) { console.log(x); console.log(y); } f('a', 'b', 'c'); //a 和 ["b","c"] f('a') //a 和 [] f() //undefined 和 []
-
Es6 和 同步异步任务
2021-10-17 20:43:49导入其它模块成员使用 import 关键字 向外共享模块成员使用 export 关键字 1.2 在 node.js 中体验 ES6 模块化 node.js 中默认仅支持 CommonJS 模块化规范,若想基于 node.js 体验与学习 ES6 的模块化语法,...1. Es6 模块化
1.1 ES6 模块化规范中定义:
-
每个 js 文件都是一个独立的模块
-
导入其它模块成员使用 import 关键字
-
向外共享模块成员使用 export 关键字
1.2 在 node.js 中体验 ES6 模块化
node.js 中默认仅支持 CommonJS 模块化规范,若想基于 node.js 体验与学习 ES6 的模块化语法,可以进行如下配置:
-
确保安装了 v14.15.1 或更高版本的 node.js
-
node -v 命令可查看
-
-
在 package.json 的根节点中添加 "type": "module" 节点
1.3 ES6 模块化的基本语法
-
默认导出与默认导入
// export default 默认导出的成员 let n1 = 10; let n2 = () => console.log('hello') export default { n1, n2 } //每个模块中,只允许使用唯一的一次 export default,否则会报错! // import 接收名称 from '模块标识符'
-
按需导出与按需导入
-
// export 按需导出的成员 export let s1 = 'sss'; export let s2 = () => console.log('hello');
-
//import { s1 } from '模块标识符' // 每个模块中可以使用多次按需导出 // 按需导入的成员名称必须和按需导出的名称保持一致 // 按需导入时,可以使用 as 关键字进行重命名 // 按需导入可以和默认导入一起使用
-
-
直接导入并执行模块中的代码
// import '模块标识符' // 如果只想单纯地执行某个模块中的代码,并不需要得到模块中向外共享的成员,可以执行该代码
2. Promise
2.1 回调地狱
多层回调函数的相互嵌套,就形成了回调地狱. 其缺点
-
代码耦合性太强,牵一发而动全身,难以维护
-
大量冗余的代码相互嵌套,代码的可读性变差
为了解决回调地狱的问题,ES6 中新增了 Promise 的概念。
2.2 Promise 的基本概念
-
Promise 是一个构造函数
-
创建 Promise 的实例 const p = new Promise()
-
new 出来的 Promise 实例对象,代表一个异步操作
-
-
Promise.prototype 上包含一个 .then() 方法
-
每一次 new Promise() 构造函数得到的实例对象,都可以通过原型链的方式访问到 .then() 方法,例如 p.then()
-
-
.then() 方法用来预先指定成功和失败的回调函数
// p.then(成功的回调函数,失败的回调函数) // p.then(result => { }, error => { }) // 调用 .then() 方法时,成功的回调函数是必选的、失败的回调函数是可选的
2.3 .then() 方法的特性
如果上一个 .then() 方法中返回了一个新的 Promise 实例对象,则可以通过下一个 .then() 继续进行处理。通过 .then() 方法的链式调用,就解决了回调地狱的问题。
2.4 通过 .catch 捕获错误
在 Promise 的链式操作中如果发生了错误,可以使用 Promise.prototype.catch 方法进行捕获和处理
2.5 Promise.all() 方法
Promise.all() 方法会发起并行的 Promise 异步操作,等所有的异步操作全部结束后才会执行下一步的 .then操作(等待机制)
2.6 Promise.race() 方法
Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就立即执行下一步的 .then 操作(赛跑机制) .
3. async 和 await
3.1 什么是 async/await
async/await 是 ES8(ECMAScript 2017)引入的新语法,用来简化 Promise 异步操作。
3.2 async/await 的使用注意事项
-
如果在 function 中使用了 await,则 function 必须被 async 修饰
-
在 async 方法中,第一个 await 之前的代码会同步执行,await 之后的代码会异步执行
async function fn(){ const r1 = await Promise 对象 } // 具名函数 async const fn1 = async () => { const r1 = await Promise 对象 }// 匿名函数
4. EventLoop
4.1 JavaScript 是单线程的语言
JavaScript 是一门单线程执行的编程语言。也就是说,同一时间只能做一件事情。如果前一个任务非常耗时,则后续的任务就不得不一直等待,从而导致程序假死的问题。
4.2 同步任务和异步任务
为了防止某个耗时任务导致程序假死的问题,JavaScript 把待执行的任务分为了两类:
-
同步任务(synchronous)
-
又叫做非耗时任务,指的是在主线程上排队执行的那些任务 只有前一个任务执行完毕,才能执行后一个任务
-
-
异步任务(asynchronous)
-
又叫做耗时任务,异步任务由 JavaScript 委托给宿主环境进行执行
-
当异步任务执行完成后,会通知 JavaScript 主线程执行异步任务的回调函数
-
4.3 同步任务和异步任务的执行过程
-
同步任务由 JavaScript 主线程次序执行
-
异步任务委托给宿主环境执行
-
已完成的异步任务对应的回调函数,会被加入到任务队列中等待执行
-
JavaScript 主线程的执行栈被清空后,会读取任务队列中的回调函数,依次序执行
-
JavaScript 主线程不断重复上面的第 4 步
JavaScript 主线程从“任务队列”中读取异步任务的回调函数,放到执行栈中依次执行。这个过程是循环不断的,所以整个的这种运行机制又称为 EventLoop(事件循环)
5. 宏任务和微任务
JavaScript 把异步任务又做了进一步的划分,异步任务又分为两类,分别是:
-
宏任务(macrotask)
-
异步 Ajax 请求、
-
setTimeout、setInterval、
-
文件操作
-
其它宏任务
-
-
微任务(microtask)
-
Promise.then、.catch 和 .finally
-
process.nextTick
-
其它微任务
-
5.1 宏任务和微任务的执行顺序
每一个宏任务执行完之后,都会检查是否存在待执行的微任务,如果有,则执行完所有微任务之后,再继续执行下一个宏任务。
-
-
ES6新特性有哪些?
2022-03-11 12:22:47ES6新特性有哪些? 一、新的原始类型和变量声明 1,symbol 在ES6之前,我们知道JavaScript支持8种数据类型:Object,String,Boolean,Number,Null,Undefined、Array、Function。现在,ES6新增了一种原始数据类型...ES6新特性有哪些?
一、新的原始类型和变量声明
1,symbol
在ES6之前,我们知道JavaScript支持8种数据类型:Object,String,Boolean,Number,Null,Undefined、Array、Function。现在,ES6新增了一种原始数据类型:symbol,表示独一无二的值,即每个symbol类型的值都不相同。这让我想起了另一个特殊的值:NaN,想一想,他们是不是有一点类似呢!
var sy = Symbol('test'); var sy1 = Symbol('test'); console.log(tepeof sy); //'symbol' sy == sy1; //false var sy2 = new Symbol('test'); //error : Symbol is not a constructor
创建symbol数据类型的值时,需要给Symbol函数传递一个字符串,并且有一点特殊的是:不能使用new关键字调用它。另外,每个symbol类型值都是独一无二的,即使传递的是相同的字符串。
2,let和const
ES6新增了两个声明变量的关键字:let和const。
他们声明的变量仅在let和const关键字所在的代码块内起作用,即在使用let和const的那一对大括号{}内起作用,也称块级作用域(ES6之前只有函数作用域和全局作用域)。
let和const声明变量不会在预编译过程中有提升行为(在全局声明也不会变成window的属性),且同一变量不能重复声明。所以要使用这类变量,只能在let和const关键字之后使用它们。
let和const关键字还有一个特性:“暂时性死区”,即在使用了该关键字的块级作用域中,其内部使用let和const关键字声明的变量与外部作用域中的变量相互隔绝,互不影响。即使是同名变量。
var a = 1; { console.log(a); //error Cannot access 'a' before initialization let a = 0; console.log(a); //0 } console.log(a); //1
const用来声明一个常量,声明时必须赋值,且一旦声明就不能改变。
其实说const变量不能更改是不准确的,请看下面的例子:
const obj = { name:'ren', age:12 }; obj = {}; //error obj.sex = male; consol.log(obj); //{name:'ren',age:12;sex:'male'}
const声明的如果是一个原始值,那么上面的说法是准确的,如果const声明的是一个引用值,那么更准确的说法应该是一个不能被重新赋值的变量。
3,解构赋值
解构赋值是对赋值运算符的扩展。它是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
let [a,b,c] = [1,2,3]; console.log(a,b,c); //1,2,3 let [a,b,c] = [1,,3]; console.log(a,b,c); //1,undefined,3 let [a,,b] = [1,2,3]; console.log(a,b);//1,3 let [a,..b] = [1,2,3]; //...是剩余运算符,表示赋值运算符右边除第一个值外剩余的都赋值给b console.log(a,b);//1,[2,3]
事实上所有可枚举(iterable)的对象都可以使用解构赋值,例如数组,字符串对象,以及ES6新增的Map和Set类型。
let arr = 'hello'; let [a,b,c,d,e] = arr; console.log(a,b,c,d,e); //'h','e','l','l','o'
对象的解构赋值和数组类似,不过左边的变量名需要使用对象的属性名,并且用大括号{}而非中括号[]:
let obj = {name:'ren',age:12,sex:'male'}; let {name,age,sex} = obj; console.log(name,age,sex); //'ren' 12 'male' let {name:myName,age:myAge,sex:mySex} = obj; //自定义变量名 console.log(myName,myAge,mySex); //'ren' 12 'male'
二 新的对象和方法
1,Map和Set
Map对象用于保存键值对,任何值JavaScript支持的值都可以作为一个键或者一个值。这听起来和对象差不多啊?其实它们还是有区别的:
a) object的键只能是字符串或ES6的symbol值,而Map可以是任何值。
b) Map对象有一个size属性,存储了键值对的个数,而object对象没有类似属性。
let myMap = new Map([['name','ren'],['age',12]]); console.log(myMap); //{'name'=>'ren','age'=>12} myMap.set('sex','male'); console.log(myMap); //{'name'=>'ren','age'=>12,'sex'=>'male'} myMap.get('name'); //'ren' myMap.has('age'); //true myMap.delete('age'); //true myMap.has('age'); //false myMap.get('age'); //undefined
Map构造函数接收一个二维数组来创建一个Map对象。数组元素的第0位表示Map对象的key,第1位表示Map对象的value。
Map对象使用set方法来新增数据,set方法接收两个参数,第一个表示key,第二个表示value。使用get方法获取数据,参数是对象的key。
Map对象使用delete方法来删除数据,接收一个参数,表示需要被删除的key。
Map对象使用has方法检测是否已经具有某个属性,返回boolean值。
Set对象和Map对象类似,但它是用来存储一组唯一值的,而不是键值对。类似数组,但它的每个元素都是唯一的。
let mySet = new Set([1,2,3]); console.log(mySet); //{1,2,3} mySet.add(4); console.log(mySet); //{1,2,3,4} mySet.delete(1); //true mySet.has(1); //false
利用Set对象唯一性的特点,可以轻松实现数组的去重:
let arr = [1,1,2,3,4,4]; let mySet = new Set(arr); let newArr = Array.from(mySet); console.log(newArr); //[1,2,3,4]
2,对象新特性
创建对象的字面量方式可以更加简洁。直接使用变量名作为属性,函数体作为方法,最终变量值变成属性值,函数名变成方法名。
let name = 'ren'; let age = 12; let myself = { name, age, say(){ console.log(this.name); } }; console.log(myself); //{name:'ren',age:12,say:fn} myself.say(); //'ren'
对象的拓展运算符(…)三点。用于拷贝目标对象所有可遍历的属性到当前对象。
let obj = {name:'ren',age:12}; let person = {...obj}; console.log(person);//{name:'ren',age:12} obj == person;//false let another = {sex:'male'}; let someone = {...person,...another};//合并对象 console.log(someone);//{name:'ren',age:12,sex:'male'}
ES6对象新增了两个方法,assign和is。
assign用于浅拷贝源对象可枚举属性到目标对象。
let source = {a:{ b: 1},b: 2}; let target = {c: 3}; Object.assign(target, source); console.log(target); //{c: 3, a: {b:1}, b: 2} source.a.b = 2; console.log(target.a.b); //2
如果有同名属性,那么目标对象的属性值会被源对象的属性值覆盖。所以数组的表现就有一点特别了:
Object.assign([1,2,3],[11,22,33,44]);//[11,22,33,44]
数组的index就是属性名,当使用assign方法时,从第0位开始,目标数组的值便开始被源数组的值覆盖了。
is方法和(===)功能基本类似,用于判断两个值是否绝对相等。
Object.is(1,1);//true Object.is(1,true);//false Object.is([],[]);//false Object.is(+0,-0);//false Object.is(NaN,NaN);//true
他们仅有的两点区别是,is方法可以区分+0还是-0,还有就是它认为NaN是相等的。
3,字符串新方法
includes()判断字符串是否包含参数字符串,返回boolean值。如果想要知道参数字符串出现的位置,还是需要indexOf或lastIndexOf方法。
startsWith()/endsWith(),判断字符串是否以参数字符串开头或结尾。返回boolean值。这两个方法可以有第二个参数,一个数字,表示开始查找的位置。
let str = 'blue,red,orange,white'; str.includes('blue');//true str.startsWith('blue');//true str.endsWith('blue');//false
repeat()方法按指定次数返回一个新的字符串。如果次数是大于0的小数则向下取整,0到-1之间的小数则向上取整,其他负数将抛出错误。
console.log('hello'.repeat(2));//'hellohello' console.log('hello'.repeat(1.9));//'hello' console.log('hello'.repeat(-0.9));//'' console.log('hello'.repeat(-1.9));//error
padStart()/padEnd(),用参数字符串按给定长度从前面或后面补全字符串,返回新字符串。
let arr = 'hell'; console.log(arr.padEnd(5,'o')); //'hello' console.log(arr.padEnd(6,'o')); //'helloo' console.log(arr.padEnd(6)); //'hell ',如果没有指定将用空格代替 console.log(arr.padStart(5,'o')); //'ohell'
另外,如果字符串加上补全的字符串超出了给定的长度,那么,超出的部分将被截去。
4,数组的新方法
of()是ES6新增的用于创建数组的方法。of把传入的参数当做数组元素,形成新的数组。
let arr = Array.of(1,'2',[3],{}); console.log(arr); //[1,'2',[3],{}]
from()方法可以将可迭代对象转换为新的数组。函数可接受3个参数:第一个表示将被转换的可迭代对象,第二个是回调函数,将对每个数组元素应用该回调函数,然后返回新的值到新数组,第三个是回到函数内this的指向。后两个参数是可选的。
let obj = { double(n) { return n * 2; } } let arr = [1, 2, 3]; console.log(Array.from(arr, function (n){ return this.double(n); }, obj)); // [2, 4, 6]
find()和findIndex(),查找数组中符合条件的元素值或索引,方法不会修改原数组。
接受一个回调函数作为参数,函数可以接受四个参数,分别是当前遍历到的元素,当前遍历到的索引,数组本身以及函数内this的指向。方法会把回调函数作用于每一个遍历到的元素,如果遍历到某一个元素可以使回调函数返回true,那么find方法会立即返回该元素,findIndex方法会返回该元素的索引。并终止继续遍历。
如果有多个符合条件的,也将只返回第一个。如果遍历完整个数组也无法是回调函数返回true,那么find方法将返回undefined,findIndex方法将返回-1。
let arr = [1,2,3,4,5]; console.log(arr.find((ele) => { return ele === 1; }));//1 console.log(arr.findIndex((ele) => { return ele > 4; })); //4
fill()/copyWithin(),替换数组中部分元素,会修改原数组。
let arr = [1,2,3,4,5]; console.log(arr.fill(0,0,3));//[0,0,0,4,5] //参数1表示目标值,参数2,3表示替换的始末位置,左闭右开区间。 console.log(arr.copyWithin(0,2,4));//[0,4,0,4,5] //参数1表示修改的起始位置,参数2,3表示用来替换的数据的始末位置,左闭右开区间。
fill()用指定的值替换,copyWithin()使用数组中原有的某一部分值替换。
includes()用于检测数组是否包含某个值,可以指定开始位置。
let arr = [1,2,3,4,5]; console.log(arr.includes(2));//true console.log(arr.includes(1,1));//false
三、函数
1,参数默认值
ES6首次添加了参数默认值。我们再也不用在函数内部编写容错代码了。
function add(a=1,b=2){ return a + b; } add();//3 add(2);//4 add(3,4);//7
和参数默认值一起,ES6还带来了不定参。它的功能和使用arguments差不多。
function add(...num){ return num.reduce(function(result,value){ return result + value; }); } add(1,2,3,4);//10
下面介绍的箭头函数没有arguments属性,如果箭头函数内要实现不定参,上述方式就是一个不错的选择了。
2,箭头函数
箭头函数实现了一种更加简洁的书写方式,并且也解决了关键字声明方式的一些麻烦事儿。箭头函数内部没有arguments,也没有prototype属性,所以不能用new关键字调用箭头函数。
箭头函数的书写方式:参数 => 函数体。
let add = (a,b) => { return a+b; } let print = () => { console.log('hi'); } let fn = a => a * a; //当只有一个参数时,括号可以省略,函数体只有单行return语句时,大括号也可以省略,强烈建议不要省略它们,是真的难以阅读
当函数需要直接返回对象时,你必须使用小括号把对象包裹起来。否则将抛出错误。
const fn = () =>{name:'ren',age:12}; // SyntaxError ******************************************* const fn = () =>({name:'ren',age:12});
箭头函数和普通函数最大的区别在于其内部this永远指向其父级AO对象的this。
普通函数在预编译环节会在AO对象上添加this属性,保存一个对象(请参照《JavaScript之深入对象(二)》)。每个普通函数在执行时都有一个特定的this对象,而箭头函数执行时并不直接拥有this属性,如果你在箭头函数中使用this,将根据函数作用域链,直接引用父级AO对象上this绑定的对象。普通函数的AO对象只有在函数执行时才产生,换言之,普通函数的this是由函数执行时的环境决定。而箭头函数的特别之处在于,当函数被定义时,就引用了其父级AO对象的this,即箭头函数的this由定义时的环境决定。
根据箭头函数的特点,不难推测:如果定义对象的方法直接使用箭头函数,那么函数内的this将直接指向window。
var age = 123; let obj = { age:456, say:() => { console.log(this.age); } }; obj.say(); //123 //对象是没有执行期上下文的(AO对象),定义对象的方法实际上是在全局作用域下,即window
如果你一定要在箭头函数中让this指向当前对象,其实也还是有办法的(但是没必要这么麻烦啊,直接使用普通函数不是更好吗?):
var age = 123; let obj = { age:456, say:function(){ var fn = () => { console.log(this.age); } return fn(); } }; obj.say(); //456
我们来分析一下这是怎么做到的:首先,我们使用obj调用say方法时,say内创建了AO对象,并且该AO对象的this属性指向了obj(这里不明白的请回去复习一下我的《JavaScript之深入函数/对象》),然后,say内部又声明了一个箭头函数。我们说箭头函数在声明时就要强行引用父级AO的this属性,那么现在该箭头函数的父级AO是谁呢?当然就是say的AO啦,所以这里箭头函数的this直接就绑定了obj,最后箭头函数在执行时拿到的this,实际上就是say方法的AO.this,即obj本身。
上面是在对象中使用箭头函数,如果那让你难于理解,那么请看下面这种方式:在普通函数中使用箭头函数。
var obj = {name:'ren'}; function test(){ var fn = () => { console.log(this); }; fn(); } test(); //window test.call(obj); //{name:'ren'}
test函数在全局执行时,其this指向window,这时也产生了箭头函数的定义,于是箭头函数内的this也被指向了window,所以最终打印出window对象。
当我们手动改变test函数执行时this的指向时,箭头函数定义所绑定的this实际上也被我们修改了。所以最终打印出obj。
四、class(类)
class 作为对象的模板被引入ES6,你可以通过 class 关键字定义类。class 的本质依然是一个函数。
1,创建类
class Ex { //关键字声明方式 constructor(name){ this.name = name; this.say = () => { console.log(this.name); } } methods(){ console.log('hello ' + this.name); } static a = 123; static m = () => { console.log(this.a); }; } //let ex = class{} 字面量方式 var example = new Ex('ren'); example.say(); //'ren' Ex.m(); //123 example.methods(); //'hello ren' constructor是创建类必须的方法,当使用new调用类创建实例时,将自动执行该方法,该方法和构造函数类似,默认返回this对象。实例的方法和属性都定义在constructor内部。相当于构造函数的this方式。 类保留了prototype属性,类中的方法不需要使用function关键字,并且方法之间不需要逗号隔开。类中定义的方法实际上还是保存在类的prototype属性上。 使用static关键字定义类的静态属性和方法。类中不能定义共有属性,要想定义实例的共有属性还是需要使用prototype属性:Ex.prototype.属性名 = 属性值。 创建实例依然使用new关键字。 2、类的继承 类的继承通过extends关键字实现。 class Person { constructor (name,age){ this.name = name; this.age = age; } say(){ console.log(this.name + ':' + this.age); } } class Student extends Person{ constructor (name,age,sex){ super(name,age); this.sex = sex; } } var student = new Student('ren',12,'male'); student.name; //'ren' student.sex; //'male' student.say(); //'ren:12'
子类继承自父类,不会隐式的创建自己的this对象,而是通过super()引用父类的this。这个过程和在子构造函数内使用父构造函数call(this)很像,但他们有本质的区别。另外,ES6规定,super()必须在子类的this之前执行。所以一般我们把super()放在子类constructor方法的第一行,这样准没错!
五、模块导入和导出
1,导入
ES6使用关键字 import 导入模块(文件),有两种常用的方式:
import ‘模块名称’ from ‘路径’; import ‘路径’;
通过 import…from 的方式引入模块,模块名称实际上相当于定义一个变量,用来接收即将导入的模块。
路径可以有很多方式,既可以是绝对路径,也可以是相对路径,甚至只是一个简单的模块名称,更甚至连文件后缀都不需要。当你使用该命令时,系统会自动从配置文件中指定的路径中去寻找并加载正确的文件。
import Vue from "vue"; //完整路劲其实是 "../node_modules/vue/dist/vue.js";
通过 import… 的方式一般用来引入样式文件或预处理文件,因为他们不需要用变量来接收。
2,导出
ES6 通过 export 和export default 导出模块。导出的含义是向外暴露、输出,在一个文件中通过 import 导入另一个文件,通过变量即可以接收到导出的数据了。一般情况下,JS文件可以向外输出变量、函数和对象。
let name = 'ren',age = 12; export {name,age}; //注意:变量需要用大括号包裹,然后才能向外输出
如果仅需向外暴露一个变量:
export var name = 'ren';
使用 export 向外输出函数的用法和变量相同,这里不再举例。
总结:使用 export 向外输出成员时,可以同时输出多个,并且必须用‘{}’大括号包裹,在其他地方使用 import 导入时,接收成员的变量名必须和这里输出的名称一致,同时,可以根据实际情况,仅接收实际需要的的成员(接收的时候也要用大括号包裹)。
如果希望通过 export 向外暴露成员,并且在导入的时候自定义接收名称,那么你可以使用 as 关键字重命名。
let name = 'ren', age = 12; export {name, age}; import {name as myName, age as myAge} from 'url';
与 export 相比,export default 有以下几点不同:首先,在同一个模块中,export default 只允许向外暴露一次成员;然后,这种方式可以使用任意的名称接收,不像 export 那样有严格的要求;最后,export 和 export default 可以在同一模块中同时存在。
let person = {name:'ren'}; let age = 12; let address = 'cd'; export default person; export {age}; export {address}; import man,{age,address} from 'url'
小技巧:通常 import 无法直接被浏览器识别,即如果在HTML文档中引入的 JS 文件直接使用了 import 关键字,浏览器会报错。要想直接在被HTML文档引用的 JS 文件中使用 import,需要给该
六 异步机制
ES6新增了两种实现异步的新机制,Promise和Generator。文笔有限,怕讲的不清楚,误人子弟,请有兴趣的同学去下面的链接继续学习,廖老师的教程也是受很多人推崇的,当然MDN更官方。
1,Promise
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544
2,Generator
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Generator
https://www.liaoxuefeng.com/wiki/1022910821149312/1023024381818112
-
ES6模块化与异步编程高级用法
2022-04-09 17:19:19为什么是 ES6 模块化规范 ES6 模块化规范是浏览器端与服务器端通用的模块化开发规范。它的出现极大的降低了前端开发者的模块化学 习成本,开发者不需再额外学习 AMD、CMD 或 CommonJS 等模块化规范。 一、ES6 模块... -
ES6 import / export / export default
2021-05-17 15:20:19在 ES6 之前,实现模块化使用的是 CommonJS 和 AMD 两种。前者更适合用于服务器,后者更适合用于浏览器。RequireJS 就是 AMD 最流行的实现...ES6 的模块功能主要由两个命令构成:export 和 import。 export 命令用于规 -
Es6新特性有哪些?
2020-04-21 09:48:56箭头操作符 =>; 对类class的支持(constructor构造函数); 不定参数...x;let和const关键字; ...模块的支持import;...promise异步函数的处理模式(pending等待中;...在ES6中,可以使用解构从数组和对象提取值... -
你知道ES5 和 ES6 的区别吗?,能说出说几个 ES6 的新增方法吗?
2021-08-19 18:19:00目录 ES5 和 ES6 的区别 ES6 的新增方法 1、新增声明命令 let 和 const 1.1)特点 ...2、模板字符串(Template String) ...6、import 和 export 7、Promise 对象 8、解构赋值 8.1)数组的解构赋值 8.2) -
ES6模块化的import和export用法方法总结
2020-11-30 18:57:15ES6之前已经出现了js模块加载的方案,最...ES6模块主要有两个功能:export和import export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口 import用于在一个模块中加载另一个含有export接口的模块。 也就 -
ES6的内容有哪些?超级详细解析
2021-07-06 17:16:36ES6内容1、const 和 let2、箭头函数,箭头函数的this指向3、数组新方法4、模板字符串5、解构赋值6、扩展运算符(... 三个点)和 函数默认值7、class类 和继承8、JSON的应用9、Promise的应用10、async,await组合应用... -
es6--同步与异步
2021-08-13 16:43:221 Promise:对异步操作做了一个统一封装。 let p = new Promise((resolve,reject)=>{ $.ajax({ url:"data/a.json", dataType:"json", success(data){ resolve(data); }, err(res){ reject(res) } }) }... -
es6异步加载
2018-10-06 11:20:53import _ from 'lodash' fetchSuggest: _.debounce(function () {}, 500), 用户输入 在判断 用户连续输入的 情况下 不执行查询操作,一旦用户输入间隔超过500ms 执行查询操作... -
es6 import()函数
2021-02-19 14:04:31import()函数 简介 前面介绍过,import命令会被 JavaScript 引擎静态分析,先于模块内的其他模块执行(叫做”连接“更合适)。所以,下面的代码会报错。 // 报错 if (x === 2) { import MyModual from './... -
ES6 import()
2021-05-26 02:49:53前面介绍过,import命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行(import命令叫做“连接” binding 其实更合适)。所以,下面的代码会报错。 // 报错 if (x === 2) { import MyModual from './... -
JavaScript ES6中export、import与export default的用法和区别
2021-01-19 17:55:39ES6 import和export的用法 ES6之前已经出现了js模块加载的方案,最主要的是CommonJS和AMD规范。commonjs主要应用于服务器,实现同步加载,如nodejs。AMD规范应用于浏览器,如requirejs,为异步加载。同时还有CMD规范... -
ES6 新增特性有那些?
2021-06-03 00:28:31ES6新增了许多新特性,不是因为面试经常会问才需要会它,个人认为里面的许多方法特别简单 下面是我整理的一些比较常用的新增特性 一、新增数据类型 Symbol 猿话:Symbol-ES6神奇的数据类型zhuanlan.zhihu.... -
面试官:你是怎么理解ES6中Module的?使用场景?
2021-01-21 08:31:00ES6设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量 // ES6模块 import { stat, exists, readFile } from 'fs'; 上述代码,只加载3个方法,其他方法不加载,即 ES6 可以... -
详解es6的export和import命令
2021-10-11 11:20:34### 1、概述 一直以来开发vue项目,对export和import的用法都比较模糊,看别人怎么写...为此ES6新增了export和import命令实现了模块功能,而且它的实现方式简单得不可思议,完全取代了CommonJS和AMD,现已成为浏览... -
day-09-es6模块化和异步编程高级 import export
2021-06-10 20:43:12第一次执行node的es6模块化 (1)确保node版本,14.15.1以上 node -v (2)生成package.json npm init -y (3)修改package.json "type":"module", 注意:如果是中文有空格的路径文件夹,那么手动创建package.json (4)写代码 ... -
CommonJS 和 ES6 Module 究竟有什么区别?
2021-06-17 15:09:43CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。 CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。...CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载 -
ES6 import和Node require
2019-05-22 16:54:06ES6之前已经出现了js模块加载的方案,最主要的是CommonJS和AMD规范。commonjs主要应用于服务器,实现同步加载,如nodejs。AMD规范应用于浏览器,如requirejs,为异步加载 require的基本语法 核心概念:在导出的... -
common-JS 中的 require/exports 和 ES6 中 import/export 的区别是什么?
2022-06-15 12:59:14ES6 模块是动态引用,如果使用 import 从一个模块加载变量,那些变量不会缓存,而是成 为 一个指向被加载模块的引用,import/export 最终都是编译为 require/exports 来执行的 require/exports来自野生规范当中,即... -
ES6语法之export、export defalut、import的用法
2022-05-28 18:16:56之前一直搞不懂export、export defalut、import之间的关系,总是模模糊糊靠猜,认真学习了下,现在我又行了 -
ES6模块化与异步编程
2021-08-01 15:39:481ES6模块化 2Promise 3asycn/await 4EventLoop 5宏任务与微任务 6数据库API接口 1ES6模块化 其实以前的文章也涉及到过ES6点的相关知识,但是总结的不算太完全,并且并没有深刻的认识。所以我又重新对知识点... -
ES6模块化与异步编程学习笔记
2022-03-20 11:58:11ES6模块化与异步编程学习笔记 -
ES6 import Export 把一个js文件导入另一个js
2021-08-10 20:43:44文件结构: 导出:export_0.js let myName = "Tom"; let myAge = 20; let myfn = function(){ return "My name is" + myName + "! I'm '" + myAge + "years old." ...let myClass = class myClass { ...导入:es6.