构造函数&数据常用函数
JavaScript构造函数&数据常用函数
以下为学习过程中的极简提炼笔记,以供重温巩固学习
准备工作
- 已完成JavaScript前面10节学习
学习目的
- 掌握基于构造函数创建对象,理解实例化过程
- 掌握对象数组字符数字等类型的常见属性和方法,便捷完成功能
了解面向对象编程的基础概念及构造函数的作用 体会 JavaScript 一切皆对象的语言特征 掌握各引用类型和包装类型对象属性和方法的使用
深入对象
- 理解引用对象类型值存储的的特征
- 掌握包装类型对象常见方法的使用
创建对象
创建对象有三种方式
- 利用对象字面量创建对象
<script>
const o = {
name: '佩奇'
}
</script>- 利用 new Object 创建对象
<script>
const o = new Object ({
name: '佩奇'
})
</script>语法格式案例
<body>
<script>
// const obj = new Object()
// obj.uname = 'pink老师'
// console.log(obj)
const obj = new Object({ uname: 'pink' })
console.log(obj)
</script>
</body>- 利用 构造函数 创建对象
构造函数
构造函数是专门用于创建对象/初始化对象的函数 如果一个函数使用 new 关键字调用,那么这个函数就是构造函数
<script>
// 定义函数
function foo() {
console.log('通过 new 也能调用函数...');
}
// 调用函数
new foo;
</script>使用场景: 常规的 {...} 语法允许创建一个对象。比如我们创建了佩奇的对象,继续创建乔治的对象还需要重新写一遍 此时可以通过构造函数来快速创建多个类似的对象
<script>
// 常规对象创建
// 创建Peppa对象
const Peppa = {
name: '佩奇',
age: 6,
gender: '女'
}
// 创建George对象
const George = {
name: '乔治',
age: 3,
gender: '男'
}
// 创建Mum对象
const Mum = {
name: '猪妈妈',
age: 30,
gender: '女'
}
// 创建Dad对象
const Dad = {
name: '爸爸',
age: 32,
gender: '男'
}
// 通过构造函数,一次性创建
// 1.创建新对象
function Pig(name,age,gender){
// 2.构造函数this指向新对象
this.name = name
this.age = age
this.gender = gender
}
// 3.new关键字调用函数,执行构造函数代码,修改this,添加新的属性
const Peppa = new Pig('佩奇',6,'女')
const George = new Pig('乔治',3,'男')
const Mum = new Pig('猪妈妈',30,'女')
const Dad = new Pig('猪爸爸',32,'男')
// 4.返回新对象
console.log(Peppa)
</script>总结:
- 命名以大写字母开头
- 只能由
new操作符执行 - 使用
new关键字调用函数的行为被称为实例化 - 实例化构造函数时没有参数时可以省略
() - 构造函数内部无需写
return返回值即为新创建的对象 - new Object() new Date() 也是实例化构造函数
注:实践中为了从视觉上区分构造函数和普通函数,习惯将构造函数的首字母大写。
构造函数-实例成员
通过构造函数创建的对象称为实例对象 实例对象中的属性和方法称为实例成员
<script>
// 构造函数
function Person() {
// 构造函数内部的 this 就是实例对象
// 实例对象中动态添加属性
this.name = '小明'
// 实例对象动态添加方法
this.sayHi = function () {
console.log('大家好~')
}
}
// 实例化,p1 是实例对象
// p1 实际就是 构造函数内部的 this
const p1 = new Person()
console.log(p1)
console.log(p1.name) // 访问实例属性 打印小明
p1.sayHi() // 调用实例方法 打印大家好
</script>总结:
- 构造函数内部
this实际上就是实例对象,为其动态添加的属性和方法即为实例成员 - 为构造函数传入参数,动态创建结构相同但值不同的对象
注:构造函数创建的实例对象彼此独立互不影响。
构造函数-静态成员
在 JavaScript 中底层函数本质上也是对象类型 因此允许直接为函数动态添加属性或方法 构造函数的属性和方法被称为静态成员
<script>
// 构造函数
function Person(name, age) {
// 省略实例成员
}
// 静态属性
Person.eyes = 2
Person.arms = 2
// 静态方法
Person.walk = function () {
console.log('^_^人都会走路...')
// this 指向 Person
console.log(this.eyes)
}
</script>总结:
- 静态成员指的是添加到构造函数本身的属性和方法
- 一般公共特征的属性或方法静态成员设置为静态成员
- 静态成员方法中的
this指向构造函数本身
语法格式案例
<body>
<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)
// const pepa = { uname: '佩奇', age: 6 }
// const obj = new Object()
function Goods(name, price, count) {
this.name = name
this.price = price
this.count = count
this.sayhi = function () { }
}
const mi = new Goods('小米', 1999, 20)
console.log(mi)
const hw = new Goods('华为', 3999, 59)
console.log(hw)
console.log(mi === hw)
mi.name = 'vivo'
console.log(mi)
console.log(hw)
// const date = new Date('2022-4-8')
// console.log(date)
// 静态成员
Goods.num = 10
console.log(Goods.num)
Goods.sayhi = function () { }
</script>
</body>内置构造函数
掌握各引用类型和包装类型对象属性和方法的使用。
在 JavaScript 中最主要的数据类型有 6 种,分别是字符串、数值、布尔、undefined、null 和 对象
JS中几乎所有的数据都可以基于构成函数创建
基本数据类型:(也被称为简单类型或基础类型)
- 字符串
- 数值
- 布尔
- undefined
- null
其实字符串、数值、布尔、等基本类型也都有专门的构造函数,这些我们称为包装类型
包装类型包括:
- String,Number,Boolean 等
引用类型:
- 对象
常见的对象类型数据包括:数组和普通对象
引用类型包括:
- Object,Array,RegExp,Date 等
JavaScript 基础阶段学习的 Date 就是内置的构造函数
<script>
// 实例化
let date = new Date();
// date 即为实例对象
console.log(date);
</script>语法格式案例
<body>
<script>
const str = 'pink'
console.log(str.length)
const num = 12
console.log(num.toFixed(2))
const str = 'pink'
// js 底层完成, 把简单数据类型包装为了引用数据类型
const str = new String('pink')
</script>
</body>Object
Object 是内置的构造函数,用于创建普通对象
<script>
// 通过构造函数创建普通对象
const user = new Object({name: '小明', age: 15})
// 这种方式声明的变量称为【字面量】,推荐使用字面量方式声明对象
let student = {name: '杜子腾', age: 21}
// 对象语法简写
let name = '小红';
let people = {
// 相当于 name: name
name,
// 相当于 walk: function () {}
walk () {
console.log('人都要走路...');
}
}
console.log(student.constructor);
console.log(user.constructor);
console.log(student instanceof Object);
</script>学习三个常用静态方法(静态方法就是只有构造函数Object可以调用的)
- 推荐使用字面量方式声明对象,而不是
Object构造函数 Object.keys静态方法获取对象中所有属性Object.values静态方法获取对象中所有属性值Object.assign静态方法用于对象拷贝,以创建新的对象,经常在 给对象添加属性 的场景使用
<script>
// 1 user这个对象里面有name和age属性
const user = {name: '小明', age: 15}
// 2.1 获得对象的所有属性键,并返回一个数组
const arr = Object.keys(user)
console.log(arr) //得到数组['name','age']
// 2.2 获得对象的所有属性值,并返回一个数组
const arr = values(user)
console.log(arr) //得到数组['小明','15']
// 2.3 将 user 对象 拷贝给 obj
const obj = {}
Object.assign(obj,name)
console.log(obj) //得到新对象obj = 对象属性{name: '小明', age: 15}
// 2.4 将 user 对象 添加属性
Object.assign(o,{gender: '男'}) // (新对象,{需要增加的属性})
console.log(o) //得到增加属性后的新对象 o = 对象属性{name: '小明', age: 15,gender:'男'}
</script>语法格式案例
<body>
<script>
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('/')
</script>
</body>注意:Object.keys 和 Object.values 返回的是一个数组
Array
Array 是内置的构造函数,用于创建数组。
<script>
// 构造函数创建数组
let arr = new Array(5, 7, 8);
// 字面量方式创建数组
let list = ['html', 'css', 'javascript']
</script>创建数组建议使用字面量创建,不用 Array构造函数创建 数组赋值后,无论修改哪个变量另一个对象的数据值也会相当发生改变。
reduce 方法返回函数累计处理的结果,经常用于求和等
<script>
arr.reduce(function(){},起始值)
// 起始值可以省略,如果写就作为第一次累计的起始值
// reduce 返回函数累计处理的结果,经常用于求和等
arr.reduce(function(累计值,当前元素[,索引号][,源数组]){},起始值)
// 1. 如果有起始值,则以起始值为准开始累计, 累计值 = 起始值
// 2. 如果没有起始值, 则累计值以数组的第一个数组元素作为起始值开始累计
// 3. 后面每次遍历就会用后面的数组元素 累计到 累计值 里面 (类似求和里面的 sum )
// 求和案例
const arr = [1,5,9]
const count = arr.reduce((prev,item) => prev + item)
console.log(count)
</script>总结:
推荐使用字面量方式声明数组,而不是
Array构造函数实例方法
forEach用于遍历数组,替代for循环 (重点) 不返回,用于不改变值,经常用于查找打印输出值实例方法
filter过滤数组单元值,筛选数组元素,并生成新数组(重点)实例方法
map迭代原数组,生成新数组,新数组里面的元素是处理之后的值,经常用于处理数据(重点)实例方法
reduce累计器,返回函数累计处理的结果,经常用于求和等实例方法
join数组元素拼接为字符串,返回字符串(重点)实例方法
find查找元素, 返回符合测试条件的第一个数组元素值,如果没有符合条件的则返回 undefined(重点)实例方法
every检测数组所有元素是否都符合指定条件,如果所有元素都通过检测返回 true,否则返回 false(重点)实例方法
some检测数组中的元素是否满足指定条件 如果数组中有元素满足条件返回 true,否则返回 false实例方法
concat合并两个数组,返回生成新数组实例方法
sort对原数组单元值排序实例方法
splice删除或替换原数组单元实例方法
reverse反转数组实例方法
findIndex查找元素的索引值
语法格式案例
<body>
<script>
// arr.reduce(function(累计值, 当前元素){}, 起始值)
// arr.reduce(function (prev, item) {
// // console.log(11)
// // console.log(prev)
// return prev + item
// }, 0)
// arr.reduce(function (prev, item) {
// console.log(11)
// // console.log(prev)
// return prev + item
// })
const arr = [1, 2, 3]
const re = arr.reduce((prev, item) => prev + item)
console.log(re)
</script>
</body>语法格式案例
<body>
<script>
const arr = [{
name: '张三',
salary: 10000
}, {
name: '李四',
salary: 10000
}, {
name: '王五',
salary: 20000
},
]
// 涨薪的钱数 10000 * 0.3
// const money = arr.reduce(function (prev, item) {
// return prev + item.salary * 0.3
// }, 0)
const money = arr.reduce((prev, item) => prev + item.salary * 0.3, 0)
console.log(money)
</script>
</body>语法格式案例
<body>
<script>
// const arr = ['red', 'blue', 'green']
// const re = arr.find(function (item) {
// return item === 'blue'
// })
// console.log(re)
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 === '华为'
// })
// 1. find 查找
// const mi = arr.find(item => item.name === '小米')
// console.log(mi)
// 2. every 每一个是否都符合条件,如果都符合返回 true ,否则返回false
const arr1 = [10, 20, 30]
const flag = arr1.every(item => item >= 20)
console.log(flag)
</script>
</body>数组常见方法 - 伪数组转换为真数组
静态方法 Array.from()
语法格式案例
<body>
<script>
// Array.from(lis) 把伪数组转换为真数组
const lis = document.querySelectorAll('ul li')
// console.log(lis)
// lis.pop() 报错
const liss = Array.from(lis)
liss.pop()
console.log(liss)
</script>
</body>包装类型
在 JavaScript 中的字符串、数值、布尔具有对象的使用特征,如具有属性和方法,如下代码举例:
<script>
// 字符串类型
const str = 'hello world!'
// 统计字符的长度(字符数量)
console.log(str.length)
// 数值类型
const price = 12.345
// 保留两位小数
price.toFixed(2) // 12.34
</script>之所以具有对象特征的原因是字符串、数值、布尔类型数据是 JavaScript 底层使用 Object 构造函数“包装”来的,被称为包装类型
构造函数 String
String 是内置的构造函数,用于创建字符串
<script>
// 使用构造函数创建字符串
let str = new String('hello world!');
// 字面量创建字符串
let str2 = '你好,世界!';
// 检测是否属于同一个构造函数
console.log(str.constructor === str2.constructor); // true
console.log(str instanceof String); // false
</script>总结:
- 实例属性
length用来获取字符串的度长(重点) - 实例方法
split('分隔符')用来将字符串拆分成数组(重点) - 实例方法
substring(需要截取的第一个字符的索引[,结束的索引号])用于字符串截取(重点) - 实例方法
startsWith(检测字符串[, 检测位置索引号])检测是否以某字符开头(重点) - 实例方法
includes(搜索的字符串[, 检测位置索引号])判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false(重点) - 实例方法
toUpperCase用于将字母转换成大写 - 实例方法
toLowerCase用于将就转换成小写 - 实例方法
indexOf检测是否包含某字符 - 实例方法
endsWith检测是否以某字符结尾 - 实例方法
replace用于替换字符串,支持正则匹配 - 实例方法
match用于查找字符串,支持正则匹配
注:String 也可以当做普通函数使用,这时它的作用是强制转换成字符串数据类型。
语法格式案例
<body>
<script>
//1. split 把字符串 转换为 数组 和 join() 相反
// const str = 'pink,red'
// const arr = str.split(',')
// console.log(arr)
// const str1 = '2022-4-8'
// const arr1 = str1.split('-')
// console.log(arr1)
// 2. 字符串的截取 substring(开始的索引号[, 结束的索引号])
// 2.1 如果省略 结束的索引号,默认取到最后
// 2.2 结束的索引号不包含想要截取的部分
// const str = '今天又要做核酸了'
// console.log(str.substring(5, 7))
// 3. startsWith 判断是不是以某个字符开头
// const str = 'pink老师上课中'
// console.log(str.startsWith('pink'))
// 4. includes 判断某个字符是不是包含在一个字符串里面
const str = '我是pink老师'
console.log(str.includes('pink')) // true
</script>
</body>语法格式案例
<body>
<script>
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('')
</script>
</body>String 方法小案例,思路: ①:把字符串拆分为数组,这样两个赠品就拆分开了 用那个方法? //split(‘,’) ②:利用map遍历数组,同时把数组元素生成到span里面,并且返回 ③:因为返回的是数组,所以需要 转换为字符串, 用那个方法? //join(‘’) ④:p的innerHTML 存放刚才的返回值
构造函数 Number
Number 是内置的构造函数,用于创建数值
<script>
// 使用构造函数创建数值
let x = new Number('10')
let y = new Number(5)
// 字面量创建数值
let z = 20
</script>总结:
- 推荐使用字面量方式声明数值,而不是
Number构造函数 - 实例方法
toFixed用于设置保留小数位的长度
语法格式案例
<body>
<script>
// toFixed 方法可以让数字指定保留的小数位数
const num = 10.923
// console.log(num.toFixed())
console.log(num.toFixed(1))
const num1 = 10
console.log(num1.toFixed(2))
</script>
</body>语法格式案例
<body>
<script>
const num = 10
console.log(String(num))
console.log(num.toString())
</script>
</body>综合案例
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.list {
width: 990px;
margin: 100px auto 0;
}
.item {
padding: 15px;
transition: all .5s;
display: flex;
border-top: 1px solid #e4e4e4;
}
.item:nth-child(4n) {
margin-left: 0;
}
.item:hover {
cursor: pointer;
background-color: #f5f5f5;
}
.item img {
width: 80px;
height: 80px;
margin-right: 10px;
}
.item .name {
font-size: 18px;
margin-right: 10px;
color: #333;
flex: 2;
}
.item .name .tag {
display: block;
padding: 2px;
font-size: 12px;
color: #999;
}
.item .price,
.item .sub-total {
font-size: 18px;
color: firebrick;
flex: 1;
}
.item .price::before,
.item .sub-total::before,
.amount::before {
content: "¥";
font-size: 12px;
}
.item .spec {
flex: 2;
color: #888;
font-size: 14px;
}
.item .count {
flex: 1;
color: #aaa;
}
.total {
width: 990px;
margin: 0 auto;
display: flex;
justify-content: flex-end;
border-top: 1px solid #e4e4e4;
padding: 20px;
}
.total .amount {
font-size: 18px;
color: firebrick;
font-weight: bold;
margin-right: 50px;
}
</style>
</head>
<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茶叶,清洗球,宝马, 奔驰'
}
]
// 1. 根据数据渲染页面
document.querySelector('.list').innerHTML = goodsList.map(item => {
// console.log(item) // 每一条对象
// 对象解构 item.price item.count
const { picture, name, count, price, spec, gift } = item
// 规格文字模块处理
const text = Object.values(spec).join('/')
// 计算小计模块 单价 * 数量 保留两位小数
// 注意精度问题,因为保留两位小数,所以乘以 100 最后除以100
const subTotal = ((price * 100 * count) / 100).toFixed(2)
// 处理赠品模块 '50g茶叶,清洗球'
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)}</p>
<p class="count">x${count}</p>
<p class="sub-total">${subTotal}</p>
</div>
`
}).join('')
// 3. 合计模块
const total = goodsList.reduce((prev, item) => prev + (item.price * 100 * item.count) / 100, 0)
// console.log(total)
document.querySelector('.amount').innerHTML = total.toFixed(2)
</script>
</body>分析业务模块: ①:把整体的结构直接生成然后渲染到大盒子.list 里面 ②:那个方法可以遍历的同时还有返回值 //map 方法 ③:最后计算总价模块,那个方法可以求和? //reduce 方法
分析业务模块: ①:先利用map来遍历,有多少条数据,渲染多少相同商品
- 可以先写死的数据
- 注意map返回值是 数组,我们需要用 join 转换为字符串
- 把返回的字符串 赋值 给 list 大盒子的 innerHTML ②:里面更换各种数据,注意使用对象解构赋值
- 更换数据
- 先更换不需要处理的数据,图片,商品名称,单价,数量
- 采取对象解构的方式
- 注意 单价要保留2位小数, 489.00 toFixed(2)
- 更换数据 - 处理 规格文字 模块
- 获取 每个对象里面的 spec , 上面对象解构添加 spec
- 获得所有属性值是: Object.values() 返回的是数组
- 拼接数组是 join(‘’) 这样就可以转换为字符串了
- 更换数据 - 处理 赠品 模块
- 获取 每个对象里面的 gift , 上面对象解构添加 gift
- ①:把字符串拆分为数组,这样两个赠品就拆分开了 用那个方法? //split(‘,’)
- ②:利用map遍历数组,同时把数组元素生成到span里面,并且返回
- ③:因为返回的是数组,所以需要 转换为字符串, 用那个方法? //join(‘’)
- 注意要判断是否有gif属性,没有的话不需要渲染
- 利用变成的字符串然后写到 p.name里面
- 更换数据 - 处理 小计 模块
- 小计 = 单价 * 数量
- 小计名可以为: subTotal = price * count
- 注意保留2位小数 关于小数的计算精度问题: 0.1 + 0.2 = ? 解决方案: 我们经常转换为整数 (0.1100 + 0.2100)/ 100 === 0.3 这里是给大家拓展思路和处理方案 ③:利用reduce计算总价
- 计算 合计 模块
- 求和用到数组 reduce 方法 累计器
- 根据数据里面的数量和单价累加和即可
- 注意 reduce方法有2个参数,第一个是回调函数,第二个是 初始值,这里写 0
