Javascript ES6 part1

eve2333 发布于 2024-10-25 98 次阅读


听了介绍感觉就是把js在oop的使用

作用域

作用域(scope)规定了变量能够被访问的“范围”,离开了这个“范围”变量便不能被访问,

作用域分为: 局部作用域、 全局作用域

1. 函数作用域:

在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。

1. 函数内部声明的变量,在函数外部无法被访问
2. 函数的参数也是函数内部的局部变量
3. 不同函数内部声明的变量无法互相访问
4. 函数执行完毕后,函数内部的变量实际被清空了

2. 块作用域:

在JavaScript中使用{ }包裹的代码称为代码块,代码块内部声明的变量外部将 有可能 无法被访问。

1. let 声明的变量会产生块作用域,var 不会产生块作用域
2. const 声明的常量也会产生块作用域
3. 不同代码块之间的变量无法互相访问
4. 推荐使用 let 或 const

1.2 全局作用域

<script> 标签  和 .js 文件 的【最外层】就是全局作用域,在此声明的变量在函数内部也可以被访问。 全局作用域中声明的变量,任何其它作用域都可以被访问。 
注意:
1. 为 window 对象动态添加的属性默认也是全局的,不推荐!
2. 函数中未使用任何关键字声明的变量为全局变量,不推荐!!!
3. 尽可能少的声明全局变量,防止全局变量被污染
JavaScript 中的作用域是程序被执行时的底层机制,了解这一机制有助于规范代码书写习惯,避免因作用域导致的语法错误。

1.3 作用域链

作用域链本质上是底层的 变量查找机制 。
在函数被执行时,会 优先查找当前 函数作用域中查找变量。如果当前作用域查找不到则会依次 逐级查找父级作用域 直到全局作用域。

1. 嵌套关系的作用域串联起来形成了作用域链
2. 相同作用域链中按着 从小到大 的规则查找变量
3. 子作用域能够访问父作用域,父级作用域无法访问子级作用域

垃圾回收机制

2.内存的生命周期
JS环境中分配的内存, 一般有如下生命周期:
1. 内存分配 :当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
2. 内存使用 :即读写内存,也就是使用变量、函数等
3. 内存回收 :使用完毕,由垃圾回收自动回收不再使用的内存
 说明:全局变量一般不会回收(关闭页面回收); 一般情况下局部变量的值不用了, 会被自动回收
————————————————

但如果不了解JS的内存管理机制,我们同样非常容易成内存泄漏(内存无法被回收)的情况。
不再用到的内存,没有及时释放, 就叫做 内存泄漏。

和c/cpp相同,栈和堆

浅拷贝和深拷贝

引用计数

标记清除

闭包closure

概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域
简单理解: 闭包 =  内层函数 + 外层函数的变量
闭包作用: 封闭数据,提供操作,外部也可以访问函数内部的变量

    // 简单的写法
    function outer() {
      let a = 10
      function fn() {
        console.log(a)
      }
      fn()
    }
    outer()===fn===function fn(){}

 是外部需要调用内部的函数,而不是获取这个函数的值

 实现数据的私有,非常好闭包,class private:

 内存泄漏的可能

变量提升

变量提升是 JavaScript 中比较“奇怪”的现象,它允许在变量声明之前即被访问(仅存在于  var  声明变量)
注意:
1. 变量在未声明即被访问时会报语法错误
2. 变量在var声明之前即被访问,变量的值为 undefined
3. let/const 声明的变量不存在变量提升
4. 变量提升出现在相同作用域当中
5. 实际开发中推荐先声明再访问变量
说明:
JS初学者经常花很多时间才能习惯变量提升,还经常出现一些意想不到的bug,正因为如此,ES6 引入了块级作用域,用let 或者 const声明变量,让代码写法更加规范和人性化。
变量提升的流程:
1. 先把var 变量提升到当前作用域于最前面
2. 只提升变量声明, 不提升变量赋值
3. 然后依次执行代码
不建议使用var声明

 underfinedworld!

函数进阶

函数提升与变量提升比较类似,是指函数在声明之前即可被调用。

动态参数 

  <script>
    function getSum() {
      // arguments 动态参数 只存在于 函数里面
      // 是伪数组 里面存储的是传递过来的实参
      // console.log(arguments)  [2,3,4][1, 2, 3, 4, 2, 2, 3, 4]
      let sum = 0
      for (let i = 0; i < arguments.length; i++) {
        sum += arguments[i]
      }
      console.log(sum)
    }
    getSum(2, 3, 4)
    getSum(1, 2, 3, 4, 2, 2, 3, 4)
  </script>

1. arguments 是一个 伪数组 ,只存在于函数中
2. arguments 的作用是 动态获取函数的实参

剩余参数

剩余参数允许我们将一个不定数量的参数表示为一个数组

剩余参数主要的使用场景: 用于获取多余的实参

  <script>
    function getSum(...arr) {
      console.log(arr)  // 使用的时候不需要写 ...
    }
    getSum(2, 3)  // [2,3]
    getSum(1, 2, 3, 4, 5)  // [1,2,3,4,5]
  </script>
  <script>
    function getSum(a, b, ...arr) {
      console.log(arr)  // 使用的时候不需要写 ...
    }
    getSum(2, 3)  // []
    getSum(1, 2, 3, 4, 5)  // [3,4,5]
  </script>

1. ... 是语法符号,置于最末函数形参之前,用于获取 多余 的实参
2. 借助 ... 获取的剩余实参,是个 真数组
剩余参数和动态参数区别: 动态参数是伪数组,剩余参数是真数组
开发中,还是提倡多使用 剩余参数

展开运算符

展开运算符(…),将一个数组进行展开,不会修改原数组

典型运用场景: 求数组最大值(最小值)、合并数组等

对于求最大值,有Math.max()这一方法,但是只是用于string求max,对于数组无法识别,因此用展开运算符

const arr=[1,2,1,5,1,1,2,6,5,9]
console.log(...arr)
console.log(Math.max(...arr))//9

console.log(Math.min(...arr))//1

log括号内可以打印多个参数,用逗号隔开,打印结果就是多个参数是在控制台用空格隔开 

对于合并数组,

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

箭头函数

引入箭头函数的目的是更简短的函数和不用this,更实用于需要匿名函数的地方

基本语法
const fn=()=>{
    console.log(123)
}
fn()
//123


const fn=(x)=>{
    console.log(x)
}
fn(1)
只有一个形参可以省略小括号
const fn= x =>{
    console.log(x)
}
fn(1)

只要一行代码可以省略大括号
const fn = x => console.log(x)
fn(1)

只有一行代码可以省略return
const fn=x=>x+x
console.log(fn(1))

const fn=(x,y)=>x+y
console.log(fn(1,2))

加括号的函数体返回对象字面量,加:
const fn =(uname)=>({name:uname})
console.log(fn('kobe'))
直接返回对象

箭头函数属于表达式函数,因此不存在函数提升 

1. 普通函数有arguments 动态参数
2. 箭头函数 没有 arguments 动态参数,但是 有剩余参数 ..args

  <script>
    // 1. 利用箭头函数来求和
    const getSum = (...arr) => {
      let sum = 0
      for (let i = 0; i < arr.length; i++) {
        sum += arr[i]
      }
      return sum
    }
    const result = getSum(2, 3, 4)
    console.log(result) // 9
  </script>

this指向问题

  <script>
    // 以前this的指向:  谁调用的这个函数,this 就指向谁
    // console.log(this)  // window
    // // 普通函数
    // function fn() {
    //   console.log(this)  // window
    // }
    // window.fn()
    // // 对象方法里面的this
    // const obj = {
    //   name: 'andy',
    //   sayHi: function () {
    //     console.log(this)  // obj
    //   }
    // }
    // obj.sayHi()
 
    // 2. 箭头函数的this  是上一层作用域的this 指向
    // const fn = () => {
    //   console.log(this)  // window
    // }
    // fn()
    // 对象方法箭头函数 this

    // const obj = {
    //   uname: 'pink老师',
    //   sayHi: () => {
    //     console.log(this)  // this 指向谁? window
//因为箭头函数没有this 是从当前作用域的上一层作用域this 的指向 sayHi的上一层是obj 
//obj的谁调用 this就指向谁 是window调用 所以是window
    //   }
    // }
    // obj.sayHi()
 
    const obj = {
      uname: 'pink老师',
      sayHi: function () {
        console.log(this)  // obj
        let i = 10
        const count = () => {
          console.log(this)  // obj 
        }
        count()
      }
    }
    obj.sayHi()
 实在看不出箭头函数内的this指向谁,就把它换成普通函数试一下,
找到普通函数的this后再往上找一级就好了
  </script>

箭头函数不会创建自己的this,他只会从自己的作用域链上一级沿用this

在开发中使用箭头函数要考虑函数的this的值,事件回调函数使用箭头函数,this是全局的window,因此DOM回调函数为了简便,不是很推荐箭头函数

解构赋值

 数组解构

将数组的单元值快速批量赋值给一系列变量的简介语法

const arr=[100,60,80]
const [max,min,avg]=[100,60,80]
交换变量
let a=1
let b=2;

[b,a]=[a,b]
1.立即执行函数要加
 (function ( })() //(function ( })()  

2、使用数组的时候
  const arr = [1, 2, 3] const str ='pink';
[1, 2, 3].map(function (item){ console.log(item)
])
 let a =1
let b=2
;[b, a] = [a, b] console.log(a, b) 
const [a,b,c,d]=[1,2,3]
console.log(a) //1
console.log(b) //2
console.log(c) //3
console.log(d) //underfined
const [a,b...c]=[1,2,3,4]
console.log(a)//1
console.log(b)//2
console.log(c)//[3,4]
const [a='手机',b='华为']=['小米']
console.log(a)//小米
console.log(b)//华为
const[a,b,,d]=[1,2,3,4]
console.log(a)//1
console.log(b)//2
console.log(d)//4

多维数组解构 

对象解构

对象解构是将对象属性和方法快速批量赋值给一系列变量的简洁语法。

1. 基本语法:
1. 赋值运算符 = 左侧的 {} 用于批量声明变量,右侧对象的属性值将被赋值给左侧的变量
2. 对象属性的值将被赋值给与属性名 相同的 变量
3. 注意 解构的变量名不要和外面的变量名冲突 否则报错
4.对象中找不到与变量名一致的属性时变量值为 undefined

  <script>
    // 对象解构
     const obj = {
        uname: 'pink老师',
        age: 18
     }
    //  解构的语法
    const { uname, age } = {age: 18, uname: 'pink老师' }
    // 等价于 const uname =  obj.uname
    // 要求属性名和变量名必须一直才可以
    console.log(uname)
    console.log(age)
  </script>
  <script>
    // 1. 对象解构的变量名 可以重新改名  旧变量名: 新变量名
    const { uname: username, age } = { uname: 'pink老师', age: 18 }
    console.log(username)
    console.log(age)
  </script>
  <script>
    // 2. 解构数组对象
    const pig = [
      {
        uname: '佩奇',
        age: 6
      }
    ]
    const [{ uname, age }] = pig
    console.log(uname)
    console.log(age)
  </script>
  <script>
     const pig = {
       name: '佩奇',
      family: {
         mother: '猪妈妈',
         father: '猪爸爸',
         sister: '乔治'
       },
      age: 6
     }
     // 多级对象解构
     const { name, family: { mother, father, sister } } = pig
     console.log(name)
     console.log(mother)
     console.log(father)
     console.log(sister)
 
    const person = [
      {
        name: '佩奇',
        family: {
          mother: '猪妈妈',
          father: '猪爸爸',
          sister: '乔治'
        },
        age: 6
      }
    ]
    const [{ name, family: { mother, father, sister } }] = person
    console.log(name)
    console.log(mother)
    console.log(father)
    console.log(sister)
  </script>

侧面反映出数组是有序的,对象是无序的 

P159对象解构20.00-32.38 ​

forEach遍历

forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数

主要使用场景: 遍历数组的每个元素

语法
被遍历的数组.forEach(function(当前数组元素,当前元素索引号){
//函数体
})

1. forEach 主要是遍历数组
2. 参数当前数组元素是必须要写的,索引号可选。

<script>
// forEach就是遍历  加强版的for循环 适合于遍历数组对象 有点像C17的const auto i:
const arr ['red', 'green', 'pink']
constIresult arr. forEach(function (item, index){

    console.log(item)//数组元素 red green pink 
    console.log(index)/索引号
)
// console. Log(result) 
</script>

和map不一样,map有返回值,可以用来处理数组,然后返回新数组,forEach是加强版for循环,可以遍历数组对象,对里面的数据进行处理,不如插入到哪个dom元素等

<body>
  <div class="list">
    <!-- <div class="item">
      <img src="" alt="">
      <p class="name"></p>
      <p class="price"></p>
    </div> -->
  </div>
  <script>
    const goodsList = [
      {
        id: '4001172',
        name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',
        price: '289.00',
        picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
      },
      {
        id: '4001594',
        name: '日式黑陶功夫茶组双侧把茶具礼盒装',
        price: '288.00',
        picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',
      },
      {
        id: '4001009',
        name: '竹制干泡茶盘正方形沥水茶台品茶盘',
        price: '109.00',
        picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
      },
      {
        id: '4001874',
        name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
        price: '488.00',
        picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
      },
      {
        id: '4001649',
        name: '大师监制龙泉青瓷茶叶罐',
        price: '139.00',
        picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
      },
      {
        id: '3997185',
        name: '与众不同的口感汝瓷白酒杯套组1壶4杯',
        price: '108.00',
        picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',
      },
      {
        id: '3997403',
        name: '手工吹制更厚实白酒杯壶套装6壶6杯',
        price: '99.00',
        picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',
      },
      {
        id: '3998274',
        name: '德国百年工艺高端水晶玻璃红酒杯2支装',
        price: '139.00',
        picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',
      },
    ]
 
    // 1. 声明一个字符串变量
    let str = ''
    // 2. 遍历数据 
    goodsList.forEach(item => {
      // console.log(item)  // 可以得到每一个数组元素  对象 {id: '4001172'}
      // const {id} =  item  对象解构
      const { name, price, picture } = item
      str += `
      <div class="item">
        <img src=${picture} alt="">
        <p class="name">${name}</p>
        <p class="price">${price}</p>
      </div>
      `
    })
    // 3.生成的 字符串 添加给 list 
    document.querySelector('.list').innerHTML = str
  </script>
</body>

163筛选商品案例

深入对象

创建对象三种方式

1. 利用对象字面量创建对象

const o = {
    name:'字面量'
}


2. 利用 new Object 创建对象

<script>
    // const obj = new Object()
    // obj.uname = 'pink老师'
    // console.log(obj)
    const obj = new Object({ uname: 'pink' })
    console.log(obj)
  </script>

3. 利用构造函数创建对象 

构造函数

构造函数 :是一种特殊的函数,主要用来初始化对象,就是oop的类

使用场景: 常规的 {...} 语法允许创建一个对象。比如我们创建了佩奇的对象,继续创建乔治的对象还需要重新写一遍,此时可以通过 构造函数 来 快速创建多个类似的对象 。
构造函数在技术上是常规函数。
不过有两个约定:
1. 它们的命名以 大写字母开头 。
2. 它们只能由 " new " 操作符来执行。
构造函数语法: 大写字母开头的函数

  <script>
    // 创建一个猪 构造函数 
    function Pig(uname, age) {
      this.uname = uname
      this.age = age
    }
 
     console.log(new Pig('佩奇', 6))
     console.log(new Pig('乔治', 3))
    const p = new Pig('佩奇', 6)
    console.log(p)
  </script>

1. 使用 new 关键字调用函数的行为被称为 实例化
2. 实例化构造函数时没有参数时可以省略 ()
3. 构造函数内部无需写return,返回值即为新创建的对象,即自动返回创建的新对象
4. 构造函数内部的 return 返回的值无效,所以不要写return
5. new Object() new Date() 也是实例化构造函数

function Goods(name, price, count){ this. name name
this. price price this. count count
const mi = new Goods('小米', 1999,20) console.log(mi)
const hw = new Goods('华为', 3999,59) console. log(hw)
// const date = new Date('2022-4-8') / consoLe. Log(date)

new实例化过程

 实例成员和静态成员

实例成员:
通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员。

JS中其实是没有堆和栈的概念的

构造函数的属性和方法被称为静态成员

function Pig(name) {
this.name = name
}
Pig.eyes = 2 // 静态属性
I
Pig.sayHi = function (){ // 静态方法
console.log(this)
}
Pig.sayHi()
console.log(Pig.eyes) // 2

内置构造函数

在 JavaScript 中 最主要 的数据类型有 6 种:
基本数据类型: 字符串、数值、布尔、undefined、null
引用类型: 对象
但是,我们会发现有些特殊情况: 
其实字符串、数值、布尔、等基本类型也都有专门的构造函数,这些我们称为 包装类型 。
JS中几乎所有的数据都可以基于构造函数创建
引用类型 :Object,Array,RegExp,Date 等
包装类型 :String,Number,Boolean 等

5.1 Object
Object 是内置的构造函数,用于创建普通对象。 

但是推荐使用字面量方式声明对象,而不是 Object 构造函数 ​

 第一种方法

1.Object.keys
作用: Object.keys 静态方法获取 对象中所有属性(键)
语法:
  <script>
    const o = { uname: 'pink', age: 18 }
    // 1.获得所有的属性名
    console.log(Object.keys(o))  //返回数组['uname', 'age']
  </script>
注意: 返回的是一个 数组

第二种方法

  <script>
    const o = { uname: 'pink', age: 18 }
    // 2. 获得所有的属性值
    console.log(Object.values(o))  //  ['pink', 18]
  </script>

第三种方法

  <script>
    const o = { uname: 'pink', age: 18 }
    // 3. 对象的拷贝
     const oo = {}
     Object.assign(oo, o)
     console.log(oo)


    Object.assign(o, { gender: '女' })
    console.log(o)
  </script>

 reduce数组

作用: reduce 返回函数累计处理的结果,经常用于求和等
基本语法:arr.reduce(function(累计值, 当前元素){}, 起始值) 
参数: 起始值可以省略,如果写就作为第一次累计的起始值

arr.reduce(function(){},起始值)

// 1. 没有初始值
const total = arr.reduce(function (prev, current) {
 return prev + current 
})
 console.log(total)

// 上一次值 当前值 返回值(第一次循坏)
      1       5      6
 
// 上一次值 当前值 返回值 (第二次循坏)
      6       8     14


const arr = [1, 5, 8]
// 2. 有初始值
const total = arr.reduce(function (prev, current) {
return prev + current
}, 10)
console.log(total)
 
// 上一次值 当前值 返回值(第一次循坏)
      10       1      11
 
// 上一次值 当前值 返回值 (第二次循坏)
      11      5    16

// 上一次值 当前值 返回值(第三次循坏)
      16       8      24

计算薪资案例

const arr =[{
name:'张三', salary: 10000 },{
name:'李四', salary: 10000 },{
name:'王五', salary: 10000 }]
//计算薪资案例
const total = arr. reduce((prev, current)=>{ 

// consoLe. Log(prev)
return prev current. salary ), 0)
console.log(total) 
上一次值
当前值 返回值 (第一次遍历) 
10000
10000 ∥上一次值
当前值
返回值(第二次遍历) //10000
10000
20000 上一次值
当前值返回值(第三次遍历) /20000
1000030000
//需求:每个人涨薪30%,当月支出多少薪资
const total arr. reduce((prev, current) = prev current.salary 1.3, console.log(total)
∥上一次值
当前值 返回值
(第一次遍历) /
13000
13000 /上一次值
当前值 返回值
(第二次遍历) /13000
13000
26000 ∥上次值
当前值
返回值(第三次遍历) //26000
13000 39000 

array

const arr =[
{
name:'小米', price: 1999 
},
{
name:'华为',
price: 3999
},]
//找小米这个对象,并且返回这个对象/ 
const mi arr. find(function (item){
 console. Log(item)//
 consoLe. Log(item. name)// 
console. Log(111)
 return item.name==='华为'
})
const mi = arr.find(item =>item.name =='小米') 
console.log(mi)
const spec ={ size: '40cm*40cm', color:'黑色'} 
//1.所有的属性值回去过来数组
// console. Log(Object. values(spec)) 
//2.转换为字符串join('/')
// console. Log(Object. vaLues(spec). join('/))
document. querySelector('div'). innerHTML Object. values(spec). join('/') 

string

1.实例属性length用来获取字符串的度长(重点)1.常见实例方法

2.实例方法split(分隔符')用来将字符串拆分成数组(重点)

3.实例方法substring(需要截取的第一个字符的索引[,结束的索引号])用于字符串截取(重点)

4.实例方法startswith(检测字符串[,检测位置索引号])检测是否以某字符开头(重点]

5.实例方法includes(搜索的字符串[,检测位置索引号])判断一个字符串是否包含在另一个字符串中,根据情况返回true 或false(重点)

6.实例方法toUpperCase用于将字母转换成大写

7.实例方法toLowerCase用于将就转换成小写

8.实例方法indexof检测是否包含某字符

9.实例方法endswith检测是否以某字符结尾

10.实例方法replace用于替换字符串,支持正则匹配

11.实例方法match查找字符串,支持正则匹配

 渲染商品案例

根据你的需求来,foreach是针对于所有的数据遍历,map是对数据进行修改和返回,for就偏向于大众化一点 

const gift='50g的茶叶,清洗球'
//1.把字符串拆分为数组
// console. log(gift.split(','))[,]
//2.根据数组元素的个数,生成对应span标签
// const str gift. split(', ') map(function (item){ 
return `<span>【品】${ item}</span><br>`
// ).join('')
// consoLe. log(str)
// document. querySeLector('div'). innerHTML=str
document.querySelector('div').innerHTML=gift.split(',').map(item=`><span>【赠品】${item}</ span><br>).join('')