【JS】JavaScript进阶 ES6 - 黑马视频笔记

1. 作用域

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

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

1.1 局部作用域

局部作用域分为:函数作用域、块作用域。

1. 函数作用域

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

函数的参数也是函数内部的局部变量。函数执行完毕,函数内部的变量实际被清空了。

2. 块作用域

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

let 声明的变量会产生块级作用域, var 不会产生块级作用域。

const 声明的常量也会产生块作用域。

不同代码块之间的变量无法互相访问。

推荐使用 let 或 const 。

for 循环声明的变量,虽然在{ }外面,但是for是一个整体,默认变量都在{}里面。还有 if while 等等。

1.2 全局作用域

<script> 标签和 .js文件的最外层都是全局作用域。全局作用域中声明的变量,任何其他作用域都可以访问。

注意:

1.为 window对象动态添加的属性默认也是全局的,不推荐,比如 a=10,其实就是 window.a=10。

2.函数中未使用任何关键字声明的变量为全局变量,不推荐。

3.尽可能少声明全局变量,防止全局变量被污染。

1.3 作用域链   【重点】

作用域链 本质上是底层的变量查找机制

可以理解为就近原则、冒泡。

在函数被执行时,会优先查找当前函数作用域中查找变量。如果找不到,则会依次逐级查找父级作用域直到全局作用域。

1. 嵌套关系的作用域串联起来形成了作用域链

2. 相同作用域链中按着从小到大的规则查找变量

3. 子作用域可以访问父作用域,但父级作用域无法访问子作用域。

1.4 垃圾回收机制

内存的生命周期

js中分配的内存,一般有如下生命周期:

1. 内存分配:声明变量、函数、对象时,系统自动分配

2. 内存使用:读写内存,也就是使用变量、函数等

3. 内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存

声明:

全局变量一般不会回收(关闭页面回收)

一般情况下局部变量的值,不用了,会被自动回收。

js垃圾回收机制-算法说明

引用计数。

定义“内存不再使用”,看一个对象是否有指向它的引用,没有引用就回收对象。

被引用一次,就计数+1,减少一个引用就-1,为0时,就释放内存。

标记清除法。

现代浏览器已经不再使用引用计数法了。

就是从根部(全局对象)出发,能到达就还是需要使用的,无法到达的就回收。

1.5 闭包 

一个函数对周围状态的引用捆绑在一起,內层函数中访问到其外层函数的作用域。

简单理解:闭包 = 内层函数 + 外层函数的变量   

function A() {
    const a = 1
    function B() {
        console.log(a)
    }
    B()
}
A()

内层函数 function B() 和 变量a 与调用函数B() 属于闭包。

闭包作用:封闭数据,提供操作,外部也可以访问函数内部的变量。

闭包:调用外部函数的变量和参数的函数 组成闭包

好处:外部可以访问函数内部变量 实现变量私有化  

缺点:造成内存泄漏  解决方法  手动释放内存  null

1.6 变量提升 

它允许在变量声明之前被访问,仅存在于 var 声明变量。

在代码执行之前,把所有 var 声明的变量提升到当前作用域的最前面只提升声明,不提升赋值

1. 变量在未声明即被访问时会报错

2. 变量在 var 声明之前即被访问,变量的值为 undefined。

console.log(num)
var num = 10

// 提升前 ↑      提升后 ↓

var num                     // 只提升变量,不提升赋值,所以值是 undefined
console.log(num)
var num = 10

 

2. 函数进阶

2.1 函数提升 

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

会把所有函数声明提升到当前作用域的最前面。

fun()
function fun(){
    console.log('函数提升,只提升函数声明,不提升函数调用')
}

2.2 函数参数 arguments ... 

1. 动态参数 arguments 

arguments 是函数内部内置的伪数组变量,包含了调用函数时传入的所有实参。

1. 是伪数组只存在于函数中

2. 作用是动态获取函数的实参。

3. 可以通过 for 循环依次得到传递过来的实参。

比如:不确定要计算多少个参数:

function getSum(){
    let sum = 0
    for(let i = 0; i < arguments.length; i++){
        sum += arguments[i]
    }
    return sum
}
console.log( getSum(8,6,4,2) )

2. 剩余参数 ...other 

将一个不定数量的参数表示为一个数组。  

1. ... 是语法符号,置于最末函数形参之前,用于获取多余的实参

2. 借助 ... 获取的剩余实参,是个真数组,可以使用数组的方法 pop push。

在剩余参数使用的时候,不需要拿...,只需要拿后面的参数名就行。

function getSum(...shuzi){
    console.log(shuzi)
}
getSum(8,6,4,2)         // 得到真数组 [8, 6, 4, 2]
function getSum(a,b,...shuzi){           // 前面的参数一一对应,剩下的都给 ...剩余参数
    console.log(a)                 // 8
    console.log(b)                 // 6
    console.log(shuzi)             // [4, 2]
}
getSum(8,6,4,2)

建议多使用 剩余参数。

2. 展开运算符 ... 

展开运算符将一个数组进行展开。

语法: ... 

1. 不会修改原数组

使用场景:求最大值、合并数组。

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

console.log(Math.max(1,2,3,4,5))     // 5       求最大值
console.log(Math.max(...arr))        // 5       本质上 ...arr === 1,2,3,4,5   打印不显示,因为打印没意义

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

const arrNew = [...arr,...arr2]     //          合并数组
console.log(arrNew)                 // [1, 2, 3, 4, 5, 9, 9, 9]

2.3 箭头函数 【重点】

箭头函数的目的是更简短的函数写法,并且不绑定this,语法比函数表达式更简洁。

使用场景:箭头函数更适用于那些本来需要匿名函数的地方。

1. 基本语法

语法: () => {  }    

1. 箭头函数        

// 普通函数
const fn1 = function() {
    console.log('123')
}
// 箭头函数
const fn2 = () => {
    console.log('123')
}

2. 箭头函数   带参数

如果只有一个参数,就可以省略小括号,无参数一个以上参数不能省略括号!      

// 2. 只有一个形参时,可以省略小括号
//const fn2 = (x) => {
  const fn2 = x => {
      console.log(x)
  }
  fn2(3333)        // 3333

3. 只有一行代码时,可以写到一行上,可以省略大括号,无需写return直接返回值

// 3. 只有一行代码时,可以省略大括号,可以写到一行上,无需写return直接返回值
const fn3 = x => return x + x
fn3(3333)        // 6666

4. 加括号的函数体返回对象字面量表达式

// 4. 箭头函数可以直接返回一个对象,用()括号包住,不然{ {xx:xx} }就报错
const fn4 = (uname) => ( {uname: uname} )
console.log( fn4('刘德华') )

//    简写前:                只有一行代码,可以写在一行上,省略{大括号}、省略 return直接返回值
//    const fn4 = (uname) => {
//        return {uname: uname}
//    }

 结论:

1. 箭头函数属于函数表达式,无函数提升

2. 箭头函数只有一个参数时可以省略 ( )括号

3. 箭头函数函数体只有一行函数可以省略花括号 { },并自动做为返回值被返回,无需写 return 

4. 加括号的函数体返回对象字面量表达式

2. 箭头函数参数

箭头函数没有 arguments 动态参数,但是有剩余参数 ...args 。

const getSum = (...my_arr) => {
    let sum = 0
    for(let i = 0; i < my_arr.length; i++){
        sum += my_arr[i]
    }
    return sum
}
console.log( getSum(8,6,4) )

3. 箭头函数 this

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

大白话就是:箭头函数的 this,是【它爹的 this】。就是上一层作用域的 this。

this:谁调用的这个函数,this 就指向谁。

DOM事件回调函数为了简便,想使用this的值,不太推荐使用箭头函数。

// 普通函数 this
function fn() {
    console.log(this)   // this 指向 window
}
fn()    // window.fn()

// 箭头函数 this    是上一层作用域的 this
function fn() {
    console.log(this)   // this 指向 window
}
fn()    // window.fn()

// 对象方法 this
const obj = {
    name: 'anni',
    sayHi: function() {
        console.log(this)    // this 指向 obj
    }
}
obj.sayHi()

// 对象方法箭头函数 this
const obj = {
    name: 'anni',
    sayHi: () => {
        console.log(this)    // this 指向 window 
    }
}
obj.sayHi()        // 箭头函数向上一层找,也就是obj的父级,所以this 是 window

 

3. 结构赋值  (数组解构、对象解构)

 

1.数组解构 

数组解构是 将数组的单元值快速批量赋值给一系列变量简洁语法。数组解构其实就是把数组里的元素赋值给变量。

基本语法:

1. 赋值运算符 = 左侧的 [ ] 用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量。

2. 变量的顺序对应数组单元值的位置依次进行赋值操作。按顺序依次赋值。

原先的方式
const arr = [1,2,3]
console.log(arr[0])
console.log(arr[1])
console.log(arr[2])
const a = arr[0]
const b = arr[1]
const c = arr[2]
console.log(a)
.....
// 上面的要么不好记忆。要么书写麻烦,此时可以使用 解构赋值 的方法来让代码更简洁:
const [a,b,c] = [1,2,3]            // 或  const [a,b,c] = arr
console.log(a)  // 1
console.log(b)  // 2
console.log(c)  // 3

典型的语法:交换两个变量的值

注意:js 前面必须加上分号。一个是立即执行函数,二是数组解构。

const a = 1
const b = 2;      // 必须加上分号,不然就和后面连一起了:const b = 2[b,a] = [a,b]
[b,a] = [a,b]     // 如果上面不写分号,这条语句前面就得写,如:  ;[b,a] = [a,b] 
console.log(a,b)  // 2 1

//-----------------
const b = 2
[b,a] = [a,b]
相当于:
const b = 2[b,a] = [a,b]
// 1. 立即执行函数
(function t() {}) ();
;(function t() {}) ()
// 2. 数组解构    特别是前面有语句的一定要加分号;  不然就连一起了
;[b,a] = [a,b]

一些附加情况:

1. 变量多 单元值少的情况

const [a,b,c] = [1,2]
console.log(a)  // 1
console.log(b)  // 2
console.log(d)  // undefined

2. 变量少 单元值多的情况

const [a,b] = [1,2,3,4]
console.log(a)  // 1
console.log(b)  // 2

3. 变量少 单元值多的情况  用剩余参数 ...

const [a,b,...c] = [1,2,3,4]
console.log(a)    // 1
console.log(b)    // 2
console.log(c)    // [3,4]   真数组
console.log(c[0]) // 3

4. 防止 undefined 传递     赋值默认值

const [a = 0,b = 0] = [1]
console.log(a)  // 1
console.log(b)  // 0   默认值

5. 按需导入,忽略某些返回值

const [a,b, ,d] = [1,2,3,4]
console.log(a)  // 1
console.log(b)  // 2
console.log(d)  // 4            // 因为b后面没有变量,3传不过来

6. 支持多维数组的结构

const [a,b,c] = [1,2,[30,40],3]         // 二维数组
console.log(a)     // 1
console.log(b)     // 2
console.log(c)     // [30,40]
console.log(c[0])  // 30
console.log(c[1])  // 40
console.log(d)     // 50

2. 对象解构 

基本语法:

1. 赋值运算符 = 左侧的 { } 用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量。

2. 对象属性的值将被赋值给与属性名相同的变量。因为对象赋值是无序的,所以,声明的变量名字必须与属性名一致

3. 注意解构的变量名不要和外面的变量名冲突,否则报错

4. 对象中找不到与变量名一致的属性时变量值为 undefined

语法: { } = { }

const { uname,age } = {
    uname: '猫',
    age: 2
}
// 也就是:
const { uname,age } = { uname: '猫',age: 2 }       //声明变量名 与 属性名 必须一致
// 等价于   cosnt uname = obj.uname
console.log(uname)    // '猫'

1. 给新的变量名赋值:

 语法:{ old_name: new_name }  ,旧值:新值,“什么值: 赋值给谁”

 当解构变量名与外面的变量名冲突时,可以重新命名。

const uname = '二哈'
const { uname:username ,age } = { uname: '猫',age: 2 }        // 加冒号 :重新命名
console.log(username)

2. 解构数组对象

数组里面有多个对象。

在解构的时候,先看外层是什么,是什么包一层什么,是对象包对象{ },数组包数组。

先看最外层是什么,再看內层的,如:最外层是[ ]数组,內层是{ }对象,所以就是 [ { } ]

const car = [
    {
        name: '铃木',
        age: 2
    }
]
const [{name,age}] = car
console.log(name)   //铃木
console.log(age)    //2

3. 多级对象解构

遇到多级对象,需要加上对象名,冒号,大括号。

const car = {
    name: '铃木',
    data: {
        torque: 24,
        date: 2023
    },
    age: 2
}
const { name, data: {torque,date} } = car
console.log(name)     //铃木
console.log(torque)   //24
console.log(date)     //2023

数组里的对象的对象:

const car = [
    {
        name: '铃木',
        data: {
            torque: 24,
            date: 2023
        },
        age: 2
    }
]
const [{ name, data: {torque,date} }] = car       // [{    { }  }]
console.log(name)     //铃木
console.log(torque)   //24
console.log(date)     //2023

模拟处理AJAX数据:

// 1. 解构
        const { name, data: { torque, date } } = car
        console.log(name)     //铃木
        console.log(torque)   //24 Nm
        console.log(date)     //2023年

// 2.上面 car 是后台传过来的,把里面的 data 当参数传给 函数
        /* 
        function getCar(arr) {
            const { data } = arr        // 就是 const { data } = car
            console.log(arr.torque)
        }
        getCar(car)
        */
        // 这样写不简洁
        

        // 由于 const { data } = car
        // 因为 car 传给了 {data},然后 car 和 {data} 是一样的,传递参数的时候,直接做解构,写 {data}

        function getCar( {data} ) {
            console.log(data.torque)    // 24 Nm
        }
        getCar(car)

3. 遍历数组 forEach() 方法【重点】

用于调用数组的每个元素,并将元素值传回给回调函数。  加强版的 for 循环。适合于遍历数组对象

遍历数组的每个元素。只遍历,不返回值。与map的区别是这个不返回值。

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

const car = ['铃木','2023年']
        car.forEach(function(item,index) {
            console.log(item)
            console.log(index)
        })

 案例:

forEach 渲染商品
const goodsList = [
            {
                id:'001',
                name:'美食美食美食美食美食美食美食美食美食',
                price:'1000',
                picture:'../../../images/bg/top_img01.jpg'
            },
            {
                id:'002',
                name:'特产特产特产特产特产特产特产特产特产特产特产',
                price:'1050',
                picture:'../../../images/bg/top_img02.jpg'
            }
        ]
        // 1. 声明一个字符串变量
        let str = ''
        // 2. 遍历数组
        goodsList.forEach( item => {
            console.log(item)        // 可以得到每一个数组元素 对象
            const {name, price, picture} = item //解构赋值 对象
            str += `
                <div class="item">
                    <img src="${picture}" width="400px">
                    <p class="price">¥${price}</p>
                    <p class="name">${name}</p>
                </div>
            `
        })
        // 3. 生成的 字符串 添加给 list
        document.querySelector(".list").innerHTML = str

4. 筛选数组 filter()    【重点】

类似于 map   。

filter () 方法创建一个新的数组,新数组中的元素是通过符合指定条件的所有数组元素。

用处:筛选数组符合条件的元素,并返回筛选后元素的新数组。

4. 深入对象

1. 创建对象的三种方式

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

const obj = {
    name: '名字啊'
}

2. 利用 new Object() 创建对象

const obj = new Object()
obj.name = '佩奇'

const obj2 = new Object( {name: '佩奇'} )            // 也可以这样写

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

 自定义一个构造函数。

2. 构造函数

是一种特殊的函数,主要用于初始化/创建对象的

可以批量生成,快速创建对象,把公共的属性都封装到一个函数里

构造函数在技术上是常规函数,有两个约定:以大写字母开头命名、只能由 new 操作符来执行。

构造函数必须 new 一下,实例化才可以。

// 1. 创建构造函数  猪类
function Pig(uname,age){
    this.uname = uname
    this.age = age
}

// 2. new 关键字调用函数
const qz = new Pig('乔治',3)
console.log(qz)                     // {uname: '佩奇', age: 5}

console.log( new Pig('佩奇',5) )    // {uname: '佩奇', age: 5}

1. 使用 new 调用函数的都叫实例化

2. 没参数时可以省略 ()

3.  函数内部无需写return,返回值是新创建的对象

4. 构造函数内部的 return 返回的值无效,所以不要写 return

5. new Object()   new Date() 也是实例化构造函数

实例化执行过程:

1. 创建新的空对象

2. 构造函数 this 指向新对象

3. 执行构造函数代码,修改 this ,添加新的属性

4. 返回新对象

3. 实例成员和静态成员

1. 为构造函数传入参数,创建结构相同,但值不相同

2. 构造函数创建的实例对象彼此独立互不影响

简单来说,实例成员,是new后实例对象里的。静态成员,是构造函数里的。

实例成员:实例属性、实例方法。也就是实例对象里的属性和方法

实例对象相互独立,实例成员在当前实例对象使用

// 1. 实例成员:实例对象 身上的属性和方法
function Pig(name) {
    this.name = name
}
const pq = new Pig('佩奇')
pq.name = '小猪佩奇'        //实例属性
pq.sayHi = () => {         //实例方法
    console.log('Hi~~')
}

静态成员:静态属性、静态方法。也就是构造函数里的的属性和方法

静态成员只能构造函数访问。

// 2. 静态成员:构造函数 身上的属性和方法
function Pig(uname, age) {
    this.name = name
}

Pig.age = 2                 //静态属性
Pig.sayHi = function() {    //静态方法
    console.log('Hi~')
}

console.log(Pig.age)        // 2 
Pig.sayHi()                 // Hi~

4. 内置构造函数

 在 JavaScript 中最主要的数据类型有 6 种。

基本数据类型(简单数据类型):字符串、数值、布尔、undefine、null

引用数据类型(引用数据类型):对象(数组和函数都属于对象)

const str = '小猫'

// 相当于 ↓

const str = new String('小猫')    // js底层完成  把简单数据类型包装为引用数据类型

如上面例子,js底层完成  把简单数据类型包装为引用数据类型

 其实字符串、数值、布尔等都有专门的构造函数,这些称为包装类型。

js中几乎所有的数据都可以基于构造函数创建。

1. Object

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

推荐使用字面量方式声明对象,而不是 Object 构造函数。因为字面量更简便一些。

常用的静态方法(静态方法就是只有构造函数Object可以调用):

Object.keys  :获取对象中所有的属性(键),返回一个数组。

Object.values  :获取对象中所有的属性值(值),返回一个数组。

Object.assign  :用于对象拷贝。经常用于给对象添加属性和值

语法:

// 1. 获得所有的属性名(键)
console.log(Object.keys(obj))       // ['name', 'color']
// 2. 获得所有的属性值(值)
console.log(Object.values(obj))     // ['黑猫', '黑色']
// 3. 对象拷贝
const obj2 = {}
Object.assign(obj2, obj)
console.log(obj2)                   // {name: '黑猫', color: '黑色'}
//    追加属性
Object.assign(obj2, { like: '小鱼干' })
console.log(obj2)                   // {name: '黑猫', color: '黑色', like: '小鱼干'}

2. Array

Array 是内置的构造函数,用于创建数组。

推荐使用字面量方式创建数组,而不是 Array  构造函数。因为字面量更简便一些。

forEach  :遍历数组。不返回数组,用于查找遍历数组元素。

filter       :过滤数组。返回新数组,返回筛选满足条件的数组元素。

map        :迭代数组。返回新数组,返回处理后的数组元素。

from        :将伪数组转换为真数组。【重点】

find         :查找元素,返回符合条件的第一个数组元素值,并返回这个对象,无符合的就返回undefined。【重点】

every      :检测数组所有元素是否都符合指定条件,都符合就返回true,否则false。【重点】

reduce    :累计器。返回累计处理的结果,用于求和。

reduce 语法:arr.reduce(function(){}, 起始值)arr.reduce(function(上一次值, 当前值){}, 初始值)

如果有起始值,则把初始值累加到里面。

const arr = [1,5,8]
// 1. 没有初始值
const total = arr.reduce(function(previous, current) {
    return previous + current
})
console.log(total)      // 14
// 2. 有初始值
const total = arr.reduce(function(previous, current) {
    return previous + current
}, 10)
console.log(total)      // 24      10+14
// 3. 箭头函数的写法
const total = arr.reduce((previous, current) => previous + current, 10)
console.log(total)      // 24      10+14

 reduce 执行过程:

1. 如果没有起始值,则上一次值就是数组的第一个数组元素的值

2. 每次循环,把返回值给做为下一次循环的上一次值

3. 如果有起始值,则起始值做为上一次值

简单来说,

无初始值,【上一次值】是【数组第一个元素的值】,【当前值】是【数组第二个元素的值】,【返回值】就是它俩累加的。第二次循环,【上一次值】是【返回值】,【当前值】是【数组第三个元素】,【返回值】是它俩累加的。

有初始值,【上一次值】是【初始值】,【当前值】是【数组第一个元素的值】,【返回值】就是它俩累加的。第二次循环,【上一次值】是【返回值】,【当前值】是【数组第二个元素】,【返回值】是它俩累加的。几个数就循环几次。

 

reduce 计算工资案例
 const arr = [
    {
        name:'牛牛',
        wages: 1000
    },{
        name:'加菲猫',
        wages: 1050 
    },{
        name:'汤姆猫',
        wages: 6543 
    }
]
// 计算工资总数
const total = arr.reduce((previous, current) => {
    //console.log(previous)   // 返回了第一个对象,不能用来相加,所以,必须有起始值 设置为0
    //return previous + current     //拿着对象累加是错误的,应该要它的属性值
    return previous + current.wages     // 对象.工资
}, 0)
console.log(total)

// 工资上涨到130%
const total_130 = arr.reduce((previous, current) => {
    //     上一次值 +  每一个工资  * 1.3
    return previous + current.wages * 1.3
}, 0)
console.log(total_130)

 

find 方法
 const arr1 = ['red','pink','blue']
const arrFind = arr1.find( item => {
    return item === 'blue'
})
console.log(arrFind)        // blue

// 用途
const arr = [
    {
        name: '一加',
        price: 2700
    },{
        name: '小米',
        price: 2710
    }
]
// 找“小米”这个对象,并且返回这个对象
const xiaoMi = arr.find( item => {
    //console.log(item)                //每一个对象
    //console.log(item.name)           //每一个对象的name属性值
    return item.name === '小米'
})
console.log(xiaoMi)              // {name: '小米', price: 2710}

 

every 与 some 语法:

every 全都符合条件、some 只要有一个符合条件就行。

// 2. every 都符合就返回true
const arr2 = [10,20,30,40]
const arr2Every = arr2.every( item => item >= 10)   //条件是每个都>=10
console.log(arr2Every)          // true
// 3. some  只要有一个符合就返回true    
const arr2Some = arr2.some( item => item >= 30)   //条件是有一个>=10就行
console.log(arr2Some)          // true

3. String 

 

 

// 1. split() 把字符串 转换为 数组,和 join() 相反
const str1 = 'pink,red,blue'
const arr1 = str1.split(',')        // 分隔符
console.log(arr1)

// 2. substring(开始的索引号 [,结束的索引号])  截取字符串。少用substr()
//    如果省略结束的索引号,默认读取到最后
//    结束的索引号不包含想要截取的部分
const str2 = '那个地方有黑猫,旁边还有加菲猫'
console.log(str2.substring(5,7))    //黑猫    5-7但不包含7

// 3. startsWith(检测字符串 [,检测位置索引号]) 检测是否以某个字符串开头
const str3 = '加菲猫a在我旁边,黑猫在外面'
console.log( str3.startsWith('加菲猫a'))     // true
console.log( str3.startsWith('加菲猫A'))     // false
console.log( str3.startsWith('黑猫',8))     // true

// 4. includes(检测字符串 [,检测位置索引号])   只要字符串包含指定内容,就返回true,否则false
const str4 = '加菲猫a在我旁边,黑猫在外面'
console.log(str4.includes('加菲猫'))       //true
console.log(str4.includes('旁边,黑猫'))    //true
console.log(str4.includes('我旁边',2))     //true
console.log(str4.includes('白猫'))         //false
console.log(str4.includes('猫A在'))       //false

显示赠品(split 把字符串转换为数组,map 再遍历,join 再转换为字符串)

显示赠品(把字符串转换为数组,再遍历,再转换为字符串)
 // 案例:显示赠品
const case1 = '新版标准外语,五十音教程,PDF资料'
//                     转换为数组  再遍历数组
const case1str = case1.split(',').map( item => {
    return `<span>【赠品】${item}</span>`
}).join('</br>')    // join把数组转成字符串 br换行

console.log(case1str)   //<span>【赠品】新版标准外语</span></br><span>...
// 渲染到页面div当中
document.querySelector('div').innerHTML = case1str

4. Number 

Number 是内置的构造函数,用于创建数值

常用方法:

toFixed()  :设置保留小数位的长度,四舍五入

const n = 12.345
// 保留两位小数 四舍五入
console.log(n.toFixed(2))   // 12.35

const n2 = 10
console.log(n2.toFixed(2))      // 10.00

案例:购物车

案例:购物车
 <div class="list">
    <!-- <div class="item">
        <img src="/images/bg/top_img01.jpg" alt="图片">
        <p class="name">鸡排丼饭鸡排丼饭鸡排丼饭鸡排丼饭鸡排丼饭
            <span class="tag">【赠品】xxx</span>
            <span class="tag">【赠品】xxx</span>
        </p>
        <p class="spec">原味</p>
        <p class="price">1500.00</p>
        <p class="count">2</p>
        <p class="sub-total">3000.00</p>
    </div> -->
</div>
<div class="total">
    <p class="total-title">合计:</p>
    <p class="total-yuan">3000.00</p>
</div>

<script>
    const goodsList = [
        {
            id: '50001001',
            name: '鹿児島県産黒毛和牛100%小田牛のハンバーグステーキ',
            price: 600.00,
            picture: '/images/bg/top_img01.jpg',
            count: 1,
            spec: '120g'
        },{
            id: '50001002',
            name: '桂花拉麺 4食 麻辣が食欲をそそります、麻辣が絶妙なハーモニーに',
            price: 1596.00,
            picture: '/images/bg/top_img02.jpg',
            count: 4,
            spec: '麻辣',
            gift: '新鲜鸡蛋*4个,辣椒*1瓶'
        },{
            id: '50001001',
            name: '鹿児島県産黒毛和牛100%小田牛のハンバーグステーキ',
            price: 500.5,
            picture: '/images/bg/top_img03.jpg',
            count: 5,
            spec: '120g'
        },{
            id: '50001002',
            name: '桂花拉麺 4食 麻辣が食欲をそそります、麻辣が絶妙なハーモニーに',
            price: 1596.00,
            picture: '/images/bg/top_img04.jpg',
            count: 3,
            spec: '原味',
            gift: '新鲜鸡蛋*4个'
        },
    ]

    // 1. 遍历数组数据,渲染页面
    document.querySelector('.list').innerHTML =  goodsList.map( item => {
        console.log(item)   //每一条对象
        // 更换数据 图片文字价格等 采取对象解构方式 单价保留2位小数
        //     对象解构 item.name item.price ....
        const {name,price,picture,count,spec,gift} = item
        // 处理 赠品 模块   
        //   声明变量接收赠品数据,首先判断有没有赠品,有就处理数据,没有就返回空格''
        const giftStr = gift ? gift.split(',').map( item => {
            return `<span class="tag">【赠品】${item}</span>`
        }).join('') : ''
        // 计算小计模块 单价*数量  
        //   小数精度问题 0.1+0.2=0.30004 ,因为保留2位小数,所以乘以100,最后除以00
        const subTotal = ((price * 100 * count) / 100 ).toFixed(2)

        // 渲染页面
        return `
            <div class="item">
                <img src="${picture}" alt="图片">
                <p class="name">${name} ${giftStr}</p>
                <p class="spec">${spec}</p>
                <p class="price">${price.toFixed(2)}</p>
                <p class="count">${count}</p>
                <p class="sub-total">${subTotal}</p>
            </div>
        `

    }).join('')

    // 2. 合计模块
    const total = goodsList.reduce( (prev,item) => {
        return prev + (item.price * 100 * item.count) / 100
    }, 0)
    console.log(total)
    document.querySelector('div.total .total-yuan').innerHTML = total.toFixed(2)

</script>

 

posted @ 2023-02-22 21:08  nekmea  阅读(83)  评论(0编辑  收藏  举报