乐趣区

关于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 均可触发
退出移动版