ES_5_6_7

一、ECMAScript介绍

1、它是一种由ECMA组织(前身为欧洲计算机制造商协会)制定和发布的脚本语言规范

2、而我们学的 JavaScript 是ECMA 的实现,但术语 ECMAScript 和 JavaScript 平时表达是同一个意思

3、JS包含三个部分

​ 1)、ECMAScript(核心)

​ 2)、扩展 ==> 浏览器端

​ BOM(浏览器对象模型)

​ DOM(文档对象模型)

​ 3)、扩展 ==> 负无穷端

​ Node

4、ES 的几个重要版本

​ ES5:09年发布

​ ES6(ES2015):15年发布,也称为ECMA2015

​ ES7(ES2016):16年发布,也称为ECMA2016(变化不大)

ES5

二、严格模式
1、理解

​ ● 除了正常运行模式(混杂模式),ES5添加了第二种运行模式:“严格模式”(strict mode)

​ ● 顾名思义,这种模式使得 JavaScript 在更严格的语法条件下运行

2、作用/目的

​ ● 消除 JavaScript 语法的一些不合理、不严谨之处,减少一些怪异行为

​ ● 消除代码运行的一些不安全之处,为代码的安全运行保驾护航

​ ● 为未来新版本的 JavaScript 做好铺垫

3、使用

​ ● 在全局或函数的第一条语句定义为:‘use strict’

​ ● 如果浏览器不支持,只解析为一条简单的语句,没有任何副作用

4、语法和行为改变

​ ● 必须用 var 声明变量

    <script type="text/javascript">
        'use strict'	//使用严格模式
		name = 'Tom'	//使用严格模式如果在变量声明之前不加var,则会报错
        var username = 'kobe'
        console.log(username)
    </script>

​ ● 禁止自定义的函数中的this指向window

    <script type="text/javascript">
        'use strict'
        function Person(name, age) {
            this.name = name
            this.age = age
        }
        Person('kobe', 39)  //这样自调用会报错,如果要解决这个问题,可以使用new
        new Person('kobe', 39)
    </script>

​ ● 创建 eval 作用域

    <script type="text/javascript">
        'use strict'
        var str = 'NBA'
        eval('var str = "CBA"; alert(str)')	//打印CBA
        alert(str)	//如果不用严格模式,会污染全局,会打印CBA,但是如果使用了严格模式,会打印NBA
    </script>

​ ● 对象不能有重名属性

    <script type="text/javascript">
        'use strict'
        
        var obj = {
            username: 'kobe',
            username: 'wade'	//如果不使用严格模式,重复定义是没问题的,但是如果使用了严格模式,这里会报错
        }
    </script>
三、JSON对象
1、JSON.stringify(obj/arr)

​ js 对象(数组)转换为json对象(数组)

2、JSON.parse(json)

​ json对象(数组)转换为js对象(数组)

四、Object扩展

ES5给Object扩展了一些静态方法,常用的2个:

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

​ ● 作用:以指定对象为原型创建新的对象

​ ● 为新的对象指定新的属性,并对属性进行描述

​ ○ value:指定值

​ ○ writable:标识当前属性值是否是可修改的,默认为false

​ ○ configurable:标识当前属性是否可以被删除,默认为false

​ ○ enumerable:标识当前属性是否能用 for in 枚举,默认为false

    <script type="text/javascript">
        var obj = {username: 'damu', age: 30}
        var obj1 = {}
        obj1 = Object.create(obj, {
            sex: {
                value: '男',
                writable: true,
                configurable: true
                enumerable: true
            }
        })
        console.log(obj1.sex)   //男
        obj1.sex = '女'  //当writable不设置或者设置为false,sex属性是不能修改的,只有设置为true属性才能修改
        console.log(obj1.sex)
        delete obj1.sex //当configuration为false或在不设置值时,是不能删除属性的,只有设置为true才能将属性删除
        console.log(obj1)
        for(var i in obj1){
            console.log(i)  //for in 能枚举对象的属性,但是如果enumerable未设置或者设置为false,使用for in 是不能枚举出属性的,只有设置为true才能枚举出来
        }
    </script>
2、Object.defineProperties(object, descriptors)

​ ● 作用:为指定对象定义扩展多个属性

​ ○ get:用来获取当前属性值的回调函数,获取扩展属性值的时候get方法自动调用

​ ○ set:修改当前属性值的触发的回调函数,并且实参即为修改后的值

​ 存取器属性:setter,getter一个用来存值,一个用来取值

    <script type="text/javascript">
        var obj2 = {firstName: 'kobe', lastName: 'bryant'}
        Object.defineProperties(obj2, {
            fullName: { //扩展一个为fullName的属性,获取扩展属性值的时候get方法自动调用
                get: function () {  //获取扩展属性的值
                    return this.firstName + " " + this.lastName
                },
                set: function (data) {  //监听扩展属性,当扩展属性发生变化的时候会自动调用,自动调用后会将变化的值作为实参注入到set函数
                    console.log('set()')
                    var names = data.split(" ")
                    this.firstName = names[0]
                    this.lastName = names[1]
                }
            }
        })
        console.log(obj2.fullName)
        obj2.fullName = 'tim duncan'
        console.log(obj2.fullName)
    </script>
3、对象本身的两个方法

​ get propertyName(){} 用来获取当前属性值的回调函数

​ set propertyName(){} 用来监视当前属性值变化的回调函数

	<script>
        var obj3 = {
            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]
            }
        }
        console.log(obj)
        obj.fullName = 'kobe bryant'
        console.log(obj.fullName)
    </script>
五、Array扩展

​ 注意:下面这些方法都是给数组的实例调用的

1、Array.prototype.indexOf(value):得到值在数组中的第一个下标

    <script type="text/javascript">
        var arr = [2,4,3,1,2,6,5,4]
        console.log(arr.indexOf(4))	//1
    </script>

2、Array.prototype.lastIndexOf(value):得到值在数组中的最后一个下标

    <script type="text/javascript">
        var arr = [2,4,3,1,2,6,5,4]
        console.log(arr.lastIndexOf(4))	//7
    </script>

3、Array.prototype.forEach(function(item, index){}):遍历数组

    <script type="text/javascript">
        var arr = [2,4,3,1,2,6,5,4]
        arr.forEach(function (item, index) {
            console.log(item, index)
        })
    </script>

4、Array.prototype.map(function(item, index){}):遍历数组返回一个新数组,返回加工之后的值

    <script type="text/javascript">
        var arr = [2,4,3,1,2,6,5,4]
        var arr1 = arr.map(function (item, index) {
            return item + 10
        })
        console.log(arr1)   //[12, 14, 13, 11, 12, 16, 15, 14]
    </script>

5、Array.prototype.filter(function(item, index){}):遍历过滤出一个新的子数组,返回条件为true的值

    <script type="text/javascript">
        var arr = [2,4,3,1,2,6,5,4]
        var arr2 = arr.filter(function (item, index) { //过滤出大于3的数
            return item > 3
        })
        console.log(arr2)   //[4, 6, 5, 4]
    </script>
六、Function扩展

1、Function.prototype.bind(obj)

​ 作用:将函数内的this绑定为obj,并将函数返回

2、面试题:区别bind()与call()和apply()

​ ● 都能指定函数中的this

​ ● call()/apply()是立即调用函数

​ ● bind() 是将函数返回

    <script type="text/javascript">
        var obj = {
            username: 'kobe'
        }
        function foo(data) {
            console.log(this, data)
        }
        //bind的特点:绑定完this不会立即调用当前的函数,而是将函数返回
        //bind传参的方式同call一样
        var bar = foo.bind(obj, 33)
        console.log(bar)
        bar()
    </script>

ES6

七、let_const关键字
1、let

​ ● 作用

​ 与 var 类似,用于声明一个变量

​ ● 特点

​ ○ 在块作用域内有效

​ ○ 不能重复声明

​ ○ 不会预处理(预解析,找到var后面的变量去声明但是不赋值以及找function并提前定义好),不存在提升

​ ● 应用

​ ○ 循环遍历加监听

​ ○ 使用let取代var是趋势

    <button>测试1</button>
    <button>测试2</button>
    <button>测试3</button>

    <script type="text/javascript">
        //console.log(username)   //会报错,不会预处理
        let username = 'kobe'
        //let username = 'wade' //let不能重复声明,这里会报错

        let btns = document.getElementsByTagName('button')
        for(let i = 0 ; i < btns.length ; i++){ //遍历循环监听,如果使用var声明i,那么alert函数都会打印3,使用let可以打印0,1,2。这是因为let在块级作用域内有效
            var btn = btns[i]
            btn.onclick = function () {
                alert(i)
            }
        }
    </script>

        //以前的做法,使用闭包打印,或者在button上面增加index属性,指定index为递增的整数
        for(var i = 0 ; i < btns.length ; i++){
            (function (i) {
                var btn = btns[i]
                btn.onclick = function () {
                    alert(i)
                }
            })(i)
        }
2、const

​ ● 作用

​ 定义一个常量

​ ● 特点

​ ○ 不能修改

​ ○ 其他特点同let

​ ● 应用

​ 保存不用改变的数据

    <script type="text/javascript">
        const KEY = 'NBA'
        KEY = 'CBA' //const声明的常量不能修改,会直接报错
    </script>
八、变量的解构赋值
1、理解

​ 从对象或数字中提取数据,并赋值给变量(多个)

2、对象的解构赋值
	let {n, a} = {n: 'tom', a: 12}
3、数组的解构赋值
	let [a, b] = [1, 'atguigu']
4、用途

​ 给多个形参赋值

    <script type="text/javascript">
        //以前的用法
        let obj = {username: 'kobe', age: 39}
//        let username = obj.username   //如果下面使用解构赋值了,这里如果还是这样定义会报错,遵循let的规则:不能重复定义
//        let age = obj.age

        //变量解构赋值
        let {username, age} = obj
        console.log(username, age)  //kobe, 39
        let {username, xxx} = obj
        console.log(username, xxx)  //kobe, undefined
        let {username} = obj
        console.log(username)  //kobe, 39

        //数组解构赋值
        let arr = [1,3,5,'abc',true]
        let [a, b, c, d, e] = arr
        console.log(a, b, c, d, e)  //1,3,5,'abc',true
        let [a, b] = arr
        console.log(a, b)   //1,3
        let [,,a,b] = arr
        console.log(a, b)   //5, 'abc'
        
        //函数参数解构赋值
        function foo({username, age}) {
            console.log(username, age)
        }
        foo(obj)
    </script>
九、模板字符串

1、模板字符串:简化字符串的拼接

​ 模板字符串必须用 `` 包含;

​ 变化的部分使用${xxx}定义;

    <script type="text/javascript">
        let obj = {username: 'kobe', age: 39}
        //以前的拼串
        let str = '我的名字叫: ' + obj.username + ", 年龄是: " + obj.age
        console.log(str)

        //使用模板字符串
        str = `我的名字叫: ${obj.username}, 年龄是: ${obj.age}`
        console.log(str)
    </script>

十、对象的简写方式

​ 简化的对象写法:

​ ● 省略同名的属性值

​ ● 省略方法的function

    <script type="text/javascript">
        let username = 'kobe'
        let age = 39
        //以前的写法
        let obj = {
            username: username,
            age: age,
            getName: function () {
                return this.username
            }
        }
        console.log(obj)
        //简写方式
        obj = {
            username,   //同名的属性可以省略不写
            age,
            getName(){  //可以省略函数的function
                return this.username
            }
        }
        console.log(obj)
    </script>

十一、箭头函数
1、作用

​ 定义匿名函数

2、基本语法

​ ● 没有参数:() => console.log(‘xxx’)

​ ● 一个参数:i => i+2

​ ● 大于一个参数:(i, j) => i+j

​ ● 函数体不用大括号:默认返回结果

​ ● 函数体如果有多个语句,需要用{}包围,若有需要返回的内容,需要手动返回

3、使用场景

​ 多用来定义回调函数

4、箭头函数特点

​ ● 简洁

​ ● 箭头函数没有自己的this,箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this

​ ● 扩展理解:箭头函数的this看外层是否有函数

​ 如果有,外层函数的this就是内部箭头函数的this

​ 如果没有,则 this 是 window

    <button id="btn1">测试箭头函数this_1</button>
    <button id="btn2">测试箭头函数this_2</button>

    <script type="text/javascript">
//        let fun = function () {
//
//        }
/***************************************************************************************/
        //形参的情况
        //1.没有形参的时候
        let fun1 = () => console.log('我是箭头函数')
        fun1()

        //2.只有一个形参的时候;当只有一个形参的时候()可以省略
        let fun2 = (a) => console.log(a)
        fun2('aaa')
        fun2 = a => console.log(a)
        fun2('bbb')

        //3.两个及两个以上的形参的时候; 当形参是两个或两个以上的时候()不能省略
        let fun3 = (x, y) => console.log(x, y)
        fun3(12, 23)
/***************************************************************************************/
        //函数体的情况
        //1.函数体只有一条语句或者是表达式的时候{ }可以省略-->省略{ }带来的结果是会自动返回语句执行的结果或者是表达式的结果
        //  如果加了{ },并且希望返回计算结果时,需要使用return
        let fun4 = () => console.log('我是箭头函数')
        fun4()
        fun4 = (x, y) => x+y
        console.log(fun4(12, 42))   //54
        fun4 = (x, y) => {return x+y}
        console.log(fun4(12, 45))   //57
        //2.函数体不止一条语句或者是表达式的情况{ }不能省略
        let fun5 = (x, y) => {
            console.log(x, y)
            return x+y
        }
        console.log(fun5(35, 49))

    </script>
/***************************************************************************************/
    <script type="text/javascript">
        //测试箭头函数的this
        let btn1 = document.getElementById('btn1')
        let btn2 = document.getElementById('btn2')
        btn2.onclick = () => {
            alert(this)
        }

        let obj = {
            name: '箭头函数',
            getName(){
                btn2.onclick = () => {
                    console.log(this)
                }
            }
        }
        obj.getName()
    </script>

十二、三点运算符

​ ● 用途

​ ○ rest(可变)参数

​ ■ 用来取代 arguments,但比 arguments 灵活,只能是最后部分形参参数

        function foo(a, b) {
            console.log(arguments)
            //arguments.callee 就是函数本身
            console.log(arguments.callee)
//            arguments.forEach(function (item, index) {    //这样会报错,forEach是数组特有方法,arguments是伪数组,不具备这个方法
//
//            })
        }
        foo(2, 65)
/***************************************************************************************/
        function foo1(...value) {
            console.log(value)
            //arguments.callee 就是函数本身
            console.log(arguments.callee)
            value.forEach(function (item, index) {    //value是真数组,可以调用forEach
                console.log(item, index)
            })
        }
        foo1(2, 65)
/***************************************************************************************/
        function foo1(a, ...value) {    //三点运算符前面还可以传形参,但是后面不能加形参
            console.log(value)
            //arguments.callee 就是函数本身
            console.log(arguments.callee)
            value.forEach(function (item, index) {    //value是真数组,可以调用forEach
                console.log(item, index)
            })
        }
        foo1(2, 65, 45, 23) //会将2赋给a,其他的赋给value

​ ○ 扩展运算符

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

十三、形参默认值

​ 形参默认值:调用函数时如果没传实参则使用默认值,传了实参则使用实际实参值

    <script type="text/javascript">
        //定义一个点的坐标的构造函数
        function Point(x = 1, y = 2) {
            this.x = x
            this.y = y
        }
        let point = new Point(23, 35)
        console.log(point)
        let point1 = new Point()
        console.log(point1)
    </script>

十四、promise对象
1、理解

​ ● promise对象:代表了未来某个将要发生的事件(通常是一个异步事件)

​ ● 有了promise对象,可以将异步操作以同步的流程表达出来,避免了层次嵌套的回调函数(俗称’回调地狱’)

​ ● ES6的promise是一个构造函数,用来生成promise实例

2、使用promise基本步骤

​ ● 创建promise对象

​ ● 调用promise的then()

    <script type="text/javascript">
        //创建promise对象
        let promise = new Promise((resolve, reject) => {   //这个函数是同步的,说明会先执行函数体里面的内容
            //初始化promise状态:pending -- 初始化
            console.log('111')
            //执行异步操作,通常是发送ajax请求、开启定时器
            setTimeout(() => {
                console.log('333')
                //根据异步任务的返回结果去修改promise的状态
                //异步认为执行成功
                resolve(data)   //修改promise的状态为fullfilled -- 成功的状态
                reject(data)    //修改promise的状态为 rejected  -- 失败的状态
            }, 2000)
        })
        console.log('222')

        promise
                .then((data) => {   //成功的回调
                    console.log(data, '成功了...')
                }, (data) => {      //失败的回调
                    console.log(data, '失败了...')
                })
    </script>

3、promise对象的3个状态

​ ● pending:初始化状态

​ ● fullfilled:成功状态

​ ● rejected:失败状态

4、应用

​ ● 使用promise实现超时处理

​ ● 使用promise封装处理ajax请求

5、promise练习
    <script type="text/javascript">
        //定义获取新闻的功能函数
        function getNews(url) {
            let promise = new Promise((resolve, reject) => {
                //状态:初始化
                //执行异步任务
                //创建xmlHttp实例对象
                let xmlHttp = new XMLHttpRequest();
                //绑定监听 readyState
                xmlHttp.onreadystatechange = function () {
                    if(xmlHttp.readyState === 4){
                        if(xmlHttp.status == 200){  //请求成功
                            console.log(xmlHttp.responseText)
                            //修改状态
                            resolve(xmlHttp.responseText)   //修改promise的状态为成功状态
                        } else {    //请求失败
                            reject('暂时没有新闻内容')
                        }
                    }
                }
                //open 设置请求的方式以及url
                xmlHttp.open('GET', url)
                // 发送
                xmlHttp.send()
            })
            return promise
        }

        getNews('http://localhost:8080/news?id=1')
                .then((data) => {
                    console.log(data)
                    //发送请求获取评论内容
                    let commentsUrl = JSON.parse(data).commentsUrl
                    let url = 'http://localhost:8080' + commentsUrl
                    //发送请求
                    return getNews(url)
                }, (error) => {
                    console.log(error)
                })
                .then((data) => {
                    console.log(data)
                }, () => {
                    
                })
    </script>

十五、Symbol
1、前言

​ ES5中对象的属性名都是字符串,容易造成重名,污染环境

2、概念

​ ES6中添加了一种原始数据类型symbol(已有的原始数据类型:String,Number,boolean,null,

​ undefined,对象)

3、特点

​ ● symbol属性对应的值是唯一的,解决命名冲突问题

​ ● symbol值不能与其他数据进行计算,包括同字符串拼串

​ ● for in,for of 遍历时不会遍历symbol属性

4、使用

​ ● 调用Symbol函数得到symbol值

	let symbol = Symbol()
    let obj = {}
    obj[symbol] = 'hello'

​ ● 传参标识

	let symbol = Symbol('one')
    let symbol2 = Symbol('two')
    console.log(symbol)		//Symbol('one')
	console.log(symbol2)	//Symbol('two')

​ ● 内置Symbol值

​ ○ 除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法

​ ○ Symbol.iterator

​ 对象的Symbol.iterator属性,指向该对象的默认遍历器方法

代码:

    <script type="text/javascript">
        //创建symbol属性值
        let symbol = Symbol()
        console.log(symbol)
        let obj = {username: 'kobe', age: 39}
        obj[symbol] = 'hello'
        console.log(obj)
        //for in,for of不能遍历symbol属性
        for(let i in obj){
            console.log(i)
        }

        let symbol2 = Symbol()
        let symbol3 = Symbol()
        console.log(symbol2 == symbol3) //false
        symbol2 = Symbol('one')
        symbol3 = Symbol('two')
        console.log(symbol2, symbol3)

        //可以去定义常量
        const Person_key = Symbol('person_key')
        console.log(Person_key)
    </script>

十六、iterator接口机制
1、概念

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

2、作用

​ ● 为各种数据结构提供一个统一的、简便的访问接口

​ ● 使得数据结构的成员能够按某种顺序排列

​ ● ES6 创造了一种新的遍历命令 for…of 循环,Iterator接口主要供 for…of 消费

3、工作原理

​ ● 创建一个指针对象(遍历器对象),指向数据结构的起始位置

​ ● 第一次调用next方法,指针自动指向数据结构的第一个成员

​ ● 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员

​ ● 每调用next方法返回的是一个包含 value 和 done 的对象,{value: 当前成员的值, done: 布尔值}

​ ○ value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束

​ ○ 当遍历结束的时候返回的value值是undefined,done值为true

​ 原生具备iterator接口的数据(可用for of 遍历)

4、扩展理解

​ ● 当数据结构上部署了Symbol.iterator接口,该数据就是可以用for of 遍历

​ ● 当使用for of去遍历目标数据的时候,该数据会自动去找Symbol.iterator属性

​ //Symbol.iterator 属性指向对象的默认遍历器方法(承接上一章节:iterator接口)

​ ■ Array

​ ■ arguments

​ ■ set 容器

​ ■ map容器

​ ■ String

​ …

模拟遍历器对象:

    <script type="text/javascript">
        //模拟指针对象(遍历器对象)
        function myIterator(arr) {  //iterator接口
            let nextIndex = 0   //记录指针的位置
            return {
                next: function () {
                    return nextIndex < arr.length ? {value: arr[nextIndex++], done: false}:
                    {value: undefined, done: true}
                }
            }
        }
        //准备一个数据
        let arr = [1, 4, 65, 'abc']
        let iteratorObj = myIterator(arr)
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
        console.log(iteratorObj.next())
    </script>

使用for of遍历有iterator接口的数据类型

    <script type="text/javascript">
        let arr = [1,5,3,'abc',true]
        //es6将iterator接口部署到指定的数据类型上,可以使用for of去循环遍历
        //部署的数据类型有:数组、字符串、arguments、set容器、map容器
        for(let i of arr){
            console.log(i)  //1,5,3,'abc',true
        }

        let str = 'abcdefg'
        for(let i of str){
            console.log(i)  //a,b,c,d,e,f,g
        }
        
        function fun() {
            for(let i of arguments){
                console.log(i)  //1,4,5,'abc
            }            
        }
        fun(1,4,5,'abc')
        
        let obj = {username: 'kobe', age: 39}
        for(let i of obj){  //对象不能使用iterator
            console.log(i)
        }
    </script>

当数据结构上部署了Symbol.iterator接口,该数据就是可以用for of 遍历;当使用for of去遍历目标数据的时候,该数据会自动去找Symbol.iterator属性

    <script type="text/javascript">
        //等同于在指定的数据内结构上部署了iterator接口
        //当使用for of去遍历某一个数据结构的时候,首先去找Symbol.iterator,找到了就去遍历,没有找到的话不能遍历,会报obj is not iterator的错误
        let targetData = {
            [Symbol.iterator]: function () {
                let nextIndex = 0   //记录指针的位置
                return {
                    next: function () {
                        return nextIndex < this.length ? {value: this[nextIndex++], done: false}:
                        {value: undefined, done: true}
                    }
                }
            }
        }

        //使用三点运算符、结构赋值,默认去调用iterator接口
        let arr1 = [1,6]
        let arr2 = [2,3,4,5]
        arr1 = [1, ...arr2, 6]
        console.log(arr1)
        let [a,b] = arr1
        console.log(a, b)
    </script>

十七、Generator函数
1、概念

​ ● ES6提供的解决异步编程的方案之一

​ ● Generator函数时一个状态机,内部封装了不同状态的数据

​ ● 用来生成遍历器对象

​ ● 可暂停函数(惰性求值),yield可暂停,next方法可启动。每次返回的是yield后的表达式结构

2、特点

​ ● function 与函数名之间有一个星号

​ ● 内部用yield表达式来定义不同的状态

​ ● 例如:

	function* generatorExample(){
        let result = yield 'hello'	//状态值为 hello
        yield 'generator'	//状态值为 gendrator
    }

​ ● generator函数返回的是指针对象(接iterator章节),而不会执行函数内部逻辑

​ ● 调用next方法函数内部逻辑开始执行,遇到yield表达式停止,返回{value: yield后的表达式结构/undefined,

​ done: }

​ ● 再次调用next方法会从上一次停止时的yield处开始,直到最后

​ ● yield语句返回结果通常为undefined,当调用next方法时,传参内容会作为启动时yield语句的返回值

代码:

    <script type="text/javascript">
        function* myGenerator() {
            console.log('开始执行')
            /*
            *   yield 'hello' 这个语句的返回值一般是undefined,要获取返回值,使用let result = yield 'hello'
            *   但是如果想获得返回值,可以在MG.next()中传入参数,这个参数就是返回值,如:
            *   MG.next('abc'),那么 yield 'hello' 的返回值就是 'abc'
            * */
            let result = yield 'hello'
            console.log(result)
            console.log('暂停后,再次执行')
            yield 'generator'
            console.log('遍历完毕')
            return '返回的结果'
        }
        let MG = myGenerator()  //返回指针对象
        console.log(MG.next())  //{value: hello, done: false}
        console.log(MG.next('abc'))  //{value: generator, done: false}
        console.log(MG.next())  //{value: '返回的结果', done: true}
    </script>

对象的symbol.iterator属性指向遍历器对象

    <script type="text/javascript">
        //对象的symbol.iterator属性指向遍历器对象
        let obj = {username: 'kobe', age: 39}
        obj[Symbol.iterator] = function* myTest () {
            yield 1
            yield 2
            yield 3
        }
        for(let i of obj){
            console.log(i)  //1,2,3
        }
    </script>

Generator函数练习:

    <script type="text/javascript">
        function getNews() {
            $.get(url, function (data) {
                console.log(data)
                let url = 'http://localhost:8080' + data.commentsUrl
                SX.next(url)	//第14行
            })
        }

        function *sendXml() {
            //这里两个url是第14行传过来的url
            let url = yield getNews('http://localhost:8080/news?id=1')
            yield getNews(url)
        }

        //获取遍历器对象
        let SX = sendXml()
        SX.next()
		/*
			指向逻辑:首先获取遍历器对象,获取遍历器对象以后,通过SX.next()方法会执行遍历器中的第一个
			yield,执行第一个yield时,会调用上面的getNews方法,调用getNews方法时,在最后又会执行
			SX.next()方法,当执行第二个SX.next()方法后,又会执行遍历器中的第二个yield,此时第二个
			SX.next()方法的入参会给到遍历器的第一个yield的返回值,将返回值传给第二个yield,全部过程完毕
		*/
    </script>

十八、class类使用

1、通过class定义类/实现类的继承

2、在类中通过constructor定义构造方法

3、通过new来创建类的实例

4、通过extends来实现类的继承

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

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

    <script type="text/javascript">
        //定义一个人物的类
        class Person{
            constructor(name, age){
                this.name = name
                this.age = age
            }
            //类的一般方法
            showName(){ //这里不能用 showName: function(){}的方式,会报错。只能用简写方式
                console.log(this.name, this.age)
            }
        }
        let person = new Person('kobe', 39)
        console.log(person)
        person.showName()

        //子类
        class StarPerson extends Person{
            constructor(name, age, salary){
                super(name, age) //调用父类的构造方法
                this.salary = salary
            }
            showName(){
                console.log(this.name, this.age, this.salary)
            }
        }
        let p1 = new StarPerson('wade', 36, 100000000000)
        console.log(p1) //会调用子类重写的方法
    </script>

十九、字符串、数值的扩展
1、字符串扩展

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

​ ● startsWith(str):判断是否以指定字符串开头

​ ● endsWith(str):判断是否以指定字符串结尾

​ ● repeat(count):将指定字符串重复指定次数

    <script type="text/javascript">
        let str = 'abljwelfjwgjorjlef'
        console.log(str.includes('l'))  //true
        console.log(str.startsWith('a'))
        console.log(str.endsWith('f'))
        console.log(str.repeat(5))	//将str重复5次
    </script>

2、数值的扩展

​ ● 二进制与八进制数值表示法:二进制用0b,八进制用0o

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

​ ● Number.isNaN(i):判断是否是NaN

​ ● Number.isInteger(i):判断是否是整数

​ ● Number.parseInt(str):将字符串转换为对应的数值

​ ● Math.trunc(i):直接去除小数部分

	<script type="text/javascript">
        console.log(0b1010)
		console.log(0o23)
		console.log(Number.isFinite(Infinity))
		console.log(Number.isNaN(NaN))
		console.log(Number.isInteger(123.0))	//true
		console.log(Number.parseInt('23abc'))	//123
		console.log(Math.trunc(123.123))	//123
    </script>

二十、数组的扩展

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

​ ● Array.of(v1, v2, v3):将一系列值转换成数组

​ ● find(function(value, index, arr){return true}):找出第一个满足条件的true的元素

​ ● findIndex(function(value, index, arr){return true}):找出第一个满足条件返回true的元素下标

​ ● [].slice.call(lis): 将伪数组转换为真数组

	let btns = document.getElementsByTagName('button')
    Array.from(btns).forEach(function(item, index){
        console.log(item)
    })

	let arr = Array.of(1,4,'abc',true)
    console.log(arr)

	let arr2 = [2,3,4,2,5,7,3,6,5]
    let result = arr2.find(function(item, index){
        return item > 4
    })
    console.log(result)	//5

	result = arr2.findIndex(function(item, index){
        return item > 4
    })
	console.log(result)	//true

二十一、对象的扩展

1、Object.is(v1, v2):判断2个数据是否完全相等

2、Object.assign(target, source1, source2 …):将源对象的属性赋值到目标对象上

3、直接操作 __proto__属性

​ let obj2 = {}

​ obj2.__proto__ = obj1

4、Object.keys(obj): 得到对象自身可枚举属性组成的数组

	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.is()是以字符串的形式判断
    
    let obj = {}
    let obj1 = {username: 'anverson', age: 42}
    let obj2 = {sex: '男'}
    Object.assign(obj, obj1, obj2)
	console.log(obj)
	
	let obj3 = {}
    let obj4 = {qian: 50000}
    obj3.__proto__ = obj4
	console.log(obj3)
	console.log(obj3.qian)	//50000

二十二、深度克隆
1、数据类型

​ ● 数据分为基本数据类型(String,Number,Boolean,Null,Undefined)和对象数据类型

​ ○ 基本数据类型

​ 特点:存储的是该对象的实际数据

​ ○ 对象数据类型

​ 特点:存储的是该对象在栈中引用,真是的数据存放在堆内存里

2、复制数据

​ ● 基本数据类型存放的就是实际的数据,可直接复制

​ let number1 = 2

​ let number2 = number2

​ ● 克隆数据:对象/数组

​ ○ 区别:浅拷贝/深度拷贝

​ 判断:拷贝是否产生了新的数据还是拷贝的是数据的引用

​ 知识点:对象数据存放的是对象在栈内存的引用,直接复制的是对象的引用

​ let obj = {username: ‘kobe’}

​ let obj1 = obj //obj1复制了obj在栈内存的引用

浅拷贝:拷贝的引用,修改拷贝以后的数据会影响源数据,使得源数据不安全

深拷贝:拷贝的时候生成新数据,修改拷贝以后的数据不会影响源数据

​ ○ 常用的拷贝技术

​ 1)、arr.concat():数组浅拷贝

​ 2)、arr.slice():数组浅拷贝

​ 3)、JSON.parse(JSON.stringify(arr/obj)):数组或对象深拷贝,但不能处理函数数据

​ 4)、浅拷贝包含函数数据的对象/数组

​ 5)、深拷贝包含函数数据的对象/数组

    <script type="text/javascript">
        //不会影响原数据
        let str = 'abcd'
        let str2 = str
        console.log(str2)   //abcd
        str2 = ''
        console.log(str)    //abcd

        let obj = {username: 'kobe', age: 39}
        let obj1 = obj
        console.log(obj1)   //{username: 'kobe', age: 39}
        boj1.uaername = 'wade'
        console.log(obj.username)   //wade

        //拷贝数组/对象,没有生产新的数据而是复制了一份引用
        let arr = [1, 4, {username: 'kobe', age: 39}]
        let arr2 = arr
        arr2[0] = 'abcd'
        console.log(arr, arr2)  //都是['abcd', 4, {username: 'kobe', age: 39}]
        /*
        * 拷贝数据:
        *   基本数据类型:
        *       拷贝后会生成一份新的数据,修改拷贝以后的数据不会影响源数据
        *   对象/数组
        *       拷贝后不会生成新的数据,而是拷贝引用。修改拷贝以后的数据会影响原来的数据
        * 拷贝数据的方法:
        *   1.直接赋值给一个变量             //浅拷贝,如上面数组的拷贝
        *   2.Object.assign()               //浅拷贝
        *   3.Array.prototype.concat()      //浅拷贝
        *   4.Array.prototype.slice()       //浅拷贝
        *   5.JSON.parse(JSON.stringify())	//深度克隆,但是拷贝的数据不能有函数,它处理不了
        * */

        //验证 Object.assign() -- 浅拷贝,会影响原数组
        let obj = {username: 'kobe'}
        let obj2 = Object.assign(obj)
        console.log(obj2)
        obj.username = 'wade'
        console.log(obj, obj2)    //{username: 'wade'}, {username: 'wade'}

        //验证 Array.prototype.concat() -- 浅拷贝,会影响原数组,但是基本数据类型不会有影响
        let arr = [1, 3, {username: 'kobe'}]
        let testArr = [2, 4]
        let arr2 = arr.concat()
        console.log(arr2)   //[1, 3, {username: 'kobe'}]
        arr2[1] = 'a'
        console.log(arr)    //[1, 3, {username: 'kobe'}]
        arr[2].username = 'wade'
        console.log(arr)    //[1, 3, {username: 'wade'}]

        //验证 Array.prototype.slice() -- 浅拷贝
        let arr3 = arr.slice()
        arr3[2].username = 'anverson'
        console.log(arr)    //[1, 3, {username: 'anverson'}]

        //验证 JSON.parse(JSON.stringify()) -- 深拷贝
        let arr4 = JSON.parse(JSON.stringify(arr))
        console.log(arr4)
        arr4[2].username = 'duncan'
        console.log(arr, arr4)  //[1, 3, {username: 'anverson'}], [1, 3, {username: 'duncan'}]
		arr[3] = function fun(){}
		arr4 = JSON.parse(JSON.stringify(arr))
        console.log(arr4)	//不会将函数进行拷贝,因为JSON.stringify会将对象转换为JSON字符串,修改了数据类型
    </script>

3、深度克隆实现
    <script type="text/javascript">
        /*
        *   思考:
        *       如何实现深度拷贝(克隆)
        *       拷贝的数据里有对象/数组时,不能实现深度克隆,要想深度克隆,拷贝的数据里不
        *       能有对象/数组
        *       即使有对象/数组可以继续遍历对象/数组里边每一项值,
        *       一直拿到基本数据类型,然后再去赋值,就是深度拷贝
        * */
        //知识点储备
        /*
        *   如何判断数据类型:arr --> Array    null --> Null
        *   1、typeof返回的数据类型:String,Number,Boolean,Undefined,Object,Function
        *   2、Object.prototype.toString.call(obj)
        * */
        let res = 'abcd'
        console.log(Object.prototype.toString.call(res))   //string
        res = null
        console.log(Object.prototype.toString.call(res))   //null
        res = [1, 3]
        console.log(Object.prototype.toString.call(res))   //array
        
        //for in 循环遍历对象时返回属性名,遍历数组时返回下标
        let obj = {username: 'kobe', age: 39}
        for(let i in obj){
            console.log(i)  //username, age
        }
        let arr = [1, 3, 'abc']
        for(let i in arr){
            console.log(i)  //0,1,2
        }
        
        //定义检测数据类型的功能函数
        function checkedType(target){
            return Object.prototype.toString.call(target).slice(8, -1)
        }

        //实现深度克隆 --> 对象/数组
        function clone(target) {
            //判断拷贝的数据类型
            //初始化 result 成为最终克隆的数据
            let result, targetType = checkedType(target)
            if(targetType === 'Object'){
                result = {}
            } else if(targetType == 'Array'){
                result = []
            } else {
                return target
            }

            //遍历目标数据
            for(let i in target){
                //获取数据结构的每一项值
                let value = target[i]
                //判断目标结构里的每一项值是否存在对象/数组
                if(checkedType(value) === 'Object' || checkedType(value) === 'Array'){
                    //继续遍历获取到的value值
                    resulet[i] = clone(value)
                } else {    //获取到的value值是基本数据类型或者是函数
                    result[i] = value
                }
            }
            return result
        }
        let arr3 = [1,2,{username: 'kobe', age:39}]
        let arr4 = clone(arr3)
        console.log(arr4)
        arr4[2].username = 'wade'
        console.log(arr3, arr4)

        let obj3 = {username: 'kobe', age: 39}
        let obj4 = obj3
        console.log(obj4)
        obj4.username = 'wade'
        console.log(obj3, obj4)
    </script>

二十三、set、map容器
1、Set容器

​ 无序不可重复的多个value的集合体

​ 方法:

​ ● Set()

​ ● Set(array)

​ ● add(value)

​ ● delete(value)

​ ● has(value)

​ ● clear()

​ ● size

2、Map容器

​ 无序的 key,不重复的 key-value 的集合体

​ 方法:

​ ● Map()

​ ● Map(array)

​ ● set(key, value) //添加

​ ● get(key)

​ ● delete(key)

​ ● has(key)

​ ● clear()

​ ● size

    <script type="text/javascript">
        let set = new Set([1,2,5,7,4,8,4])
        console.log(set)    //1,2,5,7,4,8
        set.add(3)
        console.log(set.size, set)  //7  1,2,5,7,4,8,3
        console.log(set.has(9)) //false
        console.log(set.has(7)) //true
        set.clear()
        console.log(set)    //把所有数据清除了

        let map = new Map([['aaa','username'], [36, 'age']])
        console.log(map)
        map.set(78, 'haha')
        console.log(map)
        map.delete('aaa')
        console.log(map)
    </script>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值