ECMAscript 567

严格模式

如何开启严格模式?

function strictMode(){
'use strict'
//something
}

开启严格模式的特性:

  1. 必须用var关键字声明变量
    'use strict'
    name = 'Fitz'
    console.log(name) //报错 nams is not defined
  2. 自定义函数中的this不能指向window
    'use strict'
    function Test(){
    this.name = 'Fitz'
    } Test(); //此时直接执行函数相当于 window.name = 'Fitz'
    // 但是在严格模式下自定义函数this不能指向window 所以 报错
  3. eval()中的代码有独立作用域
    'use strict'
    var i=666
    eval('var i=3; console.log(i)') //i=3
    console.log(i) //i=666
  4. 对象中的属性名不能出现相同
    'use strict'
    obj = {
    name: 'dd',
    name: 'cc'
    } //报错
  5. 全局对象是undefined
    非严格模式中 ==>  window
    严格模式 ==> undefined

字符串扩展

  1. str.includes(str): 判断是否包含指定的字符串

    let str = 'this is a string'
    console.log(str.includes('is')) //true
    console.log(str.includes(' ')) //true
    console.log(str.includes('das')) //false
    console.log(str.includes('a s')) //true
  2. str.startsWith(str): 判断是否以指定字符串开头

    let str = 'this is a string'
    console.log(str.startsWith('t')) //true
    console.log(str.startsWith('a')) //false
  3. str.endsWith(str): 判断是否以指定字符串结尾

    let str = 'this is a string'
    console.log(str.endsWith('g')) //true
    console.log(str.endsWith('h')) //false
  4. str.repeat(count): 重复指定次数

    let str = 'this is a string'
    console.log(str.repeat(2)) //this is a stringthis is a string

数值的扩展

  1. Number.isFinite(i): 判断是否是有限大的数

    let num = 666
    let num2 = 666.0
    let num3 = 3.1415926535 console.log(Number.isFinite(num)) //true
    console.log(Number.isFinite(Infinity))//false
  2. Number.isNaN(i): 判断是否是判断是否是NaN

    let num = 666
    let num2 = 666.0
    let num3 = 3.1415926535 console.log(Number.isNaN(num)) //false
    console.log(Number.isNaN(NaN)) //true
  3. Number.isInteger(i): 判断是否是整数

    let num = 666
    let num2 = 666.0
    let num3 = 3.1415926535 console.log(Number.isInteger(num)) //true
    console.log(Number.isInteger(num2)) //true
  4. Number.parseInt(i): 将字符串转换为对应数值

    let num = 666
    let num2 = 666.0
    let num3 = 3.1415926535
    console.log(Number.parseInt(num2)) //666
    console.log(Number.parseInt(num3)) //3
  5. Number.trunc(i): 直接去除小数部分

    let num = 666
    let num2 = 666.0
    let num3 = 3.1415926535
    console.log(Math.trunc(num2)) //666
    console.log(Math.trunc(num3)) //3

Object对象方法扩展

  1. Object.create(prototype,[descriptors])

    1. 作用:

      1. 以指定对象为原型创建新的对象

      2. 为新对象指定新属性,并对属性执行描述

    2. 常用的属性

      1. value: 自定义属性值
      2. writable:标识描述属性是否能修改,默认为false
      3. configurable: 标识当前属性是否可以被删除,默认为false
      4. enumerable: 标识当前属性能够使用for in 枚举, 默认为false
    var obj = {
    username: 'dd',
    age: 30
    } var obj1 = Object.create(obj,{
    att1: {
    value: '我是att1的属性值',
    writable: true,
    enumerable: true,
    configurable: true
    },
    password: {
    value: '666',
    writable: true,
    enumerable: true,
    configurable: true
    }
    })
  2. Object.defineProperties(object,[descriptors])

    //扩展原型属性
    var obj3 = {
    name: 'Lx',
    age: 20
    }
    Object.defineProperties(obj3,{
    //info属于扩展属性
    //this ---> obj3
    info: {
    //当扩展属性改变时,自动调用该方法(obj.info = xx)
    set: function(data){
    console.log('data -->' + data)
    var splitData = data.split(' ')
    this.name = splitData[0]
    this.age = splitData[1]
    }, //获取扩展属性的值,自动调用该方法 (obj.info)
    get: function(){
    return this.name + '->' + this.age
    }
    }
    //扩展属性的set与get本质上调用的是
    //set propertyName()
    //get propertyName()
    }) console.log(obj3.info); //Lx->20
    obj3.info = 'ddd 99' //data -->ddd 99
    console.log('change success --> ' + obj3.info) //change success -->ddd->99
    var obj4 = {
    name: 'sun',
    age: 999,
    get personInfo(){
    console.log('get()')
    return 'name is -> ' + this.name + 'age is -> ' + this.age
    },
    set personInfo(info){
    console.log('set()')
    var spliter = info.split(' ')
    this.name = spliter[0]
    this.age = spliter[1]
    }
    } console.log(obj4.personInfo); //get() name is -> sunage is -> 999
    obj4.personInfo = 'Liu 13' //set()
    console.log(obj4.personInfo); //get() name is -> Liu age is -> 13
  3. Object.is(v1,v2) 判断两个数据是否完全相等

    1. 原理是先转换成字符串再判断两者是否相等
    console.log(0 === -0)           //true
    console.log(NaN === NaN) //false
    console.log(Object.is(0,-0)) //false
    console.log(Object.is(NaN,NaN)) //true
  4. Object.assign(target,source1,source2..) 将原对象的属性复制到目标对象上

    let myObj = {}
    let myObj2 = {name: '我会被复制到另一个对象中'}
    let myObj3 = {age: 999}
    let myObj4 = {gender: 'male'}
    Object.assign(myObj,myObj2,myObj3,myObj4)
    console.log(myObj) //{name: "我会被复制到另一个对象中", age: 999,gender: "male"}
  5. 直接操作__proto__属性

    //直接操作 __proto__
    let myObj5 = {}
    let myObj6 = {dream: 'rich'}
    myObj5.__proto__ = myObj6
    console.log(myObj5)
    console.log(myObj5.dream) //rich

数组的扩展

  1. map(function(item,index)}{})

    遍历数组返回一个新数组,数组中的值是在加工后的

    var arr = [1,3,4,5,67,12,4]
    var newArr = arr.map(function(item,index){
    return item ** 2
    })
    console.log(newArr) //[1, 9, 16, 25, 4489, 144, 16]
    console.log(arr) //不会改变元素组
  2. filter(function(item,index)}{})

    遍历数组返回一个新数组,数组中的值是在条件为true的

    var arr = [1,3,4,5,67,12,4]
    var newArr2 = arr.filter(function(item,index){
    return index > 2 //过滤条件
    })
    console.log(newArr2) //[5,67,12,4] 值为: 过滤条件 === true
    console.log(arr) //不会改变元素组

数组方法的扩展

  1. Array.from(v) 将伪数组对象或可遍历对象转换为真数组

    //定义一个伪数组
    let fakeArr = {
    0: 'first!',
    1: 'hello',
    2: '3',
    length: 3
    } Array.from(fakeArr).forEach((item,index) => {
    console.log(`item ==> ${item} index ==> ${index}`);
    }) //伪数组不能直接调用真数组的方法
    /* Array.forEach((item,index) => {
    console.log(`item ==> ${item} index ==> ${index}`);
    }) */
  2. Array.of(v1,v2,v3) 将一系列值转换为数组

    let result = Array.of(1,false,'da')
    console.log(result) //[1, false, "da"]
  3. find(function(value,index,arr){return true}) 找出第一个且只有一个满足条件返回true的元素

    let arr = [1,3,5,6,7,19]
    let result = arr.find(function(item,index){
    //只会返回第一个且只有一个满足条件的元素
    return item > 4
    })
    console.log(result) //5
  4. findeIndex(function(value,index,arr){return true}) 找出第一个且只有一个满足条件返回true的元素下标

    let arr = [1,3,5,6,7,19]
    let result = arr.findIndex(function(item,index){
    //只会返回第一个且只有一个满足条件的元素的下标
    return item > 4
    })
    console.log(result) //2

bind、call、apply用法详解

bind()、call()、apply()

三者区别:

  1. 三者都能指定this
  2. bind()是将函数返回而不是立即调用,通常用在为回调函数指定this
  3. call()与apply()是立即调用函数
  4. call()传参方式是传入多个参数
  5. apply()传参方式是将多个参数放到数组中传入

call()与apply()

var obj = {
name: 'fitz'
}
function foo(name){
console.log(this)
console.log('my name is -->' + name);
} foo('alpha') //window alpha
foo.call(obj,'logo') //obj logo

bind()

var obj = {
name: 'fitz'
}
function foo(name){
console.log(this)
console.log('my name is -->' + name);
} foo('alpha') //window alpha //bind()
var bar = foo.bind(obj,'success')
bar() //obj my name is --> success //bind()
foo.bind(obj,'success')() //obj my name is --> success //bind()主要用于为回调函数指定this
setTimeOut(function(){
console.log(this)
}.bind(obj),1000)

let const

let的作用类似于var,用于声明变量

let声明变量的特点:

  1. let有块级作用域

    var name = 'test var'
    {
    var name = 'dd'
    }
    console.log(name); //dd var没有块级作用域 let name = 'test var'
    {
    let name = 'dd'
    }
    console.log(name); //test var let有块级作用域
  2. let 不能再同一作用域内重复声明变量

    let name = 'dd'
    let name = 'cc' //报错Uncaught SyntaxError: Identifier 'name' has already been declared
  3. let不会变量提升

    //var声明变量会有变量提升的特点
    console.log(name) //undefined 此时name已经被声明但是没有复制
    var name = 'test' //上面的代码等同于
    var name
    console.log(name)
    name = 'test' //let没有变量提升
    console.log(name) //报错Cannot access 'name' before initialization
    let name = 'let is good'
    //let的优势在 循环遍历监听 中的体现
    
    //使用var
    //1s过后打印10个10
    for (var i=0; i<10; i++){
    setTimeout(function(){
    console.log(i) // 10 10 10 ... 10
    },1000)
    } //使用let
    //1s过后打印 1-9
    for (let i=0; i<10; i++){
    setTimeout(function(){
    console.log(i) // 1 2 3 4 5 6 7 8 9
    },1000)
    }
  4. 形成一个暂时性死区(TDZ)

    //暂时性死区表现在,在声明变量前无法打印变量值,而是会引发ReferenceError错误
    console.log(name)
    let name = 'Error will be happen'
    //ReferenceError: Cannot access 'name' before initialization

const作用是定义一个常量

const声明变量的特点:

  1. 定义赋值后,值不能再被修改
    const name = 'can not change'
    name = 'test to change' //报错Uncaught TypeError: Assignment to constant variable.
  2. 其他与let特性相同

let与const声明的变量在全局对象window中访问不到

let a = 'A'
const b = 'B' //var声明的变量会被挂载到window上,但是let与const声明的变量不会,直接访问便可
console.log(window.a) //undefined
console.log(a)
console.log(window.b) //undefined
console.log(b)

变量的解构赋值

从对象或者数组中提取数据,并赋值给多个变量

let myObj = {
name: 'Fitz',
age: 20
} let myArray = [1,3,5,7,9] //变量的结构赋值 ===> 对象
let {name, age} = myObj
console.log(name)
console.log(age) //变量的结构赋值 ===> 数组
let [a,b] = myArray
console.log(a)
console.log(b) //取特定位置的值
let [,,,four,five] = myArray
console.log(four)
console.log(five)

用途介绍: 给函数的形参赋值

//用途
//这是一种需要被改善的用法
function foo(obj){
console.log(obj.name)
console.log(obj.age)
}
foo(myObj) //这是改善后使用变量结构赋值的用法
function bar({name,age}){
console.log(name)
console.log(age)
}
bar(myObj)

模板字符串

作用: 简化字符串的拼接

var obj = {
name: 'Fitz'
} //这是需要改进的方法(拼接字符串)
console.log('my ' + obj.name + 'is cool')
//这是改进的方法(模板字符串)
console.log(`my ${obj.name} is cool`)

对象的简写方式

对象属性名与变量名相同时,可以省略不写

//引子
let name = 'Fitz'
let age = 20
let obj = {
name: name,
age: age,
}
console.log(obj) //简写属性
let obj2 ={
name,
age,
}
console.log(obj2)

对象内的方法也能简写

//引子
let name = 'Fitz'
let obj = {
name: name,
sayHello: function(){
return `${this} and hello!`
}
}
console.log(obj)
console.log(obj.sayHello()) //简写属性
let obj2 ={
name,
sayHello(){ //方法简写
return `${this} and hello!`
}
}
console.log(obj2)
console.log(obj2.sayHello())

箭头函数(arrow)

作用: 定义匿名函数

//使用箭头函数方式一
var func = () => console.log('i am a arrow func')
func() //使用箭头函数方式二
(() => console.log('i am a arrow func too'))()

形参个数与语法

//没有形参时候,()  不能省略
() => console.log('dd') //一个形参时候,() 可以省略
a => console.log(a) //多个形参时候,() 不能省略
(x,y) => console.log(x,y)

函数体与语法

//函数体内只有一个语句或表达式
(x,y) => x+y //此时函数会自动 return 结果, {}省略 //如果{}不省略则需要手动 return 返回结果 //函数体内有多个语句或表达式
var func = (x,y) => {
let result = x**y
return result + 1
} console.log(func(2,3)) //9

箭头函数的特点

  1. 箭头函数没有自己的this
  2. 箭头函数不是在调用的时候决定的,而是在定义的时候箭头函数所处在的对象(包裹住箭头函数的对象)就是它的this

    ===> 透彻理解

    1. 箭头函数的this取决于箭头函数是否被函数包裹着(外层是否有函数)
    2. 如果箭头函数被外层函数包裹,箭头函数的this就是包裹住箭头函数的那个函数的this(箭头函数的this === 外层函数的this)
    3. 没有被函数包裹的话就是this就是window
//测试箭头函数的this
(() => console.log(this))() //window
let outerFunc = {
flag: 'i am outerFunc',
testArrow: function(){
let innerArrowFunc = () => console.log(this)//outerFunc
innerArrowFunc()//箭头函数被testArrow包裹这
//所以this就是testArrow这个函数的this
}
}
outerFunc.testArrow() //此时testArrow的this ==> outerFunc

三点运算符

用于替代arguments但是比arguments更加灵活

...args 比 arguments 优点在于:...args收集后是一个真数组可以进行遍历,而arguments是一个伪数组不能直接遍历

function foo(...args){
console.log(args)
args.forEach(function(item,index){
console.log(item, index);
})
} foo(1,3,5)

三点运算符必须放在最后

function bar(a,b,...inLastest){
console.log(a)
console.log(b)
console.log(inLastest)
}

...args 与 args

  1. ...args是遍历数组中的每一个元素
  2. args是一整个数组
let arr = [1,2,3,4,5]
function test(x,y,...args){
console.log(...args) //3,4,5
console.log(args) //[3,4,5]
}

使用三点运算符进行扩展运算

let arr = [2,3,4,5]
let arr2 = [1, ...arr , 6]
console.log(arr2) //[1,2,3,4,5,6]
console.log(...arr2)//1,2,3,4,5,6

形参默认值

function foo(x=3,y=6){
return x * y
} console.log(foo()); //9

promise对象

promise的三种状态

  1. pending 初始化状态
  2. fullfilled 成功状态
  3. rejected 失败状态
let promise = new Promise( (resolve,reject) => {
//此时状态为pending
console.log('第一')
//执行异步操作
setTimeout(()=>{
console.log('我是定时器') //修改状态为 fullfilled,调用成功回调
resolve('resolve() ==>') //修改状态为rejected,调用失败回调
//reject('reject() ==>')
},2000) console.log('我是第二')
}) promise.then(
//成功的回调函数
(data)=>{
console.log(data + ' success');
}, //失败的回调函数
(error)=>{
console.log(error + ' fail');
}
)

promise封装ajax

function getNews(url){
//使用promise
let promise = new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest()
//xhr.open('GET','http://localhost:1080/promise-ajax.js')
xhr.open('GET',url)
xhr.send()
xhr.onreadystatechange = function(){
if (xhr.readyState === 4){
if (xhr.status >= 200 && xhr.status < 300){
//成功收到ajax请求结果,更改为成功状态
resolve('Success' + xhr.responseText)
}else{
reject('Error 没有新闻内容')
}
})
}
})
return promise
} getNews('http://localhost:1080/promise-ajax.js')
.then(
(responseText)=>{
console.log(responseText)
//成功后,向另一个路由发送评论ajax请求
//这里return的也是promise对象
return getNews('http://localhost:1080/comment.js')
},
(error)=>{
console.log(error)
}
)
//这个then用于处理评论的ajax请求
.then(
(comment)=>{
console.log(comment)
},
(error)=>{
console.log(error)
}
)

Symbol数据类型

引子

JavaScript中ES6以前总共有6种数据类型,其中5种(String,Boolean,Number,Null,Undefined)是基本数据类型,1种(Object)是引用数据类型

Symbol的作用

  1. 用于解决ES5中由于属性名都是字符串,导致的重名、污染环境的问题

symbol的使用

let obj = {
username: 'Fitz',
age: 20
} //symbol可以作为对象的一个属性
//但是不能通过obj.symbol这种方式使用
//只能通过obj[symbol]的方式使用
obj[symbol] = 'i am symbol'
console.log(obj); //{username: "Fitz", age: 20, Symbol(): "i am symbol"}

Symbol的特点

  1. Symbol属性对应的值是唯一的,解决命名冲突的问题
  2. Symbol的值不能与其他数据进行计算,也不能与字符串进行拼串操作
    console.log(`${symbol1} compare of ${symbol2}`) //报错Uncaught TypeError: Cannot convert a Symbol value to a string
  3. for...in 与 for...of遍历时不会遍历出symbol属性
    let obj = {
    username: 'Fitz',
    age: 20
    }
    obj[symbol] = 'i am symbol' //使用for in或者 for of进行遍历无法获取到symbol
    for (let item in obj){
    console.log(item); //username age
    }

Iterator迭代器

概念:iterator是一种接口机制,为不同的数据结构提供统一的访问机制

作用:

  1. 为各种数据结构提供一个统一、简便的访问接口
  2. 是数据结构中的城院按某种次序排列
  3. 主要为for...of循环使用

工作原理:

  1. 创建一个迭代器对象(指针对象),指向数据结构中的起始位置
  2. 当第一次调用next方法时,指针会往后移动,一直到数据结构中的最后一个成员
  3. 每次调用next方法返回的是一个包含value与done的对象 ==> {value: 当前成员的值,done: 布尔值(遍历是否结束)}
    1. 遍历结束后{value: undefined, done: true}

简单模拟实现iterator

let arr = [1,3,5,'abc']

function myIterator(obj){
let i = 0
let isDone = false;
return {
//返回一个next方法
next(){
if(arr[i] === undefined){
isDone = true
}
return {
value: arr[i++],
done: isDone
}
}
}
} var iter = myIterator(arr)
console.log(iter.next()); //{value: 1, done: false}
console.log(iter.next()); //{value: 3, done: false}
console.log(iter.next()); //{value: 5, done: false}
console.log(iter.next()); //{value: 'abc', done: false}
console.log(iter.next()); //{value: undefined, done: true}

将iterator接口部署到指定的数据类型后可以使用for...of去循环遍历

  1. 已经默认部署了iterator的对象:数组,字符串,arguments,set容器, map容器
    let arr2 = [1,2,3,4,5,6]
    let str = 'iterator'
    function testIterator(){
    for (i of arguments){
    console.log(`${i} <== arguments`);
    }
    } for (i of arr2){
    console.log(`${i} <== arr2`);
    }
    for (i of str){
    console.log(`${i} <== str`);
    }
    testIterator('arg1','arg2','arg3','arg4','arg5')

iterator与symbol.iterator的关系

在指定的数据结构中添加Symbol.iterator的作用是部署iterator接口,当使用for...of去遍历某一个数据结构的时候,会首先去找Symbol.iterator

let target = {
[Symbol.iterator]: function(){
let i = 0
let isDone = false;
let that = this
return {
//返回一个next方法
next(){
if(that[i] === undefined){
isDone = true
}
return {
value: that[i++],
done: isDone
}
}
}
}
}

三点运算符与对象解构赋值都运用了iterator

let arr2 = [2,3,4,5]
let arr = [1,...arr2,6]
console.log(arr)
let [item1,item2] = arr
console.log(item1,item2)

Generator生成器

概念

  1. ES6提供的解决异步编程的方案之一
  2. Generator是一个状态机,内部封装了不同状态的数据
  3. 是一个用来生成Iterator的对象
    1. Generator包含Iterator
  4. 可以惰性求值,yield可暂停,next()可以启动,每次返回的都是yield后表达式的结果

特点:

  1. 语法:function与函数名之间有一个*号
  2. 内部用yield表达式定义不同的状态
    function* aGenerator(){
    //我是一个Generator
    yield something
    }

向next()方法传入实参可以在启动Generator时,作为yield的返回值

next()方法时从上一次yield的地方开始运行

执行流程分析

//创建一个Generator
//Generator需要next()启动,遇到yield就停止
function* aGenerator(){
console.log('开始遍历')
yield 'create by Fitz'
let value = yield '返回值是next()方法的实参'
console.log(value)
console.log('遍历完成')
} let gen = aGenerator()
console.log(gen.next()) //遇到yield停止
/*
开始遍历
{value: "create by Fitz", done: false}
*/
console.log(gen.next())
/*
{value: "返回值是next()方法的实参", done: false}
*/
//此时停止在let value = yield '返回值是next()方法的实参'
console.log(gen.next('我是返回值'))
/*
调用next('我是返回值')方法
此时在let value = yield '返回值是next()方法的实参'这一句开始运行
所以返回值value就是next()方法传入的实参 ==> '我是返回值'
*/ /* 结果:
我是返回值
遍历完成
{value: undefined, done: true}
*/

async异步函数

概念: 真正意义上去解决异步回调的问题,以同步的流程表达异步操作

本质: 就只是Generator的语法糖

语法:

async function foo(){
await 异步操作 //遇到await就暂停等待异步操作完成后,再往下执行
await 异步操作
}

特点:

  1. 不需要像Generator那样需要调用next(),而是在完成await后面定义的异步操作后,自动往下运行
  2. 返回的总是 promise对象 这意味着可以使用.then(()=>{},()=>{})进行操作
    async foo(){
    return 'Fitz'
    }
    console.log(foo()) //promise{fullfill: 'Fitz'} foo().then(
    data => console.log(data),
    error => console.log(error)
    )

class类

class类的例子

class Person{
//类的构造方法
constructor(name,age){
this.name = name
this.age = age
} //类的一般方法
//只能使用对象方法的简写方式
sayName(){
console.log(this.name);
}
} let person = new Person('Fitz',20)
console.log(person)
person.sayName()

通过constructor定义类的构造方法

class useConstructor{
constructor (name,age){
this.name = name
this.age = age
}
}

类的继承

//定义一个 中国明星 类
//因为明星也是人,所以从 人类 中继承
class Person{
constructor (name,age){
this.name = name
this.age = age
} //类的一般方法
//只能使用对象方法的简写方式
sayName(){
console.log(this.name)
}
} //定义一个 外国明星 类
//因为明星也是人,所以从 人类 中继承
class ChineseStar extends Person{ } let chineseStar = new ChineseStar('jack chen',60)
console.log(chineseStar)

通过super来调用父类的构造方法

class Person{
constructor (name,age){
this.name = name
this.age = age
} //类的一般方法
//只能使用对象方法的简写方式
sayName(){
console.log(this.name)
}
} class Student extends Person{
constructor (name,age,grade){
super(name,age)//调用父类的构造方法 //super()的实参是由ForeignStar这个类的constructor提供
//而constructor的实参是在类实例中传入
/*
super()的作用相当于直接将父类的constructor复制过来
//类的构造方法
constructor(name,age){
this.name = name
this.age = age
}
*/ this.grade = grade
}
}
let student = new Student('Fitz',20,'phd')
console.log(student)

重写从父类中继承的一般方法

class Person{
constructor (name,age){
this.name = name
this.age = age
} //类的一般方法
//只能使用对象方法的简写方式
sayName(){
console.log(this.name,this.age)
}
} class Student extends Person{
constructor (name,age,grade){
super(name,age)
this.grade = grade
} /*父类中有一个sayName方法,但是只能打印name与age。此时如果还需要打印grade的话
就需要重写父类的sayName方法
*/
sayName(){
console.log(this.name,this.age,this.grade)
}
}
let student = new Student('Fitz',20,'phd')
console.log(student)
student.sayName() //'Fitz',20,'phd'
//遵循的是就近原则,所以调用的是子类中的sayName方法

克隆/拷贝

克隆数据有两种方式:

  1. 深克隆: 克隆生成新的数据,修改这个数据不会影响到原数据
    let str = 'abc'
    let str2 = str //深克隆
    str2 = 'bcd'
    console.log(str) //'abc'
  2. 浅克隆:克隆后不会产生新的数据,而是克隆、引用内存的地址值,修改数据会影响到原来的数据
    let obj = {name: 'Fitz'}
    let obj2 = obj //浅克隆
    obj2.name = 'Lx'
    console.log(obj.name) //'Lx'

克隆数据的几种方法 (深浅拷贝针对的是数组、对象):

  1. 直接复制给一个变量 浅拷贝

    let obj = {name: 'Fitz'}
    let obj2 = obj //浅克隆
    obj2.name = 'Lx'
    console.log(obj.name) //'Lx'
  2. Object.assign() 浅拷贝

    let obj = {name: 'Fitz'}
    let obj2 = Object.assign(obj) //浅克隆
    console.log('obj ==>',obj)
    console.log('obj2 ==>',obj2) console.log(obj.name) //'Fitz'
    obj2.name = 'Lx'
    console.log(obj.name) //'Lx'
    console.log(obj2.name) //'Lx'
  3. Array.prototype.concat() 浅拷贝

    let arr = [1,2,{name: 'Fitz'}]
    arr2 = arr.concat()
    arr2[0] = 666 //深克隆
    arr2[2].name = 'LX' //浅克隆
    console.log(arr) //[1, 2, {…}]
    console.log(arr2) //[666, 2, {…}]
  4. Array.prototype.slice() 浅拷贝

    let myArr = [1,2,3,{name: 'Fitz'}]
    let myArr2 = myArr.slice()
    myArr2[0] = 666
    myArr2[3].name = 'Change'
    console.log(myArr)
    console.log(myArr2)
  5. JSON.parse(JSON.stringify()) 深拷贝

    let toJsonStr = {name: 'Fitz'}
    let result = JSON.stringify(toJsonStr)
    console.log(result) //{"name":"Fitz"}
    let clone = JSON.parse(JSON.stringify(toJsonStr)) //深克隆
    console.log(clone) //{name: "Fitz"}
    clone.name = 'LX'
    console.log(clone) //{name: "LX"}
    console.log(toJsonStr) //{name: "Fitz"}

实现深度克隆

深克隆主要的目标是对象、数组,因为普通数据类型都是深克隆

现深度克隆方法的主要思路:

  1. 找到数据结构中的所有对象与数组
  2. 将其中的值全部遍历出来(遍历出的必须是基本数据类型)
  3. 然后进行复制,这个复制一定是深克隆

需要知道的知识:

  1. 检测数据的2种方法

  2. typeof

    返回值只有:Symbol,String,Number,Boolean,Function,Object,Undefined

    NaN ==> Number

    null,array ==> Object

  3. Object.prototype.toString()

    //该函数可以检测数据结构的类型
    function checkType(target){
    return Object.prototype.toString.call(target).slice(8,-1)
    }
  4. for...in枚举 对数组、对象的作用

    let obj = {name: 'Fitz',age: 20}
    let arr = [1,3,5,7,9] for (let i in obj){
    console.log(i) //name age
    } for (let i in arr){
    console.log(i) //0,1,2,3,4
    }
    /*
    结论:
    对象枚举出的是属性值
    数组枚举出的是下标值
    */

实现深度克隆

//该函数可以检测数据结构的类型
function checkType(target){
return Object.prototype.toString.call(target).slice(8,-1)
} //实现深度克隆
function deepClone(target){
let type = checkType(target) //得到数据类型
let result //初始化 //处理最终的包装容器
if(type === 'Object'){
result = {}
}else if(type === 'Array'){
result = []
}else{
//当数据类型是基本数据类型时
return target //递归的基线条件
} //处理目标数据
//同时使用Object与Array
for (let i in target){
//当是Object时,返回属性值
//当是Array时,返回下标
let value = target[i] //都能拿到obj与arr中所有的元素 //当是多维的Object与Array
if(checkType(value) === 'Object' || checkType(value) === 'Array'){
//例如: [1,[2],{a: 1}] {a: [1,[2],{b: 2}]}
//使用递归
result[i] = deepClone(value)
}else{ //当Object与Array是一维的
result[i] = value
}
} return result
} //测试
let arrForDeepClone = [1,[2],{a: 1}]
let objForDeepClone = {a: [1,[2],{b: 2}]}
let arrForDeepClone2 = deepClone(arrForDeepClone)
let objForDeepClone2 = deepClone(objForDeepClone)
arrForDeepClone2[1][0] = 666
console.log(arrForDeepClone,arrForDeepClone2)
objForDeepClone['a'][2]['b'] = 666
console.log(objForDeepClone,objForDeepClone2)

Set容器

什么是Set容器?

概念: Set容器是有无序、不可重复的多个value的集合体

Set容器的方法

  1. Set()

    //创建一个set容器实例
    let set = new Set()
    console.log(set) //Set(0) {}
  2. Set(Array)

    //创建一个set容器实例
    let set = new Set([1,1,2,3,4,2,3,6,2,54])
    console.log(set) //Set(6) {1, 2, 3, 4, 6, 54}
  3. add(value)

    //创建一个set容器实例
    let set = new Set([1,1,2,3,4,2,3,6,2,54])
    console.log(set) //Set(6) {1, 2, 3, 4, 6, 54} set.add(666)
    console.log(set) //Set(7) {1, 2, 3, 4, 6, 54, 666}
  4. delete(value)

    //创建一个set容器实例
    let set = new Set([1,1,2,3,4,2,3,6,2,54])
    console.log(set) //Set(6) {1, 2, 3, 4, 6, 54} set.delete(4)
    console.log(set) //Set(6) {1, 2, 3, 6, 54, 666}
  5. has(value)

    //创建一个set容器实例
    let set = new Set([1,1,2,3,4,2,3,6,2,54])
    console.log(set) //Set(6) {1, 2, 3, 4, 6, 54} console.log(set.has(3)) //true
  6. clear()

    //创建一个set容器实例
    let set = new Set([1,1,2,3,4,2,3,6,2,54])
    console.log(set) //Set(6) {1, 2, 3, 4, 6, 54} set.clear()
    console.log(set) //Set(0) {}
  7. size

    //创建一个set容器实例
    let set = new Set([1,1,2,3,4,2,3,6,2,54])
    console.log(set) //Set(6) {1, 2, 3, 4, 6, 54} console.log(set.size) //6

Map容器

什么是Map容器?

概念: Map容器是无序的key不重复的 多个key-value集合体

Map容器的方法:

  1. Map()

    let map = new Map()
    console.log(map) //Map(0) {}
  2. Map(Array)

    let map = new Map([
    ['name1','Fitz'],
    ['name2','Da'],
    ])
    console.log(map) //Map(2) {"name1" => "Fitz", "name2" => "Da"}
  3. set(key,value)

    let map = new Map([
    ['name1','Fitz'],
    ['name2','Da'],
    ])
    console.log(map) //Map(2) {"name1" => "Fitz", "name2" => "Da"} map.set('name3','Lx')
    console.log(map) //{"name1" => "Fitz", "name2" => "Da", "name3" => "Lx"}
  4. get(key)

    let map = new Map([
    ['name1','Fitz'],
    ['name2','Da'],
    ])
    console.log(map) //Map(2) {"name1" => "Fitz", "name2" => "Da"} console.log(map.get('name2')) //da
  5. delete(key)

    let map = new Map([
    ['name1','Fitz'],
    ['name2','Da'],
    ]) map.delete('name3')
    console.log(map) //Map(2) {"name1" => "Fitz", "name2" => "Da"}
  6. has(key)

    let map = new Map([
    ['name1','Fitz'],
    ['name2','Da'],
    ]) console.log(map.has('name2')) //true
  7. clear()

    let map = new Map([
    ['name1','Fitz'],
    ['name2','Da'],
    ])
    console.log(map) //Map(2) {"name1" => "Fitz", "name2" => "Da"} map.clear()
    console.log(map) //Map(0) {}
  8. size

    let map = new Map([
    ['name1','Fitz'],
    ['name2','Da'],
    ])
    console.log(map) //Map(2) {"name1" => "Fitz", "name2" => "Da"} console.log(map.size) //2

Array.prototype.includes


看完我的笔记不懂也会懂----ECMAscript 567的更多相关文章

  1. 看完我的笔记不懂也会懂----bootstrap

    目录 Bootstrap笔记 知识点扫盲 容器 栅格系统 源码分析部分 外部容器 栅格系统(盒模型)设计的精妙之处 Bootstrap笔记 写在开始: 由于我对AngulaJS的学习只是一个最浅显的过 ...

  2. 看完我的笔记不懂也会懂----AngulaJS

    目录 Angular.js学习笔记 ng-app(指令) ng-model ng-init angular之表达式 双向数据绑定 数据流向的总结 作用域对象 控制器对象 依赖对象与依赖注入 命令式与声 ...

  3. 看完我的笔记不懂也会懂----git

    Git学习笔记 - 什么是Git - 首次使用Git - DOS常用命令 - Git常用命令 - 关于HEAD - 版本回退 - 工作区.暂存区与版本库 - git追踪的是修改而非文件本身 - 撤销修 ...

  4. 看完我的笔记不懂也会懂----Node.js

    Node.js 学习 - 命令行窗口 - 进程与线程 - ECMAScript的缺点 - Node模块化 - Node中的全局对象 - 包 package - NPM包管理器 (Node Packag ...

  5. 看完我的笔记不懂也会懂----javascript模块化

    JavaScript模块化 模块化引子 模块化的历史进化 模块化规范 CommonJS规范 Node.js(服务器端) 下项目的结构分析 browerify(浏览器端) 下项目的结构分析 AMD规范 ...

  6. 看完我的笔记不懂也会懂----less

    目录 Less学习 语法篇 注释 变量 映射(Maps) @规则嵌套和冒泡 less中的嵌套规则 less中的混合 less的运算 extend延伸/继承 less忽略编译(转义) 导入(Import ...

  7. 看完我的笔记不懂也会懂----MongoDB

    MongoDb数据库学习 - 数据库的分类 - 数据库基本概念 - MongoDB常用指令 - MongoDB的CURD - sort({key:*[1,-1]}).limit(num).skip(n ...

  8. 看完我的笔记不懂也会懂----MarkDown使用指南

    目录 语法 [TOC] 自动生成目录 1. 标题 2. 文本强调 3. 列表 4. 图片 5. 超链接 6. 文本引用 7. 分割线 8. 代码 9. 任务列表 (MPE专属) 10. 表格 11. ...

  9. 看完我的笔记不懂也会懂----Ajax

    Ajax(Asynchronous JavaScript And XML) - 本次学习所用到的插件 - XML - JSON - 关于AJAX - HTTP协议 - AJAX重点之XMLHttpRe ...

随机推荐

  1. 2019牛客多校 Round7

    Solved:5 Rank:296 E Find the median (线段树) 题意:最开始一个空的数组 4e5次操作 每次把Li,Ri中的每个数插入进来 问当前的中位数 题解:把这n个区间离散化 ...

  2. 开源RPA软件试用

      优点 缺点 其它 Robot Framework 可视化界面 运行环境搭建复杂,依赖较多 操作复杂 倾向于自动化测试 TagUI 浏览器支持好 官方文档详细 命令行操作 非浏览器程序支持一般   ...

  3. 【非原创】LightOJ - 1284 Lights inside 3D Grid【概率期望】

    学习博客: 戳这里 戳这里 戳这里 戳这里 题意: 在一个三维的空间,每个点都有一盏灯,开始全是关的, 现在每次随机选两个点,把两个点之间的全部点,开关都按一遍:问k次过后开着的灯的期望数量: 题解: ...

  4. Leetcode(94)-二叉树的中序遍历

    给定一个二叉树,返回它的中序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,3,2] 思路:和上篇的前序遍历一样,同样有递归和非递归的做法 (1)递归 vecto ...

  5. 可重入锁ReentrantLock解析

    说到可重入锁,先从AQS的ConditionObject说起,AQS的内部类ConditionObject是构建显示锁条件队列的基础.之前AQS的解析没有说这个内部类,这里和ReentrantLock ...

  6. Python求二维数组中某列的最大值

    主要运用np.amax() import numpy as np help(np.amax) a = np.arange(9).reshape((3, 3)) max_all = np.amax(a) ...

  7. Stack Overflow Skill IQ Testing All In One

    Stack Overflow Skill IQ Testing All In One Pluralsight IQ | Stack Overflow https://www.pluralsight.c ...

  8. background & background-image & border-image

    background & background-image & border-image https://developer.mozilla.org/en-US/docs/Web/CS ...

  9. Headless Chrome

    Headless Chrome https://developers.google.com/web/updates/2017/04/headless-chrome Puppeteer & SS ...

  10. nasm astricmp函数 x86

    xxx.asm: %define p1 ebp+8 %define p2 ebp+12 %define p3 ebp+16 section .text global dllmain export as ...