关于javascript:大前端进阶ECMAScript

只有学不死,就往死里学。

概述

ECMAScript是一种能够在宿主环境中执行计算并能操作可计算对象的基于对象的程序设计语言。

ECMAScript是一种语言设计标准,尽管通常也被称为JavaScript,然而严格意义上,ECMAScript并不等于JavaScript,前者是后者的设计标准,后者是前者的具体实现和扩大(在浏览器环境中,JavaScript不仅仅实现了ECMAScript,同时还基于浏览器实现了针对DOM和BOM的操作)。

个性

ECMAScript有很多版本,其中ECMAScript2015最为突出。首先,其扭转了传统的以版本命名的形式,改为以年份命名。其次,其明确了规范公布工夫,由以前的工夫不固定改为一年一个版本。最初,其减少了诸多个性,使js更像现代化编程语言。

ES6能够特指ECMAScript2015, 也能够泛指ECMAScript2015及当前的所有版本。

ECMAScript2015新增的个性能够总结为四大类:

  1. 解决原有语言的有余(let,const,块级作用域等)。
  2. 加强语法(解构,开展,默认参数等)。
  3. 全新的对象,办法,性能(Promise等)。
  4. 全新的数据类型和数据结构(Symbol等)。

块级作用域

在ECMAScript2015以前,js中存在两种作用域:

  1. 全局作用域。
  2. 函数作用域。

ECMAScript2015新增了块级作用域,代码只在相应的代码块中起作用。

// before
if (true) {
    var num = 1
}
console.log(num) // 输入1, 能够在块之外拜访变量

// after
if (true) {
    let num = 1
}
console.log(num) // 抱错,不存在num, num只在{}形成的代码块中起作用

let,const

let,const和var一样,都是申明变量的形式,只是let,const会给变量增加作用范畴,躲避了var带来的诸多问题。

let

  1. let只能先申明,后应用。
// before
console.log(num) // 输入1, 因为浏览器编译js代码的时候,会将变量晋升,因而能够在变量申明前拜访变量
var num = 1

// after
console.log(num)
let num = 1 // 抱错,因为let变量只能先申明后应用。
  1. let申明的变量只能在块级作用域内起作用。
// before
for (var i = 0; i < 3; i++) {
    setTimeout(function () {
        console.log(i) // 输入三次 3, setTimeout在执行时,操作的都是全局作用域中的i变量。
    }, 100)
}

// after
for (let i = 0; i < 3; i++) {
    setTimeout(function () {
        console.log(i) // 输入0, 1, 2, 因为每次setTimeout在执行的时候,都应用的是其作用域内的i,不会相互影响
    }, 100)
}

const

const的用法和let雷同,只不过,const申明的变量是只读的,不能批改。

这里的只读,指的是不能批改变量指向的内存地址,然而能够批改变量的属性。
const obj = {
    name: 'zhangsan'
}
obj.name = 'lisi' // 能够批改
obj = {
    name: 'lisi'
} // 抱错,批改了变量的内存指向地址,指向了新的地址。

解构

解构容许你应用相似数组或对象字面量的语法将数组和对象的属性赋给各种变量。

// before, 用上面的形式获取数组中的每一项,并赋值给对应的变量
let arr = [1, 2, 3]
let a = arr[0]
let b = arr[0]
let c = arr[0]

// after
let [a, b, c] = arr // 解构会将数组中的每一项主动赋值到对应地位的变量
let [, , c] = arr // 如果只想获取第三个,能够传入两个,
let [a, b] = arr // 如果只想获取前两个,能够省略前面。

// 对象也能够解构
let obj = {
    name: 'zhangsan',
    age: 18,
    gender: true
}
let { name, age, gender } = obj // 因为对象属性没有程序,因而须要变量和属性名绝对应的形式解构。
let { address = '北京' } = obj // 能够为不存在的属性默认值
let { name: otherName = 'lisi'} = obj // 能够为某个属性对应的变量重命名

模版字符串

js原有””, ”两种形式示意字符串,ECMAScript2015新增了“示意字符串。

// 模版字符串反对多行字符串,不便蕴含换行符的字符串申明
let div = `<div>
              this is div
           </div>`

let name = 'zhangsan'
let intro = `my name is ${name}` // 能够嵌入变量等任何蕴含返回值的js非法语句,将被替换成返回值。

除了上述根底利用外,还蕴含一种非凡的带标签的模版字符串。

let obj = {
    name: 'zhangsan',
    age: 18,
    gender: 0
}
// 定义标签办法
// strs示意用${}宰割后的字符串数组,后续的参数代表${}对应的计算值
function changeGender(strs, name, gender) {
    console.log(strs, name, gender) // [ '我叫', ',我是', '' ] zhangsan 0

    let g = gender === 0 ? '男人' : '女人'
    return strs[0] + name + strs[1] + g
}

// 应用
console.log(changeGender`我叫${obj.name},我是${obj.gender}`)

字符串扩大

为字符串增加了常见的includes,startsWith,endsWith办法。

const str = 'my name is zhangsan'
console.log(str.includes('name')) // 判断字符串中是否蕴含name
console.log(str.startsWith('my')) // 判断字符串是否以my结尾
console.log(str.endsWith('zhangsan')) // 判断字符串是否以zhangsan结尾

对象字面量加强

增强对象字面量的申明形式,简化申明代码。

let name = 'zhangsan'
let person = {
    // 将同名的变量增加到对象上
    name,
    // 简化对象上办法属性定义
    getName() {
        return this.name
    },
    // []示意计算属性,计算失去的值作为属性的属性名
    [Math.random()]: 18
}

Object.assign

能够将多个对象的属性赋值到指标对象上,有则替换,没有则增加。

let obj = {
    name: 'zhangsan',
    age: 18
}
let obj2 = {
    address: '北京'
}
let person = {
    name: ''
}
console.log(Object.assign(person, obj, obj2))

// 复制一个全新的对象
let copied = Object.assign(person)

Object.is

Object.is能够用于判断值是否相等。

console.log(0 == false) // true, == 会先将值做转换,而后比拟
console.log(0 === false) // false, ===会执行严格的判断
// === 无奈正确辨认的状况
console.log(+0 === -0) // true,
console.log(NaN === NaN) // false , === 认为每个NaN都是独立的一个值
// Object.is能够正确判断上述的两种状况
console.log(Object.is(+0, -0)) // false,
console.log(Object.is(NaN, NaN)) // true 

参数默认值

在函数申明的时候,能够用更简略的形式给参数增加默认值。

// before
function intro(name, age) {
    name = name || 'default'
    console.log(`my name is ${name}`)
}
// after, 默认值参数必须放在非默认值参数的前面
function intro(age, name = 'default') {
    console.log(`my name is ${name}`)
}

残余参数

对于不定个数参数函数,能够用残余参数将某个地位当前的参数放入到一个数组中。

// before
function add() {
    // arguments获取所有变量, arguments是一个伪数组
    return Array.from(arguments).reduce(function (pre, cur) {
        return pre + cur
    }, 0)
}
console.log(add(1, 2, 3))

// after
function intro(name, ...args) {
    console.log(name, args) // zhangsan [ 18, '北京' ]
}
intro('zhangsan', 18, '北京')

参数开展

和默认参数相同,参数开展能够在调用函数的时候将数组中的每一项顺次赋值给函数中相应地位的参数。

function intro(name, age, address) {
    console.log(name, age, address)
}
const arr = ['zhangsan', 18, '北京']
// before
// 1. 利用获取每个地位的值实现
intro(arr[0], arr[1], arr[2])
// 2. 利用apply办法实现
intro.apply(intro, arr)
// after
intro(...arr)

箭头函数

箭头函数能够简化函数的申明,尤其是在回调函数的申明上。

const arr = ['zhangsan', 18, '北京']
// before
arr.forEach(function (item) {
    console.log(item)
})
// after
arr.forEach(item => console.log(item))

箭头函数与一般的function函数的this指向不同,function的this指向调用者的上下文,是在调用时指定,而箭头函数的this是在申明时指定,指向父级的上下文。

const obj = {
    name: 'lisi',
    getName() {
        console.log(this.name)
    }
}
var name = 'zhangsan'
let getName = obj.getName

getName() // zhangsan, window调用,this指向window
obj.getName() // lisi, obj调用,this指向obj
//----------------------------------------------
const obj2 = {
    name: 'lisi',
    getNameFn() {
        return () => {
            console.log(this.name)
        }
    }
}
obj2.getNameFn()() // lisi, 箭头函数的this指向父级上下文,即getNameFn的上下文,因为getNameFn由obj2调用,因而this指向obj2

Promise

能够利用Promise写出更优雅的异步代码,躲避回调天堂。

new Promise(resolve => {
    setTimeout(() => {
        resolve(1)
    }, 100)
}).then(value => {
    setTimeout(() => {
        resolve(value + 1)
    }, 100)
}).then(value => {
    setTimeout(() => {
        resolve(value + 1)
    }, 100)
})

Proxy

通过Proxy代理能够实现对对象编辑获取等操作的拦挡,从而在操作之前实现某种操作(例如Vue3.0就是利用Proxy实现数据双向绑定)。其和Object.defineProperty作用相似,然而相比Object.defineProperty,其语法更为简洁,而且作用范畴更广(如Object.defineProperty没法监控数组项的减少和删除,Proxy能够)。

对象字面量代理

let obj = {
    name: 'zhangsan',
    age: 18
}
let objProxy = new Proxy(obj, {
    get(target, property) {
        console.log(`获取${property}值`)
        return target[property] ? target[property] : 'default'
    },
    set(target, property, value) {
        if (property === 'age') {
            value = value > 25 ? 25 : value
        }
        target[property] = value
    }
})
console.log(objProxy.address) // default
objProxy.age = 18
console.log(objProxy.age) // 18
objProxy.age = 30
console.log(objProxy.age) // 25

Proxy对象实例化时,第二个参数能够传入更多handler,如下图:

数组代理

let arr = [1, 2, 3]
let arrProxy = new Proxy(arr, {
    set(target, property, value) {
        value = value > 10 ? 10 : value
        return target[property] = value
    }
})
arrProxy.push(11)
console.log(arr) //[ 1, 2, 3, 10 ], 拦挡胜利,和push类似的shift,unshift,pop均可触发

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理