ECMAScript
- 它是一种由ECMA组织(前身为欧洲计算机制造商协会)制定和发布的脚本语言规范
- JavaScript 是ECMA的实现
- JS 包含三个部分
- ECMAScript(核心)
- 扩展==》浏览器端
- BOM (浏览器对象模型)
- DOM(文档对象模型)
3.扩展==》服务器端 - Node
- ES的几个重要版本
- ES5:09年发布
- ES6(ES2015):15年发布,也称为ECMA2015
- ES7(ES2016):16年发布,也称为ECMA2016(变化不大)
ES5严格模式
- 目的
- 消除JavaScript语法的一些不合理性,不严谨之处,减少一些怪异行为
- 使用
- 在全局或函数的第一条语句定义为:
'use strict';
- 如果浏览器不支持,只解析为一条简单的语句,没有任何副作用
- 在全局或函数的第一条语句定义为:
- 语法和行为改变
- 必须使用 var 声明变量
- 禁止自定义的函数中的 this 指向 window
- 创建 eval 作用域
- 对象不能有重名的属性
ES_5_json对象扩展
JSON.stringify(obj/arr)
- js 对象(数组)转换为 json 对象(数组)
JSON.parse(json)
- json 对象(数组)转换为js对象(数组)
ES_5 Object 对象扩展
ES5 给 Object 扩展了一些静态方法,常用的2个:
- Object.creat(prototype, [descriptors])
- 作用:以指定对象为原型创建新的对象
- 为新的对象指定新的属性,并对属性进行描述
value
: 指定值
writabkle
: 标识当前属性值是否是可修改的,默认为false
configurable
: 标识当前属性是否可以被删除,默认为false
enumerable
: 标识当前属性是否能用 for in 枚举,默认为false
var obj = {username: 'damu', age: 30}
var obj1 = {}
obj1 = Object.creat(obj, {
set: {
value: 'nan',
writable: true,
configurable: true
}
})
- Object.defineProperties(object, descriptors)
- 作用:为指定对象定义扩展多个属性
get
: 用来获取当前属性值的回调函数
set
: 修改当前属性值触发的回调函数,并且实参即为修改后的值 - 存取器属性:setter,getter 一个用来存值,一个用来取值
- 作用:为指定对象定义扩展多个属性
Object.defineProperties(obj2, {
fullName: {
get: function () {
return this.firstName + ' ' + this.lastName;
}
set: function (data){
console.log('set()', data);
var names = data.split(' ')
this.firstName = names[0]
this.lastName = names[1]
}
}
})
- 对象本身的两个方法
get propertyName(){}
用来得到当前属性值的回调函数set propertyName(){}
用来监视当前属性值变化的回调函数
var obj = {
firstName = 'curry',
lastName = 'stephen',
get fullName(){
return this.firstName + ' ' + this.lastName
},
set fullName(data){
var names = data.split(' ')
this.firstName = names[0]
this.lastName = names[1]
}
}
ES5 数组的扩展
Array.prototype.indexOf(value)
:得到值在数组中的第一个下标Array.prototype.lastIndexOf(value)
:得到值在数组中的最后一个下标Array.prototype.forEach(function(item, index){})
: 遍历数组Array.prototype.map(function(item, index){})
:遍历数组返回一个新的数组,返回加工之后的值Array.prototype.filter(function(item, index){})
:遍历过滤出一个新的子数组,返回条件为true的值
ES5 call,apply,bind用法详解
Function.prototype.bind(obj)
:- 作用:将函数内的 this 绑定为 obj,并将函数返回
- 面试题:区别bind() 与 call() 和 apply()?
- 都能指定函数中的this
- call()/apply()是立即调用函数
- bind() 是将函数返回
ES6
let 和 const
let
- 作用:
- 与 var 类似,用于声明一个变量
- 特点:
- 在块作用域内有效
- 不能重复声明
- 不会预处理,不存在变量提升
预处理又叫预解析
- 应用:
- 循环遍历加监听
- 使用 let 取代 var 是趋势
const
- 作用:
- 定义一个常量
- 特点:
- 不能修改
- 其他特点同 let
- 应用:
- 保存不用改变的数据
变量的解构赋值
- 理解:
- 从对象或数组中提取数据,并赋值给多个变量
- 对象的解构赋值
let {n, a} = {n:'tom', a:12}
- 数组的解构赋值
let [a,b] = [1, 'atguigu'];
- 用途
- 给多个形参赋值
模板字符串
- 模板字符串:简化字符串的拼接
1. 模板字符串必须用反引号
包含
2. 变化的部分使用${xxx}
定义
let obj = {username: 'kobe', age: 39}
str = `我的名字叫: ${obj.username}, 我今年的年龄是: ${obj.age}`
对象的简写方式
简化的对象写法
- 省略同名的属性值
- 省略方法的 function
- 例如:
let x = 1
let y = 2
let point = {
x,
y,
setX (x) {this.x = X}
}
let username = 'kobe'
let age = 39
let obj = {
username, //同名的属性可以省略不写
age,
getName() { //可以省略函数的function
return this.username;
}
}
console.log(obj) //kobe 39
箭头函数
-
作用:定义匿名函数
-
基本语法:
- 没有参数:
() => console.log('xxx')
- 一个参数:
i => i+2
- 大于一个参数:
(i,j) => i+j
- 函数体不用大括号:默认返回结果
- 函数体如果有多个语句,需要用
{}
包围,若有需要返回的内容,需要手动返回
- 没有参数:
-
使用场景,多用来定义回调函数
-
箭头函数的特点:
- 简洁
- 箭头函数没有自己的 this,箭头函数的 this 不是调用的时候决定的,而是在定义的时候处在的对象就是它的 this
- 扩展理解:箭头函数的 this 看外层是否有函数
如果有,外层函数的 this 就是内部箭头函数的this
如果没有,则 this 就是 window
let fun = () => console.log('hello')
fun() //hello
//函数体只有一条语句或者是表达式的时候,{} 可以省略,同时也会自动返回语句执行的结果或者是表达式的结果
let fun1 = (x,y) => x + y
console.log(fun1(1, 2)); //3
let obj = {
name: '箭头函数',
getName: () => {
btn2.onclick = () => {
console.log(this) //window
}
}
}
obj.getName() //等同于 obj.getName() = () => {} 本质也是在 window 下定义的
三点运算符
用途:
- rest(可变)参数
- 用来取代 arguments 但比 arguments 灵活,只能是最后部分形参参数
- arguments 内部有一个
callee
方法,arguments.callee
就是指向函数本身
function fun(...values) {
console.log(arguments);//伪数组
arguments.forEach(function (item, index) {
console.log(item, index)//报错
})
console.log(values);//真数组
values.forEach(function (item, index) {
console.log(item,index)
})
}
fun(1,2,3)
let arr = [1,6]
let arr1 = [2,3,4,5]
arr = [1, ...arr1, 6]
console.log(arr) //[1,2,3,4,5,6]
console.log(...arr) //1 2 3 4 5 6
形参默认值
形参的默认值:当不传入参数的时候默认使用形参里的默认值
function Point(x = 1,y = 2) {
this.x = x
this.y = y
}
let point = new Point()
Promise 对象
- 理解:
- Promise对象,代表了未来某个将要发生的事件(通常是一个异步操作)
- 有了 promise 对象,可以将异步操作以同步的流程表达出来,避免了层层嵌套的回调函数(俗称“回调地狱”)
- ES6的 Promise 是一个构造函数,用来生成 promise 实例
- 使用 promise 基本步骤(2步):
- 创建 promise 对象
let promise = new Promise((resolve, reject) => {
//初始化promise 状态为 pending
//执行异步操作
if(异步操作成功){
resolve(value)//修改promise的状态为fullfilled
} else {
reject(errMsg)//修改promise的状态为rejected
}
})
- 调用promise的then()
promise.then(function{
result => console.log(result)
errorMsg => alert(errorMsg)
})
- promise对象的3个状态
pending
:初始化状态fulfilled
:成功状态rejected
:失败状态
- 应用:
- 使用 promise 实现超时处理
- 使用 promise 封装处理 ajax 请求
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
reject()
}, 2000)
})
promsie
.then((data) => {//成功的回调
console.log('success')
}, (error) => {//失败的回调
console.log('error')
})
function getNews() {
let promise = new Promise((resolve, reject) => {
let xmlHttp = new XMLHTTPRequest()
xmlHttp.onreadystatechange = function () {
if(xmlHttp.readyState === 4) {
if(xmlHttp.status === 200) {
resolve(xmlHttp.responseText)
} else {
reject('error')
}
}
}
xmlHttp.open('GET', url)
xmlHttp.send()
})
return promise
}
getNews('http://localhost:3000/news?id=2')
.then({data} => {
console.log(data)
let commenUrl = JSON.parse(data).commentsUrl
let url = 'http://localhost:3000' + commentsUrl;
return getNews(url)
}, (error) => {
console.log(error)
})
.then((data) => {
console.log(data)
}, () => {
console.log('error')
})
symbol
前言:ES5中对象的属性名都是字符串,容易造成重名,污染环境
Symbol:
- 概念:ES6中的添加了一种原始数据类型symbol(已有的原始数据类型:String, Number, boolean, null, undefinded, 对象)
- 特点:
- Symbol属性值对应的值是唯一的,解决命名冲突问题
- Symbol 值不能与其他数据类型进行计算,包括字符串拼接
for in, for of
遍历时不会遍历symbol属性
- 使用:
- 调用Symbol函数得到 symbol 值
let symbol = Symbol()
let obj = {}
obj[symbol] = 'hello'
2. 传参标识
let symbol = Symbol('one')
let symbol2 = Symbol('two')
console.log(symbol);//Symbol('one')
console.log(symbol2);//Symbol('two')
3. 内置Symbol值
- 除了定义自己使用的Symbol 值以外,ES6 还提供了11个内置的 Symbol 值,指向语言内部使用的方法
Symbol.iterator
- 对象的Symbol.iterator 属性,指向该对象的默认遍历器方法
iterator接口机制
- 概念:iterator 是一种接口机制,为各种不同的数据结构提供统一的访问机制
- 作用:
1.为各种数据结构,提供一个统一的,简便的访问机制
2.使得数据结构的成员能够按某种次序排列
3.ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费 - 工作原理:
- 创建一个指针对象(遍历器对象),指向数据结构的起始位置
- 第一次调用next方法,指针自动指向数据结构的第一个成员
- 接下来调用next方法,指针会一直往后移动,直到指向最后一个成员
- 每调用next方法返回的是一个包含value的done的对象,
{value: 当前成员的值, done: 布尔值}
- value表示当前成员的值,done对应的布尔值表示当前的数据是否遍历结束。
- 当遍历结束的时候返回的value值是underfinded,done值为false
原生具备iterator接口的数据(可用for of遍历)
扩展理解:
- 当数据结构上部署了Symbol.iterator接口,该数据就是可以用 for of遍历
- 当使用for of去遍历目标数据的时候,该数据会自动去找Symbol.iterator 属性
1.Array
2.arguments
3.set容器
4.map容器
5.String
…
//将iterator接口部署到指定的数据类型上,可以使用 for of 去循环遍历
//数组,字符串,arguments,set容器,map容器
let str = 'abcdegf'
for(let i of str){
console.log(i)
}
// 对象的Symbol.iterator属性;
let myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 4;
};
for(let i of myIterable){
console.log(i);
}
let obj = [...myIterable];
console.log(obj);
- 当使用for of 去遍历某一个数据结构的时候,首先去找Symbol.iterator,找到了就去遍历,没有找到的话不能遍历 xxx is not iterable
- 使用三点运算符,解构赋值,默认去调用iterator接口
Generator函数简介
- 概念:
- ES6提供的解决异步编程的方案之一
- Generator函数是一个状态机,内部封装了不同状态的数据
- 用来是生成遍历器对象
- 可暂停函数(惰性求值),yield 可暂停,next 方法可启动。每次返回的是 yield 后的表达式结果
- 特点
- function 与函数名之间有一个星号
- 内部用 yield 表达式来定义不同的状态
- generator函数返回的是指针对象(iterator),而不会执行函数内部逻辑
- 调用 next 方法函数内部逻辑开始执行,遇到yield 表达式停止,返回{value: yield后的表达式结果/undefined, done
- 再次调用next方法会从上一次停止时的 yield 处开始,直到最后
- yield 语句返回结果通常为 undefined,当调用 next 方法时传参内容会作为启动时 yield 语句的返回值
function* generatorExample(){
let result = yield 'hello'; // 状态值为 hello,result 为 undefined,除非启动时 next() 有传参进来
yield 'generator'; //状态值为generator
}
- 应用
function getNews(url) {
$.get(url, function (data) {
console.log(data)
let url = 'http://localhost:3000' + data.commentsUrl;
SX.next(url)
})
}
function* sendXml() {
let url = yield getNews('http://localhost:3000/news?id=3')
yield getNews(url)
}
let SX = sendXml()
SX.next()
async 函数(源自与ES2017)
- 概念:真正意义上去解决异步回调的问题,同步流程表达异步操作
- 本质:Generator的语法器
- 语法:
async function foo(){
await 异步操作;
await 异步操作;
}
- 特点:
- 不需要像 Generator 去调用 next 方法,遇到await 等待,当前的异步操作完成就往下执行
- 返回的总是 Promise 对象,可以用 then 方法进行下一步操作
- async 取代 Generator 函数的星号*, await 取代 Generator 的 yield
- 语意上更为明确,使用简单,经临床验证,暂时没有任何副作用以及不良反应
// 案例演示
async function sendXml(url) {
return new Promise((resolve, reject) => {
$.ajax({
url,
type: 'GET',
success: data => resolve(data),
error: error => reject(error)
})
})
}
async function getNews(url) {
let result = await sendXml(url);
let result2 = await sendXml(url);
console.log(result, result2);
}
getNews('http://localhost:3000/news?id=2')
应用技巧
async function sendXml() {
let result = await getNews('http://localhost:3000/news?id=7')
if(!result) {
alert('暂时没有新的新闻')
return
}
result = await getNews('http://localhost"3000' + result/commentsUrl);
}
sendXml();
class
- 通过class 定义类/实现类的继承
- 在类中通过 constructor 定义构造方法
- 通过 new 来创建类的实例
- 通过 extends 来实现类的继承
- 通过 super 调用父类的构造方法
- 重写从父类中继承的一般方法
- 在类里面定义的所有方法都会放在原型上
class Person {
//类的构造方法
constructor(name, age) {
this.name = name
this,age = age
}
//类的一般方法
//必须用简写方式
showName() {
console.log(this.name)
}
}
let person = new Person('kobe', 39)
person.showName() //kobe
class StarPerson extends Person {
constructor(name, age, salary){
super(name, age) //调用父类的构造方法
this.salary = salary
}
}
let p1 = new StarPerson('wade', 36, 10000000000000)
字符串的扩展
includes(str)
: 判断是否包含指定的字符串starsWith(str)
: 判断是否以指定的字符串开头endWith(str)
: 判断是否以指定的字符串结尾repeat(count)
: 重复指定次数
let str = 'ab'
console.log(str.includes('t'))//false
数值的扩展
- 二进制与八进制数值表示法:二进制用
0b
,八进制用0o
Number.isFinite(i)
:判断是否是有限大的数Number.isNan(i)
:判断是否为 NaNNumber.isInterger(i)
:判断是否是整数Number.parseInt(str)
:将字符串转换为对应的数值Math.trunc(i)
:直接去除小数部分
console.log(0b1010) //10
console.log(o056) //46
数组的扩展
Array.from(v)
:将伪数组对象阔可遍历对象转换为真数组Array.of(v1, v2, v3)
:将一系列的值转换为数组find(function(value, index, arr){return true})
:找出第一个满足条件返回 true 的元素findIndex(function(value, index, arr){return true})
:找出第一个满足条件返回 true 的元素的下标
let btns = documents.getElementsByTagName('button')
Array.from(btns).forEach....
let arr2 = [2, 3, 4, 2, 5, 7, 3, 6, 5]
let result = arr2.find(function (item, index) {
return item > 4
})
console.log(result)
对象方法的扩展
Object.is(v1, v2)
- 判断两个数据是否完全相等
- 底层是用字符串来判断
Object.assign(target, source1, source2..)
- 将原对象的属性复制到目标对象上
- 直接操作
__proto__
属性- 以前不能(以前只能操作 prototype 属性)
let obj2 = {};
obj2.__proto__ = obj1
console.log(0 == -0) //true
console.log(NaN == NaN) //false
console.log(Object.is(0, -0)) //false
console.log(Object.is(NaN, NaN))//true
深度克隆
在堆中,对基本数据类型的复制,是生成一段新的内存
对对象的复制操作,是指向原来的对象(复制了一份引用)
拷贝数组/对象,没有生成新的数据而是复制了一份引用
-
拷贝数据:
- 基本数据类型:
拷贝后会生成一份新的数据,修改拷贝以后的数据不会影响元数据 - 对象/数组:
拷贝后不会生成新的数据,而是拷贝引用,修改拷贝以后的数据会影响原来的数据
- 基本数据类型:
-
拷贝数据的方法:
- 直接赋值给一个变量 (浅拷贝)
Object.assign()
(浅拷贝)Array.prototype.concat()
(浅拷贝)Array.prototype.slice()
(浅拷贝)JSON.parse(JSON.stringify())
(深拷贝),拷贝的数据里不能有函数
要求放入的原生的js对象(obj/arr)
-
浅拷贝(对象/数组):
- 特点:拷贝的引用,修改拷贝以后的数据会影响原数据
-
深拷贝(深度克隆)
- 特点:拷贝的时候会生成新数据,修改拷贝以后的数据不会影响原数据
-
思考:
- 如何实现深度拷贝(克隆)
- 拷贝的数据里有对象/数组
- 拷贝的数据里不能有对象/数组,几时有对象/数组可以继续遍历对象,数组拿到里边每一项值,一直到拿到的是借本数据类型,然后再去复制,这就是深度拷贝。
-
知识点储备
- 如何判断数据类型,arr—>Array null —> Null
- typeof 返回的数据类型:String,Number,Boolean,Undefined,Object,Function
Object.prototype.toString.call(obj)
let result = 'abcd'
result = [1, 3]
console.log(Object.prototype.toString.call(result).slice(8, -1))
- for in 循环
- 循环对象时拿到属性名
- 循环数组时拿到下标
function checkeType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
//实现深度克隆 ---> 对象/数组
function clone(target) {
//判断拷贝的数据类型
let result, targetType = checkType(target)
if(targetType === 'Object'){
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target;
}
for(let i in target) {
let value = target[i]
if(checkType(value) === 'Object' || checkType(value) === 'Array'){
result[i] = clone(value)
} else {
result[i] = value
}
}
return result
}
Set 和 Map
- Set 容器,无序不可重复的多个 value 的集合体
- Set()
- Set(array)
- add(value)
- delete(value)
- has(value)
- clear()
- size
- Map 容器:无序的 key 不重复的多个 key-value 的集合体
- Map()
- Map(array)
- set(key, value) //添加
- get(key)
- delete(key)
- has(key)
- clear()
- size
let map = new Map([['aaa', 'username', 25], [36, 'age' ]])
console.log(map) //{"aaa" => "username", 36 => "age"}
for of 详解
- 遍历数组
- 遍历 Set
- 遍历 Map
- 遍历字符串
- 遍历伪数组
- 去重
let arr = [1, 2, 4, 5, 5, 6, 3]
let arr1 = arr
arr = []
let set = new Set(arr1)
for(let i of set){
arr.push(i)
}
console.log(arr)
ES7
- 指数运算符(幂):**
- Array.prototype.includes(value):判断数组中书否包含指定的value
console.log(3 ** 3);