var、let 和 const的区别
-
var变量
- var 声明的变量会被提升到作用域的顶部
- var 声明的变量会被挂载到window上
-
let和const
- let 和 const 作用基本一致,但是const声明的变量不能再次赋值
- 不会被挂载到window上
提升(hoisting)
console.log(a)
var a = 1
虽然我们还没声明这个a,但是我们却可以打印这个a,并且输出undefined,这种情况就叫做提升,并且提升的是声明。
不仅变量会提升,而且函数也会提升。
console.log(a)
function a(){
}
var a = 1
上面代码中,打印结果会是ƒ a(){ },及时也声明了变量a。
说明函数提升优于变量提升。
为什么需要提升?
提升存在的根本原因是为了解决函数互相调用的情况
function test1{
test2()
}
function test2{
test1()
}
Class
class MathHandle{
constructor(x,y){
this.x = x;
this.y =y;
}
add(){
return this.x + this.y
}
}
const m = new MathHandle(3,2);
console.log(m.add())
class是js构造函数的语法糖,本质就是函数
typeof MathHandle 输出function
MathHandle === MathHandle.prototype.constructor 输出true
Class继承
class Parent{
constructor(value){
this.val = value
}
getValue(){
console.log(this.val)
}
}
class Child extends Parent{
construct(value){
super(value){
this.val = value
}
}
}
let child = new Child();
这段代码可以看成Parent.call(this,value)
child instanceof Parent 输出true
子类构造函数中必须调用super
Class总结:
- Class在语法上更加贴合面向对象的写法
- Class实现继承更容易解读
- 更易于写java等后端人员使用
- 本质还是使用protoype
Promise
Promise是什么?
Promise是异步编程的解决方案,它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象
promise的构造函数是匿名函数,他有两个参数,一个是reject,一个是resolve,他们是两个函数
resolve的作用:
- 把promise对象的状态置为成功
- 异步操作结果value作为参数传给成功回调函数。
reject的作用:
- 把promise对象的状态置为失败
- 异步操作错误error作为参数返回失败回调函数。
不使用Promise请求图片
function loadimg(src,callback,fail)
{
var img = document.createElement('img')
img.onload = function(){
callback(img)
}
img.onerror = function(){
fail()
}
img.src = src;
}
var src = 'XXX'//图片链接
loadimg(src,function(img){
console.log(img.width)
},function(){
console.log('failed')
})
使用Promise请求图片
function loadimg(src){
const promise = new Promise(function(reject,resolve){
var img = document.createElement('img');
img.onload = function(){
resolve(img)
}
img.onerror = function(){
reject
}
img.src = src
})
return promise;
}
var src = 'XXX'//图片链接
var result = loadimg(src)
result.then(function(img){
console.log(img)
},function(){
console.log('failed')
})
promise步骤:
- 实例化promise对象
- 传入函数
- 并且return promise
- 成功时执行resolve,失败时执行reject
- then监听结果
catch捕获异常
result.then(function(img){
console.log(img.width)
return img;
}).then(function(img){
console.log(img.height)
}).catch(function(ex){
console.log(ex)
})
Promise.all
Promise.all([result1,result2]).then(datas=>{
console.log(datas[0])
console.log(datas[1])
})
- 接受一个数组作为参数,数组里的元素都是Promise对象的实例,如果不是,就会调用Promise.resolve方法,将参数转为Promise实例,再进一步处理。
- 接收到的datas是一个数组,里面包含着多个promise返回的数组
- 全部完成之后,才执行success
- 当该数组里的某个Promise实例进入了rejected状态,Promise.all返回的实例会立即变成rejected状态,并将第一个rejected的实例返回值传递给Promise.all返回实例的回调函数。
Promise.race
Promise.all([result1,result2]).then(data=>{
console.log(data)
})
- Promise实例并不会等待所有Proimse都跑完,而是只要有一个Promise实例改变状态,它就跟着改变状态。并使用第一个改变状态实例的返回值作为返回值。
- 谁跑得快谁先输出
Promise.resolve
Promise.resolve('foo');
//等价于
new Promise(resolve => resolve('foo'));
- 该方法的作用是将现用对象转换成promise对象
Promise.reject
var p = Promise.reject('出错了');
//等价于
var p = new Promise((resolve,reject) => reject('出错了'));
//注意:Promise的参数为匿名函数,resolve不能写为null
p.then(null,function (s) {
//then的两个参数也都为匿名构造函数
console.log(s)
})
- 会返回一个新的
promise
实例,状态为rejected
Promise标准
-
状态:
- Promise必须处于
pending
,resolved
,rejected
三个状态之一 - 初始状态是
pending
- 状态变化不可逆
- Promise必须处于
-
then:
- Promise实例必须实现then这个方法
- then()必须接收两个函数作为参数
resolve
reject
- then()返回的必须是一个Promise实例
解构赋值
之前js的写法与ES6写法的比较
- 以前js是这么写的
var obj =[a:100,b:200]
var a = obj.a
var b = obj.b
- ES6
const obj =[a:100,b:200,c:300]
const [a,c] = obj;
console.log(a);//100
console.log(c);//300
块级作用域
以前是没有块级作用域的概念的,在for循环内部的变量能被外部访问
多行字符串/模板变量
const html = `
${name}
`
包裹在反引号内
箭头函数
之前js的写法与ES6写法的比较
- 原JS
var arr =[1,2,3]
arr.map(function(item){
item+1
})
- ES6
const arr = [1,2,3]
arr.map(item=>{
item+1
});
arr.map((item,index)=>{
console.log(index)
return item+1
});
Map
- map的作用是生成一个新数组,遍历原数组,将每个元素拿出来做一些变换然后放入新的数组之中。
[1,2,3].map(v => v + 1) // [2,3,4]
map的回调函数接受三个参数,分别是当前索引元素,索引,原数组。
['1','2','3'].map(parseInt)
输出1,NaN,NaN
- parseInt('1', 0) -> 1
- parseInt('2', 1) -> NaN
- parseInt('3', 2) -> NaN
插入一下parseInt函数
parseInt(string, radix)
radix : 如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数,另外该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。
parseInt("10"); //返回 10
parseInt("19",10); //返回 19 (10+9)
parseInt("11",2); //返回 3 (2+1)
parseInt("17",8); //返回 15 (8+7)
parseInt("1f",16); //返回 31 (16+15)
parseInt("010"); //未定:返回 10 或 8
filter
- filter的作用也是生成一个新数组,遍历数组的时候,将返回值为true的元素放入新数组。
let array = [1,2,4,6]
let newArray = array.filter(item=>item!=6)
console.log(newArray)
输出1,2,4
reduce
将数组里的全部元素相加得到一个值,可能会这么写
const arr=[1,2,3,4];
let total = 0;
for(let i = 0;i < arr.length;i++){
total += arr[i]
}
console.log(total)
使用reduce就可以优化成一行代码
const arr = [1,2,3,4]
const sum = arr.reduce((acc,current)=>acc+current,0)
console.log(sum)
-对于reduce来说,它接受两个参数,一个是回调函数,一个是初始值。接下来我们来讲一下reduce的过程:
- 首先初始值为 0,该值会在执行第一次回调函数时作为第一个参数传入
- 回调函数接受四个参数,分别为累计值、当前元素、当前索引、原数组,后三者想必大家都可以明白作用,这里着重分析第一个参数
- 在一次执行回调函数时,当前值和初始值相加得出结果 1,该结果会在第二次执行回调函数时当做第一个参数传入
- 所以在第二次执行回调函数时,相加的值就分别是 1 和 2,以此类推,循环结束后得到结果 6
模块化
为什么要使用模块化?
- 解决命名冲突
- 提供复用性
- 提高代码维护性
在早期,使用了立即执行函数来解决命名冲突,污染全局作用域的问题
(function(globalVariable){
globalVariable.test = function() {}
// ... 声明各种变量、函数都不会污染全局作用域
})(globalVariable)
AMD
Asynchronous Module Definition,异步模块定义,所有的模块将被异步加载,模块加载不影响后面语句运行。所有依赖某些模块的语句均放置在回调函数中。
// AMD
define(['./a', './b'], function(a, b) {
// 加载模块完毕可以使用
a.do()
b.do()
})
CMD
// CMD
define(function(require, exports, module) {
// 加载模块
// 可以把 require 写在函数体的任意地方实现延迟加载
var a = require('./a')
a.doSomething()
})
对于依赖的模块,AMD 是提前执行,CMD 是延迟执行
AMD 推崇依赖前置,CMD 推崇依赖就近
CommonJS
// a.js
module.exports = {
a: 1
}
// or
exports.a = 1
// b.js
var module = require('./a.js')
module.a // -> log 1
ES Module
// 引入模块 API
import XXX from './a.js'
import { XXX } from './a.js'
// 导出模块 API
export function a() {}
export default function() {}