This关键字与ES6新特性

60 阅读9分钟

函数

  1. 函数定义方式:声明式,赋值式

  2. 自调用函数

    //函数定义和调用写在一块
    
    (function() {
        // 函数体
        console.log('自调用函数')
    })()
    
    //封装代码
    //封装私有变量,独立于全局变量
    
       
    
  3. arguments

在函数内部自带的变量,表示所有实参的集合,是伪数组

function fn0{
    console.log(arguments)
}

fn(10)

length属性实参个数

this关键字

  1. this表示当前对象,在同场景下this表示不同的对象

  2. 函数内部的this指向谁,取决于函数的调用方式

  • 全局定义的函数直接调用,this => window

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

    //此时this指向window

  • 对象内部的方法调用,this =>调用者

    var obj = {
        fn: function() {
            console.log(this)
        }
    }
    obj.fn()
    //此时this指向obj
    
  • 定时器的处理函数,this => window

    setTimeout(function() {
        console.log(this)
    }, 0)
    //此时定时器处理函数里面的this指向window
    
  • 事件处理函数,this =>事件源

    div.onclick = function () {
        console.log(this)
    }
    //当你点击div 的时候,this指向div
    
  • 自调用函数,this => window

    (function () {
        console.log(this)
    })()
    (function ) {
        console.log('自调用函数')
    })()
    //此时this指向window
    
  1. 重点:函数内部的 this只和函数的调用方式有关系,和函数的定义方式没有关系

call 和 apply和 bind

  1. call
  • call方法是附加在函数调用后面使用,可以忽略函数本身的 this 指向

  • 语法:函数名.call(要改变的this指向,要给函数传递的参数1,要给函数传递的参数2,...)

    var obj = { name: 'Jack’}
    function fn(a,b){
        console.log(this)
        console.log(a)
        console.log(b)
    }
    fn(12)
    fn.call(obj,12)
    
    • fn()的时候,函数内部的this指向window
    • fn.call(obj,1,2)的时候,函数内部的 this 就指向了obj这个对象
    • 使用call方法的时候,会立即执行函数,第一个参数是你要改变的函数内部的 this指向·第二个参数开始,依次是向函数传递参数
  1. apply
  • apply方法是附加在函数调用后面使用,可以忽略函数本身的this指向

  • 语法:函数名.apply(要改变的 this 指向,[要给函数传递的参数1,要给函数传递的参数2, ...])

    var obj = { name: "Jack”}
    function fn(a, b){
        console.log(this)
        console.log(a)
        console.log(b)
    }
    fn(1,2)
    fn.call(obj,[1,2])
    
    • fn()的时候,函数内部的 this指向window
    • fn.apply(obj,[1,2])的时候,函数内部的this 就指向了obj这个对象
    • 使用apply方法的时候,会立即执行函数,第一个参数是你要改变的函数内部的this指向,第二个参数是一个数组,数组里面的每一项依次是向函数传递的参数
  1. bind
  • bind方法是附加在函数调用后面使用,可以忽略函数本身的this指向

  • 和call / apply有一些不一样,就是不会立即执行函数,而是返回一个已经改变了this指向

  • 函数语法:var newFn =函数名.bind(要改变的 this 指向);newFn(传递参数)

    var obj = { name: "3ack’}
    function fn(a, b){
        console.log(this)
        console.log(a)
        console.log(b)
    }
    fn(12)
    var newFn = fn.bind(obj)newFn(12)
    
    • bind调用的时候,不会执行fn这个函数,而是返回一个新的函数
    • 这个新的函数就是一个改变了this指向以后的fn函数
    • fn(1,2)的时候this指向window
    • newFn(1,2)的时候执行的是一个和fn一摸一样的函数,只不过里面的this指向改成了obj

ES6新特性

1. let和const 关键字

  • let和const不允许重复声明变量

    //使用var的时候重复声明变量是没问题的,只不过就是后面会把前面覆盖掉
    var num = 100
    var num = 200
    
    //使用let重复声明变量的时候就会报错了
    let num = 100
    let num = 200 //这里就会报错了
    
    //使用const重复声明变量的时候就会报错
    const num = 100
    const num = 200 //这里就会报错了
    
  • 没有变量提升

    //因为预解析((变量提升)的原因,在前面是有这个变量的,只不过没有赋值
    console.log(num)  // undefined
    var num = 100
    
    //因为let不会进行预解析((变量提升),所以直接报错了
    console.log(num) // undefined
    let num = 100
    
    //因为const不会进行预解析(变量提升),所以直接报错了
    console.log(num) // undefined
    const num = 100
    
  • let和const声明的变量会被所有代码块限制作用范围

     //var声明的变量只有函数能限制其作用域,其她的不能限制
     if (true){
         var num = 100
     }
         console.log(num)  // 100
    
    // let声明的变量,除了函数可以限制,所有的代码快都可以限制其作用域《if/while/forl . ..)
    if(true){
        let num - 100
        console.log(num) // 100
    }
    console.log(num) //报错
    
    // const声明的变量。除了函数可以限制,所有的代码块都可以限制其作用域(if/while/for/...)
    if (true){
        const num = 100
        console.log(num) // 100
    }
    console.log(num)报错
    
  • let和const 的区别

let声明的变量的值可以改变,const声明的变量的值不可以改变

let num = 100
num = 200
console.log(num) //200

const num = 100
num = 200//这里就会报错了,因为 const 声明的变量值不可以改变(我们也叫做常量)

let声明的时候可以不赋值,const 声明的时候必须赋值

let num
num = 100
console.log(num) // 100

const num //这里就会报错了,因为const声明的时候必须赋值

2. 箭头函数

  • 箭头函数是ES6里面一个简写函数的语法方式

  • 重点:箭头函数只能简写函数表达式,不能简写声明式函数

    function fn() {} //不能简写
    const fun = function() {}  //可以简写
    const obj = {
        fn: function() {}  //可以简写
    }
    
  • 语法:(函数的行参) =>{函数体内要执行的代码}

    const fn = function(a, b) {
        console.log(a)
        console.log(b)
    }
    //可以使用箭头函数写成
    const fun = (a, b) => {
        console.log(a)
        console.log(b)
    }
    
    const obj = {
        fn: function(a, b) {
            console.log(a)
            console.log(b)
        }
    }
    //可以使用箭头函数写成
    const obj2 = {
        fn: (a, b) => {
            console.log(a)
            console.log(b)
        }
    }
    
  • 箭头函数的特殊性

箭头函数教内部没有this,箭头函数的this是上下文的this

//在箭头函数定义的位置往上数,这一行是可以打印出this 的
//因为这里的this是window
//所以箭头函数内部的 this就是window
const obj = {
    fn: function() {
        console.log(this)
    },
//这个位置是箭头函数的上一行,但是不能打印出this
    fun: => {
        //箭头函数内部的this 是书写箭头函数的上一行一个可以打印出 this的位置
        console.log(this)
    }
}
obj.fn()
obj.fun()

国数的行参只有一个的时候可以不写()其余情况必须写

const obj = {
    fn: () => {
        console.log('没有参数,必须写小括号')
    },
    fn2: a => {
        console.log("一个行参,可以不写小括号')
    },
    fn3: (a, b) => {
        console.log("两个或两个以上参数,必须写小括号")
    }
}

函数体只有一行代码的时候,可以不写{},并且会自动return

const obj = {
    fn: a => {
        return a + 10
    },
    fun: a => a + 10
}
    console.log(fn( 10)) // 20
    console.log(fun(10)) // 20

3. 函数传递参数的时候的默认值

我们在定义函数的时候,有的时候需要—个默认值出现,就是当我不传递参数的时候,使用默认值,传递参数了就使用传递的参数

function fn(a){
    a = a || 10
    console.log(a)
}
fn()//不传递参数的时候,函数内部的a就是10
fn(20)//传递了参数20的时候,函数内部的a就是20

在ES6中我们可以直接把默认值写在函数的行参位置

function fn(a = 10){
    console.log(a)
}
fn()//不传递参数的时候。函数内部的a就是10
fn(20)//传递了参数20的时候。函数内部的a就是20

这个默认值的方式箭头函数也可以使用

const fn = (a = 10) => {
    console.log(a)
}
fn()//不传递参数的时候,函数内部的a就是10
fn(20)//传递了参数20的时候,函数内部的a就是28

注意:箭头函数如果你需要使用默认值的话,那么一个参数的时候也需要写О

4. 解构赋值

就是快速的从对象或者数组中取出成员的一个语法方式

  • 解构对象

快速的从对象中获取成员

  // ES5的方法向得到对象中的成员
  const obj = {
      name: "ack ",
      age: 18,
      gender:"男”
  }
  let name = obj.name
  let age = obj.age
  let gender = obj.gender

  //解构赋值的方式从对象中获取成员
  const obj = {
      name: "ack ",
      age: 18,
      gender:"男" 
  }
  //前面的表示我要从obj这个对象中获取成员了 
  // name age gender都得是obj中有的成员
  // obj必须是一个对象
  let { name,age,gender } = obj
  • 解构数组

快速的从数组中获取成员

//ES5的方式从数组中获取成员
const arr = ['ack', 'Rose', "Tom']
let a = arr[0]
let b = arr[1]
let c = arr[2]

//使用解构赋值的方式从数组中获取成员
const arr = ['ack', 'Rose', ;Tom']
//前面的[]表示要从arr这个数组中获取成员了
// a b c 分别对应这数组中的索引0 1 2
// arr必须是一个数组
let [a,b,c] = arr

注意:是专门解构对象使用的]是专门解构数组使用的不能混用

  • 交换变量

    <script>
        function test1() {
        *
            利用解构交换变量值
        */ 
        let a = 3
        let b = 5//这里必须加结束语句结束符
        //利用解构交换变量值
        [a, b] =[b,a]
    
        console.log('a ', a, 'b ', b);
    }
    test1()
    
  • 解析一个从函数中返回的数组

    function func() {
        return [2,3];
    }
    var a, b;
    [a, b] = func();
    consoie. iog(a, b);
    
    undefined
    2  3
    

5. 展开运算符

ES6里面号新添加了一个运算符...,叫做展开运算符

  • 展开数组

    let arr = [12345]
    console.log( . ..arr) // 1 2 3 4 5
    
  • 合并数组

    let arr = [1234]
    let arr2 = [...arr,5]
    console.log(arr2)
    
  • 合并对象

    let obj = {
        name : "oack ',
        age: 18
    }
    let obj2 = {
        ...obj,
        gender:'男'
    }
    console.log(obj2)
    
  • 函数传递参数

    let arr = [1,2,3]
    function fn(a,b,c) {
    console.log(a)
    console.log(b)
    console.log(c)
    }
    fn(...arr)
    //等价于fn(1,2,3)
    

6. 对象字面量简化写法

当属性与值的变量同名时,可以只写一个

const name = 'ane ';
const age = 20

//es6
const person = {
    name,
    age
}
//es5
var person = {
    name: name,
    age: age
};

7. Symbol简单数据类型

  • ES6引入Symbol的原因:ES5的对象属性名都是字符串,很容易造成属性名冲突。比如,使用了一个他人提供的对象,想为这个对象添加新的方法,新方法的名字就有可能与现有方法产生冲突。如果有—种机制,保证每个属性的名字都是独一无二的,这样就从根本上防止了属性名冲突。

  • 用法:直接使用Symbol()创建新的symbol类型,并用一个可选的字符串作为其描述.

    let sym1 = symbol();
    let sym2 = Symbol( 'foo');
    let sym3 = Symbol( 'foo');
    //上面的代码创建了三个新的symbol类型。
    

注意:Symbol函数的参数只是表示对当前Symbol值的描述,因此相同参数的Symbol函数的返回值是不相等的。

  • 类型检测

    let symbol = Symbol("test symbol");
    console.log(typeof symbol);// "symbol"
    

8. Map和Set复杂数据类型

Map和Set是ES6新增的两个数据类型都是属于内置构造函数,使用new的方式来实例化使用

Set

是一个数据集合,可以在new的时候直接向内部添加数据

const s = new Set
oconsole.log(s)
//实例化的时候直接添加数据要以数组的形式添加
const s = new Set([1, 2, 3, {}, function (){}, true, "hello"])
console.log(s)

看上去是一个类似数组的数据结构,但是不是,就是Set 数据结构

  • 常用方法和属性

(1)size:用来获取该数据结构中有多少数据的

const s = new Set([123,{}, function () {}, true'hello'])
console.log(s.size) // 7

(2)add:用来向该数据类型中追加数据

const s = new Set()
s.add(0)
s.add({})
s.add(function () {})
console.log(s.size) // 3

(3)delete:是删除该数据结构中的某一个数据

const s = new Set()
s.add(0)
s.add({})
s.add(function () {})

s.delete(0)

console.log(s.size) //2

(4)clear:清空数据结构中的所有数据

const s = new Set()
s.add(0)
s.add({})
s.add(function () {})

s.clear(0)

console.log(s.size) // e

(5)forEach:用来遍历Set 数据结构的方法

const s = new Set
(s.add(0)
s.add({})
s.add(function () {})

s.forEach(item => {
    console.log(item) // 0 {} function () {}
})

(6)获取Set结构里面的数据需要借助一个...展开运算符

//把他里面的东西都放到一个数组里面去,然后再获取
const s = new Set([123456])
const a = [...s]
console.log(a)  // (6)[1,2,3,4,5,6]

console.log(a[0])// 1
console.log([...s][0])// 1
  • Set数据类型特点

Set不允许存储重复的数据

const s = new Set( [123])
s.add(1) //此时size是3
s.add(2) //此时size是3
s.add(3) //此时size是3
s.add(4) //此时size是4
  • 数组去重

    let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
    let set = new Set(array);
    console.log(set)
    //=> Set {1,2,3,4,5}
    

Map 是一个数据集合,是一个很类似于对象的数据集合

const m = new Map()
console.log(m)

(1)值 = 值 的数据类型

const m = new Map([[{},{}],[function () {},function () {}],[true,1]])
console.log(m)

/*
    Map(3) {{...} => {...}, f => f, true => 1}
        size: (...)
        _proto_: Map
        [[Entries]]: Array(3)
        0: {object => objecty
            key : {}
            value: {}
        1: {function () {} => function () {}}
            key : f {}
            value: f {}
        2: {true => 1}
            key: true
            value: 1
        length: 3
*/

(2)常用方法和属性

  • size :用来获取该数据类型中数据的个数

    const m = new Map([[00],[function () {},function () {}],[true1]])
    console.log(m.size) // 3
    
  • delete :用来删除该数据集合中的某—个数据

    const m = new Map([[f,f],[function () {},function () {}],[true1]])
    m.delete(true)
    
    console.log(m.size)//2
    
  • set:用来向该数据集合中添加数据使用

    const m = new Map()
    m.set({ name: 'jack' }, { age: 18 })
    console.log(m.size) // 1
    
  • get :用来获取该数据集合中的某—个数据

    const m = new Map()
    
    m.set({ name : "Jack"}, { age: 18 })
    m.set(truefunction () {})
    console.log(m.get(true)) // function () {}
    
  • clear :清除数据集合中的所有数据

    const m = new Map()
    m.set({ name : "Jack" }, { age: 18 })
    m.set(truefunction () {})
    m.clear()
    console.log(m.size) // 0
    
  • has :用来判断数据集合中是否存在菜一个数据

    const m =new Map()
    m.set{ name: 'Jack'} , { age: 18 })
    m.set(true,function () {})
    console.log(m.has(true)) // true
    

9. for ... of

for-of可以遍历数组,字符串和Map,不能遍历对象遍历数组,访问数组元素

遍历字符串,访问字符串字符元素

let arr = [10,20,30]
let str = 'hello'
let map = new Map([["姓名""小王"],["年龄" , "23"]]) //for-of遍历数组,获取数组元素
for(let v of arr){
    console.log(v);
}
//for-of 遍历字符串,获取字符元素
for(let v of str){
    console.log(v);
}
//for-of遍历Map集合
for(let v of map){
    console.log(v);
}

10. 模块化语法import / export

  • 模块化的理解

什么是模块?

将一个复杂的程序依据一定的规则封装成几个块,块的内部数据是私有的,只是向外部暴露一些接口,与外部其它模块通信。

前端模块化开发中:一个js文件就是一个模块,在js文件模块中定义的数据是私有的,可以向外部暴露数据和方法,其它js文件模块可以引入暴露的方法数据进行使用。

QQ截图20220902220626.png

  • Es6模块化

    • Es6模块化语法

    export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

    /定义模块math.js/ var basicNum = 0; var add = function (a,b){ return a + b; }; export { basicNum,add };

      /**引用模块**/
      import { basicNum,add } from './math ';
      function test(ele) {
          ele.textcontent = add(99 + basicNum) ;
      }
    
    • 用到export default命令,为模块指定默认输出

      // export-default.js
      export default function () {
          console.log( 'foo ');
      }
      
      // import-default.js
      import customName from './export-default ';
      customName(); // 'foo'
      

    模块默认输出,其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。

    <script type = "module">
        import {max} from './js/util.js'
        import min from './js/index.js'
        import './js/main.js'
        let m = min((20,34)
        document.querySelector('div').innerHTML = m
    </script>
    

js错误处理机制

JavaScript 解析或运行时,一旦发生错误,引擎就会抛出一个错误对象Error

1.常用错误对象

  • SyntaxError 对象

SyntaxError对象是解析代码时发生的语法错误。

//变量名错误
var 1a;
// Uncaught SyntaxError: Invalid or Unexpected token

//缺少括号
console.log 'hello');
// Uncaught syntaxError: Unexpected string
  • ReferenceError 对像

ReferenceError对象是引用一个不存在的变量时发生的错误。

//使用一个不存在的变量
unknownVariable
// Uncaught ReferenceError: unknownVariable is not defined

console.log(a) 
//Uncaught ReferenceError: a is not defined
  • TypeError对象

TypeError对象是变量或参数不是预期类型时发生的错误。Uncaught TypeError: Cannot read property

  • RangeError 对象

RangeError对象是一个值超出有效范围时发生的错误。主要有几种情况,一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值。

//数组长度不得为负数
new Array(-1)
// Uncaught RangeError: Invalid array length

2.手动生成错误对象

var err1 =new Error('出错了! ');
var err2 = new RangeError('出错了,变量超出有效范围! ')
var err3 = new TypeError('出错了,变量类型无效! ');

err1.message //"出错了!"
err2.message //"出错了,变量超出有效范围!"
err3.message //"出错了,变量类型无效!"

3.throw语句

throw语句的作用是手动中断程序执行,抛出一个错误。

if (x < e){
    throw new Error( 'x 必须为正数');
}
//Uncaught ReferenceError: x is not defined

对于JavaScript引擎来说,遇到throw语句,程序就中止了。引擎会接收到throw抛出的信息,

4.try...catch结构

一旦发生错误,程序就中止执行了。JavaScript提供了try...catch结构,允许对错误进行处理,选择是否往下执行。

try {
    throw new Error('出错了!");
} catch (e) {
    console.log(e.name + ": " + e.message);
    console.log(e.stack);
}

5.finally代码块

try...catch结构允许在最后添加一个finally代码块,表示不管是否出现错误,都必需在最后运行的语句。

try {
    throw new Error('出错了......);
    console.log(此行不会执行");
} finally {
    console.log('完成清理工作');
}