JavaScript基础笔记整理(四)

1,201 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情

js重点知识

this的三种指向

this指向取决于函数的调用 , 函数有三种调用方式:

环境对象this : 谁'调用'我,我就指向谁

(1)普通函数 : 函数名() this指向window

(2)对象方法 : 对象名 . 方法名() this指向对象

(3)构造函数 : new 函数名() this指向new创建的实例对象

小技巧 : 没有new是window , 有new是实例对象 , 有点是点左边的对象

函数上下文模式

默认情况下 , 函数内部的this是无法被修改的

函数上下文作用 : 函数上下文模式 , 可以修改函数作用域内部this指向

语法 : 有3种写法call() apply() bind() , 它们定义在Function构造函数的原型中 , 作用都是修改this指向 , 应用场景不同

call() apply() bind()     //动态修改函数中的this指向

(1)函数名 . call (修改的this , agr1..., agr2...)

function fn(a, b) {
            console.log(a + b) //50
            console.log(this) //object
        }
fn.call({name:小明},[20,30])  

call 的应用场景 : 万能数据类型检测: Object . prototype . tostring . call(数据)

万能数据类型检测原理:

a. Object .prototype . tostring()内部会返回this的数据类型 , 得到固定格式字符串 '[object 数据类型]'

b . 使用object原型中的tostring()要想得到数据类型 , 只需要把this修改成你想要检测的对象

typeof 数据 : null和数组无法检测,结果都是 'object'

(2)函数名 . apply (修改的this , 数组或者伪数组)

apply会自动帮你遍历数组 , 然后按照顺序逐一传参

function fn(a, b) {
            console.log(a + b) //50
            console.log(this) //object
        }
fn.apply({name:小明},[20,30])  // 

apply的应用场景一 : 伪数组转真数组

//伪数组 本质是 :  对象
   let obj = {
       0:20,
       1:66,
       2:88,
       3:90,
       length:4
   }  
//伪数组转真数组
   let arr = []
//借助 apply自动遍历数组/伪数组 逐一传参特点
arr.push.apply( arr,obj )
   console.log(arr)  //[20,66,88,90]//伪数组转真数组 :  Array.from( 伪数组 )
   console.log( Array.from(obj) )

ES6新语法:伪数组转真数组 Array.from(伪数组)

apply的应用场景二 : 求数组的最大值

const arr = [10,20,30]
求最大值: Math.max()
const max1 =Math.max.apply(Math,arr)
console.log(max1) //30
...展开运算符求最大值
const max = Math.max(...arr)
console.log(max) //30

ES6新语法:求数组的最大值 Math.max(...arr) ...展开运算符

(3)函数名 . bind(修改后的this)

bind不会立即执行函数 , 而是返回一个修改this之后的新函数

function fn(a,b){
            console.log( a + b )
            console.log( this )
        }
const newFn = fn.bind({name:小明})
newFn(10,20) //30 Object

(4)call() apply() bind()三者区别

相同点 : 作用一致,修改函数this指向

不同点 : a . 传参方式不同 : call是按照顺序传参, apply是数组/伪数组传参

b . 执行机制不同:call和apply会立即执行函数,而bind不会立即执行而是得到修改this的新函数

闭包(重点)

(1)闭包closure是什么?

闭包是一个访问其他函数内部变量的函数

闭包 = 函数 + 上下文引用

(2)闭包的作用 : 解决变量污染 , 让变量被函数保护起来

在实际开发中 , 闭包是一种现象,一般出现在回调函数中

function fn() {
  let count = 0
​
  setInterval(function () {
    console.log(count++)
  }, 1000)
}
代码改写 add + count 构成了闭包
function fn() {
  let count = 0
  function add() {
    console.log(count++)
  }
  
  setInterval(add, 1000)
}

递归

(1)递归函数 : 在函数中调用自己

a. 递归类似于循环一定要有结束条件,否则会导致死循环

b. 能用递归函数实现的需求,就一定可以用循环调用函数来解决,只是代码简洁与性能不同而已

let i = 1
function fn(){
  console.log('123')  //打印3次123
  i++
  if(i<=3){
    fn()
  }
}
fn()

(2)递归应用 :

a . 浅拷贝和深拷贝

b . 遍历DOM树

浅拷贝和深拷贝

浅拷贝 : 拷贝地址 , 修改拷贝后的数据对原结构会有影响

深拷贝 : 拷贝数据 , 修改拷贝后的数据对元数据没有影响

深拷贝两种方式

(1) josn方式 : let newObj = JSON.parse( JOSN.stringify(js对象))

(2)递归方式实现深拷贝

let obj = {
                name: '张三',
                age: 20,
                sex: '男',
                hobby: ['吃饭', '睡觉', '学习'],
                student: {
                    name: "班长",
                    score: 90
                }
            }
            // 深拷贝  递归方式
            // (1)创建一个空对象
        let newObj = {}
            // (2)调用函数拷贝
            // 封装函数
        function kaobei(newObj, obj) {
            // 遍历对象,把obj里面的数据拷贝给newObj
            for (let key in obj) {
                // 判断是不是数组,如果是数组就需要继续遍历
                if (obj[key] instanceof Array) {
                    newObj[key] = [] //是数组就先声明一个空数组
                        // 递归遍历数组 重新传参
                    kaobei(newObj[key], obj[key])
                } else if (obj[key] instanceof Object) {
                    newObj[key] = {} //是数组就先声明一个空数组
                        // 递归遍历数组 重新传参
                    kaobei(newObj[key], obj[key])
                } else {
                    newObj[key] = obj[key]
                }
            }
        }
        kaobei(newObj, obj)
        console.log(newObj, obj);
        newObj.hobby[0] = '游戏'
        newObj.student.name = '111'

ES6新语法

解构赋值语法

对象解构赋值

其实就是变量赋值的简写

取出对象的属性 赋值给 变量

let obj = {
            name: '张三',
            age: 20,
            sex: '男'
        }
//解构变量赋值
let {name,age,sex} = obj

数组解构赋值

取出数组的元素 赋值给变量

let arr = [10, 20, 30]
//解构数组赋值
let [n1,n2,n3] = arr

函数参数解构

当函数参数是对象类型,就可以对形参进行解构

ES6 :函数传参
function fn1({name,age,sex}){
           //声明三个变量接收对象的参数值
           console.log(name,age,sex);
       };
​
       fn1({
           name:'小明',
           age:32,
           sex:'男'
       })

箭头函数

  1. 什么事箭头函数?

箭头函数相当于function函数的简写 , 把function改成=> , 然后把形参()写在箭头的左边

  1. 语法:

    箭头函数
    let fn = (a,b)=>{
              console.log(a+b)
            }
    ​
            fn(10,20)
    (1)如果箭头函数形参只有一个,则可以省略形参小括号
            let fn1 = a => {
              return a*2
            }
    ​
            let res1 = fn1(55)
            console.log(res1)
    (2)如果函数体只有一行代码,则可以省略大括号(此时必须要省略return)
    let fn2 = a => a*2
          
            let res2 = fn2(55)
            console.log(res2)
    

    箭头函数语法注意点:

    (1)如果箭头函数形参只有一个,则可以省略形参小括号

    (2)如果函数体只有一行,则可以省略大括号{}, 此时 必须要省略return

箭头函数this指向

  1. function函数this有三种指向 :

    普通函数: 函数名() this->window

    对象方法: 对象.方法名() this->对象

    构造函数: new 函数名() this->new创建的实例

  2. 箭头函数this : 箭头函数没有this

    箭头函数中使用this, 本质是通过作用域链找上一级作用域的this

  3. 箭头函数没有this,对箭头函数影响

    (1)箭头函数不能作为构造函数

    (2)箭头函数不能修改this

    (3)事件处理函数一般不用箭头函数

  4. 箭头函数面试题

        let obj = {
          name: 'ikun',
          eat() {
            //1级  this : function函数指向对象obj
            function fn1() {
              //function函数this取决于调用   函数名()  this->window
              console.log(this)//window  
            }
            fn1()
    ​
            let fn2 = () => {
              //2级
              //this:箭头函数,访问上级1级this
              console.log(this)//obj 
            }
            fn2()
          },
          learn: () => {
            //1级 this箭头函数,访问上级 window
            function fn1() {
              //function函数this取决于调用   函数名()  this->window
              console.log(this)//window
            }
            fn1()
    ​
            let fn2 = () => {
              //2级  this箭头,访问上级1级的this -> window
              console.log(this)//window  
            }
            fn2()
          }
        } 
    ​
        obj.eat()
        obj.learn()
    

展开运算符 ...

  1. 定义:相当于遍历 数组/对象的 简写

  2. 应用 :

    (1)连接数组

    let arr1 = [10,20,30]
    let arr2 = [40,50,60]
    let arr3 = [70,80,90]
    连接数组
    arr1.push(...arr2,...arr3)
    consoloe.log(arr1) //[10,20,30,40,50,60,70,80,90]
    

    (2)求数组最大值

    let arr = [20,50,66,80,100,40]
    求最大值
    let max = Math.max(...arr)
        console.log(max)  //100
    

数据类型Set

  1. 数据类型Set是什么?

    它是一个集合 , 相当于数组,唯一的区别是 Set不能存储重复元素

  2. 应用场景 : 数组去重

    数组去重固定语法
    let newArr = [ ...new Set(数组) ]
    let arr = [10, 10, 20, 30, 20, 30, 50, 60, 70, 50]
    //需求:除去数组中重复的元素
    let newArr = [...new Set(arr)]
    console.log(newArr)  //[10, 20, 30, 50, 60, 70]
    

image.png