JavaScript - Day13 - this关键字和ES6

一、this关键字

1.this关键字的含义

         js中内置了this关键字,在不同的作用域中表示的含义不一样的

       (1)全局的this

    console.log(this) // window

       (2)普通函数的this - 所谓普通函数,指的是直接拿函数名称调用的函数

    function fn(){
        console.log(this) // window
    }
    fn()

       (3)自调用函数中的this

    (function(){
        console.log(this); // window
    })()

       (4)定时器中的this

    setTimeout(function(){
        console.log(this); // window
    },1000)

       (5)事件函数中的this

    <button id="btn">按钮</button>
    btn.onclick = function () {
        console.log(this) // 事件的标签
    }

       (6)对象方法中的this

    var obj = {
        name: '张三',
        age: 12,
        eat: function () {
            console.log(this); // 当前对象
        }
    }
    obj.eat()

       (7)箭头函数中的this - 上级作用域的this

       (8)严格模式中普通函数的this

    'use strict'
    function fn(){
        console.log(this) // undefined
    }
    fn()

2.this关键字含义的理解

       普通函数,大多都属于window的方法,所以普通函数调用就是调用window的方法;事件的绑定,其实就是在给标签对象添加方法,最终调用,其实也是在调用标签对象的方法;定时器属于window的方法,所以定时器的调用其实就是在调用window的方法

       其实一个函数定义好以后,还不能确定其中的this代表什么,主要是看这个函数最终是如何调用的。根据最终的调用方式,决定最终将函数当做了什么来调用的,才能决定this关键字的含义

function fn() {
    console.log(this)
}

// 将fn当做事件处理函数
btn.onclick = fn
// 此时fn中的this就代表事件源btn

// 将fn当做定时器的处理函数
setTimeout(fn, 1000)
// 此时fn中的this就代表window

// 将fn当做对象的方法
var obj = {
    name: '张三',
    age: 12,
    eat: fn
}
obj.eat()
// 此时fn中的this就代表对象obj

    自调用函数 === window.函数()

    全局中的this - window

    (1)函数定义好还不能确定this代表什么 - 关键取决于谁调用的他

    (2)箭头函数定义好就已经知道this代表什么 - 箭头函数中的this不能改

3.改变this的含义

      js提供了3个函数来强行修改this关键字的含义:

          3-1.call方法

                      call方法有两个作用:调用函数以及改变函数中的this

                    (1)调用函数

                                    语法:函数.call()

                    (2)改变this

                                    语法:函数.call(新的this含义)

                    (3)参数处理

                                    语法:函数.call(新的this含义, 给原函数传递实参1, 给原函数传递实参2)

                                    给call传递第一个参数为null,就表示将函数中的this改为了window

    function fn() {
        console.log(this); 
    }
    fn() // window
    fn.call() // window
    fn.call(document) // #document

    function add(a, b) {
        console.log(a + b);
        console.log(this);
    }
    add(1, 2) // 3
    add.call(document, 3, 4) //7 #document
    // 函数需要的实参,从call的第二个实参开始传递

          3-2.apply方法

                      apply和call的作用是相同的,唯一不同的地方,在于传递实参。

                      call在调用函数时,给函数传递实参,是从call的第二个参数开始传递;apply给函数                 传递实参,是将所有实参组成一个数组作为apply的第二个参数传递的:

                      apply方法有两个作用:调用函数以及改变函数中的this

                    (1)调用函数

                                    语法:函数.apply()

                    (2)改变this

                                    语法:函数.apply(新的this含义)

                    (3)参数处理

                                    语法:函数.call(新的this含义, [实参1, 实参2, ...])

    function fn() {
        console.log(this);
    }
    fn.apply(document) // #document

    function add(a, b) {
        console.log(a + b);
        console.log(this);
    }
    add.apply(document, [3, 4]) //7 #document
    // add需要的实参,都组成一个数组,作为apply的第二个参数

                    (4)call和apply的使用场景

                                  场景1:精准的检测对象的具体类型

                                           {}有toString,转成字符串的结果是 [object Object]

                                           toString方法中的this代表的是{}

                                           我们希望date能使用到{}的toSting方法,结果像上面的结果一样 - 改this

                                           {}.toString.call(date)  [object Date]

    // 场景1:精准的检测对象的具体类型
    var date = new Date()
    var arr = []
    var obj = {}
    Math

    // 类型检测 - typeof 
    console.log(typeof date);
    console.log(typeof arr);
    console.log(typeof obj);
    console.log(typeof Math);

    // typeof检测对象类型时候太单一  - 不能很直观的看到对象具体是干什么用的
    console.log({}.toString.call(date));   // [object Date]
    console.log({}.toString.call(arr));    // [object Array]
    console.log({}.toString.call(obj));    // [object Object]
    console.log({}.toString.call(Math));   // [object Math]

    console.log({}.toString.apply(date));   // [object Date]
    console.log({}.toString.apply(arr));    // [object Array]
    console.log({}.toString.apply(obj));    // [object Object]
    console.log({}.toString.apply(Math));   // [object Math]

          3-3.bind方法

                      bind方法有两个作用:复制函数,并改变新函数中的this。

                    (1)复制函数

                                    语法:函数.bind()  -----  返回新函数

                                    复制出来的新函数和原本的函数一模一样,但不是同一个

                    (2)改变this

                                    语法:函数.bind(新的this含义) ------ 返回的新函数中,this的含义会变成新的含义

                                    bind不加参数,新函数的this为window

                    (3)参数处理

                                    语法:函数.bind(改变后的this含义) - 复制函数,返回一个新函数

    function fn() {
        console.log(this);
    }
    var newFn = fn.bind(document)
    console.log(newFn);
    newFn() // #document
    console.log(fn === newFn); // false - 新函数和原函数不是同一个

    function add(a, b) {
        console.log(a + b);
        console.log(this);
    }

    var newAdd = add.bind(document)
    newAdd(3, 4)  //7 #document

                    (4)bind使用场景

<body>
    <button>按钮</button>
</body>
<script>
    document.querySelector('button').onclick = function () {

        setTimeout((function () {
            // 改变btn的背景颜色
            // document.querySelector('button')
            this.style.backgroundColor = 'red'
        }).bind(this), 500)
    }

二、ES6语法

          es6是ECMAScript的第6个版本,在2015年发布。也有的人将ECMAScript5之后版本,统称为es6。比起之前的语法,es6有很多新语法,让开发者在操作数据和函数的时候,功能既多,操作又简便。

1.定义变量

          1-1.let

                (1)let是es6新增的用于定义变量的关键字 - 使用方式跟var是一样的

    var a = 10
    console.log(a); // 10
    let b = 20
    console.log(b); // 20

                (2)let定义变量没有预解析

    var a = 10
    console.log(a);  // 10
    var a
    var b = 20
    console.log(b); // 报错 
    let b

                (3)let不允许重复定义变量

    var a = 10
    var a = 20
    console.log(a); // 20
    let b = 10 
    let b = 20
    console.log(b); // 报错

                (4)let定义的变量会自己创建一个块级作用域,将自己的作用域限制在大括号中。

例1
    for (var a = 1; a <= 3; a++) {

    } console.log(a); // 4 
    
    for (let a = 1; a <= 3; a++) {

    } console.log(a); // a没定义

例2
    var a = 10 // window打开有 a=10
    let a = 10 // window打开没有 a=10 - 说明它自带了一个作用域,大括号外面才是真正的window
    console.log(window);

例3
    for (var a = 1; a <= 3; a++) {
        (function (a) {
            setTimeout(function () {
                console.log(a);
            }, a * 1000)
        })(a)
    }

    for (let a = 1; a <= 3; a++) {
        setTimeout(function () {
            console.log(a);
        }, a * 1000)
    }

                (5)暂时性死区

    var a = 10
    function fn() {
        // 暂时性死区
        a = 20
        console.log(a);
        // let其实还是会提前解析到,只是解析后也不能使用
        let a = 30
    }
    fn()
    console.log(a);

                (6)总结:

                            (1)没有预解析

                            (2)不能重复定义

                            (3)会自带块级作用域(全局定义的变量不在window中)

          1-2.const

                (1)const是es6新增的用于定义常量的关键字 - 使用方式跟var是一样的,具备let的所有特性,另外,const定义的变量的值不能修改。

                (2)const没有预解析

    console.log(a); // 报错 - 没有预解析
    const a = 10 

                (3)const不能重复定义变量

    const a = 10
    const a = 20

                (4)const定义的变量会自己创建一个块级作用域,将自己的作用域限制在大括号中。

    if (true) {
        const a = 10
    }
    console.log(a); // 报错 - 有块级作用域

                (5)const跟let不一样的地方

                        (5-1)定义就必须赋值

    let a
    a = 10
    const b // 报错
    b = 20

                        (5-2)const的值不能改

    let a = 10
    a = 20
    console.log(a);
    const b = 20
    b = 30
    console.log(b);

                (6)总结:

                            (1)let具有的特性const都有

                            (2)定义就必须赋值

                            (3)值不可以改

2.箭头函数

        是es6中提供的新的定义函数的语法

        其实是对以前函数定义的一种简写 - 只能简写匿名函数

        语法: (形参)=>{代码段} -- 匿名函数

    // 平时写法
    function fn() {
        console.log(666);
    }
    var fn = function() {
        console.log(666);
    }
    var fn = () => {
        console.log(666);
    }
    fn()

    var add = function(a, b) {
        console.log(a + b);
    }
    var arr = (a, b) => {
        console.log(a + b);
    }
    add(3, 4)

               1.当小括号中只有一个形参的话,就可以省略小括号

    var add = function (a) {
        console.log(a + 6);
    }

    var add = (a) => {
        console.log(a+6);
    }
    add(2)

               2.当大括号中只有一行代码的话,就可以省略大括号

    var add = function (a) {
        console.log(a + 6);
    }

    var add = a => console.log(a+6);
    add(2)

                       当箭头函数省略大括号后,如果这行代码中有return关键字,return关键字必须省略

    var add = function (a) {
        return a + 3
    }

    var add = a => a + 3 // 如果return a + 3就会报错
    var sum = add(4)
    console.log(sum);

               3.箭头函数使用场景:通常在数组方法中使用

                   map - 新元素

                   filter - 条件

                   every - 条件

                   some - 条件

                   find - 条件

                   findIndex - 条件

                   以上几个数组方法的通常写法: 数组.方法(function (v) {

                                                                                      return 内容

                                                                         })

                                            箭头函数写法: 数组.方法(v => 内容

               4.箭头函数中没有this关键字 - 可以说箭头函数中的this代表的是箭头函数所在作用域中的this

    var fn = () => {
        console.log(this); /* 想输出this关键字,就得从上级作用域中查找,也就是说箭头函数里
                                      面的this代表上级作用域中的this - 此时为window  */
    }
    fn()

    document.onclick = () => {
        console.log(this); // window
    }

               5.箭头函数定义好了就已经知道this代表什么了

    var obj = {
        name: '张三',
        eat: () => {
            console.log(this); /* window - 因为obj没有作用域,只有函数有作用域,所以直接到
                                                                       全局找this  */
        }
    }
    obj.eat.call(document)// 箭头函数中的this不能修改

3.形参默认值

       因为函数调用随机数时,多数情况下有一个参数为0,所以希望调用的时候能简便一点

    随机颜色 - getRandom(0,256)
    随机字符 - getRandom(97,123)
    随机left值 - getRandom(0,innerWidth-30)
    随机下标 - getRandom(0,length)

       于是es6提供了一个简化语法:当需要让一个形参变成可选项,可传递实参也可以不传递的时候,es6中新语法,快速实现需求

       语法:function fn(a,b= 值){}

               1.函数的形参b可以给传递实参,也可以不传递

               2.带有默认值的形参必须在所有形参的末尾

    function getRandom(a, b= 0) { // 形参可以用默认值,可传可不传
        return Math.floor(Math.random() * Math.abs(a - b)) + Math.min(a, b)
    }
    console.log(getRandom(5,10));

    // 注意: 带有默认值的形参,必须放在所有形参的末尾
    function getRandom(a=0, b) { // a=0放前面,这样不行,输出NaN
        return Math.floor(Math.random() * Math.abs(a - b)) + Math.min(a, b)
    }

4.模板字符串

       es6提供了新的语法用于定义字符串:

                 var str= `字符`

                          1.一个字符串多行定义,在控制台就多行显示 ---- 在代码书写端怎么写的,就在控制台怎么显示

                          2.字符串内部通过${变量}可以直接解析变量,省略拼接

    // 图片路径
    var imgPath = 'a/b/c/1.jpg'
    // 以前写图片链接时的操作,拼接一大堆
    var img = '<img src="'+imgPath+'"/>'
    // 现在用`字符`
    var img=`<img src="${imgPath}">`
    console.log(img)

5.解构赋值

       解构赋值:是快速地方便的批量的把对象或者数组中的多个值赋值给多个变量

               1.对象解构:

                       (1)var {属性名, 属性名, ..} = 对象

                       (2)var {属性名: 新的变量名} = 对象

                       (3)var {属性名: {属性名}} = 对象

    var obj = {
        name:'张三',
        age:12,
        isman:'是',
        wife :{
            name:'翠花',
            age:13,
            isman:'不是'
        }
    }
    // var {name,age,isman} = obj // 1.属性名和变量名必须保持一致
    // console.log(name,age,isman)

    // var {name:a,age:b,isman:c}=obj // 2.取别名
    // console.log(a,b,c)
    // console.log(age) // 显示age未定义,取了别名后原来的名称就不能使用了

    // var {wife:{name,age}} = obj // 3.多重解构
    // console.log(name,age)

               2.数组:

                       (1)var [变量名, 变量名, ..] = 数组

                       (2)var [变量名, [变量名]] = 数组

                       (3)不想要的元素可以用下划线代替

    var arr = [
        1,
        2,
        [
            4,
            5
        ],
        3
    ]
    // var [a,b,c]=arr
    // console.log(a,b,c);

    // var [a,b,[d,e]]=arr
    // console.log(d,e)
    // console.log(a,b,d,e)

    // 现在只想要d,e ,不想要a,b - 用下划线作为变量名
    // var [_, _, [d, e]] = arr
    // console.log(d, e)

               3.最简短的交换两个变量的值 - 解构赋值:

    var a = 1
    var b = 2
    var [a, b] = [b, a]
    console.log(a, b);

6.展开合并运算/...运算

       1.展开:

                 展开运算符:...

               (1)对象展开   ---    ...对象    ---   将对象展开成多个键值对 

               (2)数组展开   ---    ...数组    ---   将数组展开成多个值 --- Math.max(...数组)

    // 对象展开
    var obj = {
        name: '隔壁老王',
        age: 56,
        isMan: true
    }
    var pbj = {
        ...obj, 
        wife: {
            name: '翠花',
            age: 13,
            isMan: false
        }
    }
    console.log(pbj);

    // 数组展开
    var arr = [1,9,5,7,3,4,6] // 想求最大值
    Math.max(...arr) // arr是数组,Math.max()括号里只能放数字,所以要展开

    var arr = [1,9,5,7,3,4,6] // 想求前三个元素的和
    function fn(a,b,c){
        console.log(a+b+c)
    }
    fn(...arr)

       2.合并:

               (1)...数组名 --- 当实参数量不固定,就将不固定数量的实参收集成一个数组

    function fn(...arr){ // 将多个值收集在一个数组中
        console.log(arr)
    }
    fn(1, 2)
    fn(1, 3, 5)
    fn(1, 9, 6, 4, 2, 8)

7.对象简写

       1.属性:

                  当属性名和值使用的变量名同名就可以简写 --- var obj = {name, age}

       2.方法:

                  当方法的值是匿名函数就可以简写 --- var obj = {eat() {}}

    var name = '张三'
    var age = 12
    var sex = '男'

    /*  想变成这样的方式
    {
        name: '张三',
        age: 12,
        sex: '男'
    } 
    */

    // 属性简写: 当对象的属性名 和对应的值所使用的的变量名 同名了,就可以简写了
    var obj = {
        'name': name, // 此处为: '属性':变量
        'age': age,
        'sex': sex
    }
    console.log(obj);

    // 怎么简写
    var obj = { 
        name, // 这叫一带二,它代表键值对
        age,
        sex
    }
    console.log(obj)


    // 方法简写: 当对象的方法的值是一个匿名函数的时候,方法可以简写
    var obj = { 
        name, 
        age,
        sex,
        eat: function(){
            console.log('吃吃吃')
        }
    }
    console.log(obj)

    // 怎么简写
    var obj = { 
        name, 
        age,
        sex,
        eat(){
            console.log('吃吃吃')
        }
    }
    console.log(obj)

8.Map

       这是一种es6新提供的一种对象数据,Map数据是一个键值对,类型是object --- 跟之前学习的object的区别是键可以是任意类型的数据

       Map和object的区别:

                object的键必须是字符串,如果给的不是字符串,会转成字符串作为对象的键;

                Map的键,可以是任意数据类型

    // 对象
    var obj = {
        name: '张三'
    }
    // // console.log( obj.toString() ); // 对象obj以字符串形式显示为[object,Object]
    var pbj = {}
    pbj[obj] = 111 // 此时obj是键,把对象obj当成对象pbj的键
    console.log(pbj); // 显示{[object,Object]:111}

       1.定义:

               (1)var m = new Map()

               (2)var m = new Map([[键, 值], [键, 值]])

       2.方法:

               (1)set:设置键值对

               (2)get:获取值

               (3)delete:删除键值对
 

               (6)keys:把所有键组合在一起

               (7)values:把所有值组合在一起

               (8)forEach:遍历

       3.属性:

               (1)has:判断有没有某个键

               (2)size:判断有几个键值对

               (3)clear:清空键值对

    // 操作方法
    var obj = {
        name: '张三'
    }
    var pbj = {}
    var m = new Map([[obj, '值'], [pbj, '值'], ['name', '如花'], ['age', '18'], ['sex', '女']])

    // 设置键值对
    m.set('name', '秋香') // 覆盖如花,说明键是唯一的
    console.log(m);

    // // 获取值
    var age = m.get('age')
    console.log(age)

    // 删除键值对
    m.delete('sex')
    console.log(m)

    // 把所有键组合在一起
    console.log(m.keys());

    // 把所有值组合在一起
    console.log(m.values());

    // 遍历
    // 值
    m.forEach(v => {
        console.log(v);
    })
    // 键值对
    m.forEach((v, key) => {
        console.log(v, key);
    })

    // 判断有没有某个键
    console.log(m.has('wife'))

    // 判断有几个键值对
    console.log(m.size);

    // 清除键值对
    m.clear()
    console.log(m);

9.Set

           es6提供的一种新的对象类型的数据 - Set

           官方解释:Set是所有键的集合

           我们理解的:set是新型的数组,数组中不能有重复的元素,重复也只显示一个,类型是object,是没有重复值的集合

       1.定义:

               (1)var s = new Set()

               (2)var s = new Set([多个值]) --- 多个值可以有重复,但只接受一个

    var s = new Set([1,2,3,4,4,4,4,4,4,4,4]) // 重复也只显示一次
    console.log(s);

       2.方法:

               (1)add:添加一个元素

               (2)delete:删除一个元素

               (3)clear:清空元素

               (4)forEach:遍历

       3.属性:

               (1)size:获取键值对个数

       4.数组去重应用:

               (1)[...new Set(数组)]

    // 利用set可以进行数组去重
    var arr = [1,1,2,2,3,3,4]
    var s = new Set(arr)
    var brr = [...s] // 把s展开成一个多的值,放在brr里
    console.log(s);
    console.log(brr)
    console.log([...new Set[arr]]) // 连在一起输出

10.for...of

       es6提供的一种新的遍历语法

                 1.可以遍历数组/字符串/set/map,不能遍历对象

                 2.只遍历值,不遍历下标

    // 数组
    var arr = ['张三', '宛四', '宋五', '许六']
    for(var a of arr){
        console.log(a);
    }

    // 字符串
    var brr = 'abcdefg'
    for(var b of brr){
        console.log(b);
    }

    // 对象 - 不能遍历对象
    // var crr = {
    //     name:'龙崽'
    // }
    // for(var c of crr){
    //     console.log(c);
    // }

    // Map
    var map = new Map([['a',1],['b',2]])
    for(var mappp of map){
        console.log(mappp);
    }

    // Set
    var set = new Set([1,2,3,4,4,4,4,4,4,4,4])
    for(var settt of set){
        console.log(settt);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值