JS高级-2

100 阅读9分钟

class 类名{
    //
}
创建实例:let obj = new 类名

类与构造函数

class Star{
    //构造函数
    constructor(uname){
        this.uname = uname;
    }
}

//利用类创建对象new,每次创建类对象,就会执行构造函数
const ldh = new Star('刘德华')

构造函数可以接收传递过来的参数,同时返回实例对象。
创建类的时候,类名后面不需要加小括号,构造函数(constructor)不需要加function。

类的继承

通过extends关键字来实现继承父类的属性和方法

class Father{
    sum(){
        console.log('求和')
    }
}
class Son{
    
}
const son = new Son()
son.sum()//子类可以调用父类的方法,输出求和

super关键字可以用来访问和调用对象父类的函数。【可以调用父类的构造函数】,也可以调用普通函数(子类中存在和父类相同的方法,默认先调用自己的,再调用父类的,但是用了super就可以指定父类)

class Father{
    constructor(x,y){
        this.x = x
        this.y = y
    }
    
    //类中的方法
    sum(){
        console.log(this.x+this.y)
    }
}
//子类继承父类
class Son extends Father{
    constructor(x,y){
        super(x,y);//调用父类中的构造函数
    }
    sum(){
        //调用父类方法
        console.log(super.sum()+'我是子类')
    }
}
const son = new Son(100,200);
son.sum()//300我是子类

深入对象

创建对象的三种方式

  1. 利用字面量创建对象
const o = {
    name:'佩奇'
}
  1. 利用new Object来创建对象
const obj = new Object()

//添加属性
obj.uname = 'pink'
console.log(obj)

-----------------------------------

const obj = new Object({
    uname:'pink'
})
console.log(obj)

利用构造函数创建对象(重要)

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

使用场景:常规的{...}语法允许创建一个对象,比如我们创建了佩奇对象,继续创建乔治对象,还需要重新写一遍,此时可以通过构造函数来快速创建多个类似的对象。

image.png

这样创建,需要一个一个创建,而且他们的属性是一样的,太麻烦了。

我们通过构造函数就可以解决,把公共的封装到里面:

function Pig(name,age,gneder){
    this.name = name
    this.age = age
    this.gender = gender
}

//创建佩奇对象
const Peppa = new Pig('佩奇',6,'女')

//创建乔治对象
const George = new Pig('乔治',3,'男')

console.log(Peppa)

构造函数在技术上是一个常规函数,但是有两个约定:

  1. 他们的命名以【大写字母】开头

  2. 他们只能由new操作符来执行

构造函数

//创建一个猪 构造函数,首字母大写
function Pig(uname,age){
    this.name = uname //this指向调用者 佩奇
    this.age = age
}
//通过 new 来调用
const p = new Pig('佩奇',6)
console.log(p)

image.png

image.png

案例

image.png

function Goods(name,price,count){
    this.name = name
    this.price = price
    this.count = count
}

const mi = new Goods('小米',1999,20)
const hw = new Goods('华为'3999,59)
const vivo = new Goods('vivo',1888,100)

回顾以前的Date函数,也是用new来创建。实际上Date是JavaScript内置的一个构造函数。

const date = new Date('2022-7-1')

实例化执行过程

image.png

实例成员和静态成员

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

image.png

image.png

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

被挂载到构造方法上的就是静态成员

const hw = new Goods('')

//Goods是构造函数,在构造函数里写的属性和方法就是静态成员
Goods.num = 10
Goods.sayHi = function(){
    
}

image.png

一般公共特征的属性和方法,被设置成:静态成员。

静态成员方法中的this指向构造函数本身,因为是构造方法本身调用的他。

image.png

内置构造函数

image.png

数组和函数都属于对象类型,只有对象类型才有属性和方法。

可是为什么有的简单数据类型具有属性和方法,比如length属性?

const str = 'pink' =》 const str = new String('pink')

答:实际上基本数据类型也有专门的构造函数,我们成为:包装类型。JS底层将简单数据类型,包装成了“引用数据类型”。

内置函数:
引用类型:Objcet、Array、RegExp、Date等
包装类型:String、Number、Boolean等

Object

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

const user = new Object({name:'小明',age:15})

实际上我们更推荐使用字面量的形式声明对象,而不是这种Object构造函数:const user = {...}

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

  1. 想要获取对象里面的属性和值,以前的做法:
const o = {name:'佩奇',age:6}

for(let i in o){
    console.log(i)//返回属性:name、age
    console.log(o[i])//返回值:佩奇 6
}

但是通过静态方法,不需要循环就可以获得:
Object.keys静态方法获取对象中所有属性(键)

const o = {name:'佩奇',age:6}

//获得对象的所有键,并且返回是一个数组
const arr = Object.keys(o)

console.log(arr)//['name','age']返回键,属性名

console.log(Object.values(o))//返回值,佩奇 6
  1. Object.assign 静态方法,用于对象拷贝
//拷贝对象,将o拷贝给obj
const o = {name:'佩奇',age:6}

const obj = {}

Object.assign(obj,o)

console.log(obj)//{name:'佩奇',age:6}

实际上,该方法的经常使用的场景是:给对象添加属性

const o = {name:'佩奇',age:6}

Object.assign(o,{gender:'女'})

console.log(o)//{name:'佩奇',age:6,gender:'女'}

Array

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

const arr = new Array(3,5)
console.log(arr)//[3,5]

创建数组建议使用字面量创建,而不是用Array构造函数创建。const arr = [1,2,3,4,5]

数组的常见实例方法:

image.png

image.png

map:针对每一项,进行数据处理,最终把处理后的每一项返回过来。

reduce:把每一项加起来,最后汇总出一个结果。经常用来求和。

1. reduce()

基本语法:arr.reduce(function(){},起始值)

参数:起始值可以被省略,如果写,就作为第一次累计的起始值。

arr.reduce(function(累计值,当前元素[,索引号][,源数组]){},起始值)

累计值参数:
1.如果有起始值,则以起始值为准,开始累积,累计值=起始值
2.如果没有起始值,则累计值以数组的第一个数组元素,作为起始值开始累计
3.后面每次遍历,就会用后面的数组元素,累计到值里面(类似求和里面的sum)

让【当前元素】加到【累计值】中,最后得到最终的累计值。[]表达的索引号好源数组不是必写的。

const arr = [1,2,3]

arr.reduce(function(累计值,当前元素){},起始值)
let sum = arr.reduce(function(prev,item){
    //把prev看做sum
    //prev + item //实现累加
},0)

执行过程:
prev = 起始值 + item:1 = 1
prev = 1 + item:2 = 3
prev = 3 + item:3 = 6

大多情况下,我们是不写起始值的。如果没有起始值,就拿数组的第一个元素做起始值。

箭头函数的写法:

const re = arr.reduce((prev,item) => prev + item)

console.log(re)//6
课堂案例

image.png

const arr = [{
  name: '张三',
  salary: 10000
}, {
  name: '李四',
  salary: 10000
}, {
  name: '王五',
  salary: 20000
},
]


//求涨薪的钱
arr.reduce(function(prev,item){    
    return prev + item.salary * 0.3
},0)

//求涨薪的钱,箭头函数
arr.reduce((prev,item)=>prev+item.salary*0.3,0)
find()

image.png

image.png

find():返回满足条件的第一个元素的值,否则返回undefined

const arr = ['red','blue','green']
const re = arr.find(function(item){
    return item === 'blue'
})
console.log(re)//有,就返回blue,没找到就返回undefined

常见的情况,数据非常的多,不知道具体某一条数据在数组中哪个位置

const arr = [
    {
        name:'小米',
        price:1999
    },
    {
        name:'华为',
        price:2999
    },
]

//找小米,这个对象,并且返回这个对象
const mi = arr.find(function(item){
    console.log(item)//这个item里面是所有的对象
    return item.name === '小米'
})
console.log(mi)//{name:'小米','price':1999}

返回小米所在的对象

every()

every():每一个是否都满足条件,如果全部都符合,则返回true,否则返回false

const arr1 = [10,20,30]
const flag = arr1.every(item=>item>=10)
console.log(flag)//true

some():只要有一个满足条件,就返回true,否则返回false

const arr1 = [10,20,30]
const flag = arr1.every(item=>item>=30)
console.log(flag)//true
案例

image.png

思路:先获得所有的属性值,然后拼接字符串

  1. 获得所有属性值:Object.values()返回的是数组
  2. 拼接数组是join("")这样就可以转换为字符串了
<div></div>

const spec = { size: '40cm*40cm', color: '黑色' }

document.querySelector('div').innerHTML = spec.Object.values(spec).join('/');
伪数组转换为真数组
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
//lis是一个伪数组
const lis = document.querySelectorAll('ul li')

//pop数组删除方法
//lis.pop 默认伪数组是没有数组常见方法的

//转换为真数组
const liss = Array.from(lis)
liss.pop()

通过Array.from(伪数组)

String

image.png

split

split():将字符串转换为数组。而join()相反:join是将数组转换为字符串

const str = 'pink,red'
cosnt arr = str.split(',')
console.log(arr)//['pink','red']
字符串截取

substring(开始索引,结束索引):字符串截取,结束索引不是必写的。如果不写,就是截取:从开始索引--最后一个。

结束索引:不包含在内:(5,8)从下标5到7,不包含8

const str = "今天又要做核酸了"
str.substring(5)//核酸了
str.substring(5,7)//核酸
startsWith

startsWith():检测是否以某字符开头\

str.startsWith(要检索的字符串,位置):位置可以省略个不写,默认值为0

判断是不是以某个字符开头,如果是则返回true,否则返回false

const str = 'pink老师上课中'
str.startsWith('pink')//true
str.startsWith('ink')//false
includes

includes():区分大小写、判断一个字符串是否包含在另一个字符串中,根据情况返回true或false

const str = '我是pink老师'
console.log(str.includes('pink'))//是否包含pink?true
案例

image.png

image.png

将字符串渲染到准备好的p标签的内部

1.因为标签里面存放的是伪数组,所以我们需要将字符串先拆分成数组:split(',')

2.利用map遍历数组,同时把数组元素生成到span中,并返回

  1. 因为返回的是数组,所以需要转换为字符串:join('')
const gift = '50g的茶叶,清洗球'

//把字符串拆分成数组
console.log(gift.split(','))

//根据数组元素的个数,生成对应的span标签
const arr = gift.split(',').map(function(item){
    return `<span>【赠品】${item}</span><br>`
})

返回的是处理后的一个新数组

image.png

然后将数组转换为字符串,加入进div中

let newarr = arr.join('')

document.querySelector('div').innerHTML = newarr

image.png

箭头函数的写法:

<div></div>

const gift = '50g的茶叶,清洗球'

//转换为数组
const arr = gift.join(',')

arr.map((item)=>{
    return `<span>【赠品】${item}</span><br>`
}).split('')

document.querySelector('div').innerHTML = arr

究极简写:


document.querySelector('div').innerHTML = gift.split(',').map(item=>`<span>【赠品】${item}</span><br>`).join('')`

Number

toFixed():设置保留小数位的长度

默认是返回一个整数,并且四舍五入,参数的多少决定了保留几位小数。

const price = 12.345
const num = 9.97

console.log(price.toFixed())//12
console.log(price.toFixed(2))//12.34保留两位小数

注意:整数也可以保留小数:

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

综合案例

image.png

模块分析:
1.渲染图片、标题、颜色、价格、赠品等数据
2.单价和小计模块
3.总价模块

业务分析:
1.把整体的结构直接生成,然后渲染到大盒子.list里面
2.可以遍历还可以有返回值:map()方法
3.最后计算总价模块,通过reduce()方法来求和

<div class="list">
    ................
  </div>
  <div class="total">
    <div>合计:<span class="amount">1000.00</span></div>
  </div>
  <script>
    const goodsList = [
      {
        id: '4001172',
        name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',
        price: 289.9,
        picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
        count: 2,
        spec: { color: '白色' }
      },
      {
        id: '4001009',
        name: '竹制干泡茶盘正方形沥水茶台品茶盘',
        price: 109.8,
        picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
        count: 3,
        spec: { size: '40cm*40cm', color: '黑色' }
      },
      {
        id: '4001874',
        name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
        price: 488,
        picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
        count: 1,
        spec: { color: '青色', sum: '一大四小' }
      },
      {
        id: '4001649',
        name: '大师监制龙泉青瓷茶叶罐',
        price: 139,
        picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
        count: 1,
        spec: { size: '小号', color: '紫色' },
        gift: '50g茶叶,清洗球,宝马, 奔驰'
      }
    ]
  1. 根据数据渲染页面;利用map遍历数据,可以先写死数据(map返回的是数组,我们需要用join转换为字符串)
//item是每一条对象
document.querySelector('.list').innerHTML = goodsList.map(item=>{
    return 
    `
    <div class="item">
      <img src="https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg" alt="">
      <p class="name">称心如意手摇咖啡磨豆机咖啡豆研磨机 <span class="tag">【赠品】10优惠券</span></p>
      <p class="spec">白色/10寸</p>
      <p class="price">289.90</p>
      <p class="count">x2</p>
      <p class="sub-total">579.80</p>
    </div>
    `
}).join('')
  1. 更换成活数据,采取对象解构的方式,单价要保留2为小数(toFixed(2)
const {picture,name,count,price} = item
return `
    <div class="item">
      <img src="${picture}" alt="">
      <p class="${name}"><span class="tag">【赠品】10优惠券</span></p>
      <p class="spec">白色/10寸</p>
      <p class="price">${price.toFixed(2)}</p>
      <p class="count">x${count}</p>
      <p class="sub-total">579.80</p>
    </div>
    `

模板字符串:一定要小心,不能多打一个空格!

  1. 处理规格文字模块 规格文字模块在goodList中,又用了一个对象包裹:

image.png

获取每个对象里面的spec,上面对象解构添加spec,获得所有属性值是:Object.values(),返回的是数组

const {spec} = item

//得到的是数组,需要转换为字符串
const text = Object.values(spec).join('/')
      
<p class="spec">{text}</p>
  1. 处理赠品模块 获取每个对象里面的gift,上面对象解构添加gift

思路:
先把字符串拆分成数组,这样两个赠品就拆分开了,用split('')
利用map遍历数组,同时把数组元素生成到span里面,并返回
因为返回的是数组,所以需要转换为字符串,用join()

注意要判断是否有gift属性,没有的话就不要渲染,利用变成的字符串,然后写到p.name中

const {gift} = item


//处理赠品模块,这里的item是gift后的字符串
const str = gift ? gift.split(',').map(item>=`<span class = "tag">【赠品】${item}</span>`).join('') : return`
    ...
    <p class = "name">${str}</p>
    ...
`

如果有gift,就map一下,如果没有,就直接渲染

  1. 跟换数据:处理小计模块,小计 = 单价 * 数量
//计算小计模块,单价 * 数量,保留两位小数,所以只需要*100然后/100
const subTotal = ((price * 100 *  count)/100).toFixed(2)

<p>${subTotal}</p>

小数存在的计算问题:解决方案:我们经常转换为整数: (0.1*100+0.2*100)/100 === 0.3

  1. 合计模块
const total =  goodsList.reduce((prev,item)=>prev+(item.price * 100 * item.count)/100,0)

document.querySelector('.amount') = total.toFixed(2)

整合:

  <body>
    <div class="list">
      <!-- <div class="item">
      <img src="https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg" alt="">
      <p class="name">称心如意手摇咖啡磨豆机咖啡豆研磨机 <span class="tag">【赠品】10优惠券</span></p>
      <p class="spec">白色/10寸</p>
      <p class="price">289.90</p>
      <p class="count">x2</p>
      <p class="sub-total">579.80</p>
    </div> -->
    </div>
    <div class="total">
      <div>合计:<span class="amount">1000.00</span></div>
    </div>
    <script>
      const goodsList = [
      {
        id: '4001172',
        name: '称心如意手摇咖啡磨豆机咖啡豆研磨机',
        price: 289.9,
        picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
        count: 2,
        spec: { color: '白色' }
      },
      {
        id: '4001009',
        name: '竹制干泡茶盘正方形沥水茶台品茶盘',
        price: 109.8,
        picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
        count: 3,
        spec: { size: '40cm*40cm', color: '黑色' }
      },
      {
        id: '4001874',
        name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
        price: 488,
        picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
        count: 1,
        spec: { color: '青色', sum: '一大四小' }
      },
      {
        id: '4001649',
        name: '大师监制龙泉青瓷茶叶罐',
        price: 139,
        picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
        count: 1,
        spec: { size: '小号', color: '紫色' },
        gift: '50g茶叶,清洗球,宝马, 奔驰'
      }
    ]
    
    document.querySelector('.list').innerHTML = goodsList.map(item=>{
      // item是goodList中的每一条对象,所以可以直接对象解构
      const {picture,name,price,count,spec,gift} = item
      
      
      // 因为spec中有颜色、有尺码、有总和,但是我们只获取他的values
      // 并且格式是" ../.. 所以转换为字符串的同时,再给一个格式
      const text = Object.values(spec).join('/')

      // 处理赠品,解构后得到的字符串,需要先变成数组才能map
      // gift是否存在?如果存在就map,不存在就渲染空
       const str = gift ? gift.split(',').map(item=>`<span class="tag">【赠品】${item}</span>`).join('') : ''

      return `
      <div class="item">
        <img src="${picture}" alt="">
        <p class="name">${name} ${str}</p>
        <p class="spec">${text}</p>
        <p class="price">${(price.toFixed(2)*100)/100}</p>
        <p class="count">x${count}</p>
        <p class="sub-total">${price*count}</p>
      </div>
    `
    }).join('')
      // 写join,因为每个数组之间都有逗号分割,页面渲染就会有逗号,所以转换成字符串是最好的结果

      //合计模块 
      const total =  goodsList.reduce((prev,item)=>prev+((item.price*100)*item.count)/100,0)

      document.querySelector('.amount').innerHTML = total.toFixed(2)
    </script>
  </body>