JavaScript 进阶 - 构造函数&数据常用函数
了解面向对象编程的基础概念及构造函数的作用,体会 JavaScript 一切皆对象的语言特征,掌握常见的对象属性和方法的使用。
- 了解面向对象编程中的一般概念
- 能够基于构造函数创建对象
- 理解 JavaScript 中一切皆对象的语言特征
- 理解引用对象类型值存储的的特征
- 掌握包装类型对象常见方法的使用
深入对象
创建对象三种方法
1,利用对象字面量创建对象
<script>
const o = {
name:'佩奇'
}
</script>
2.利用new Object创建对象
<script>
const o = new Object({name:'佩奇'})
console.log(o) //{name:'佩奇'}
</script>
3.利用构造函数创建对象
构造函数
构造函数:是一种特殊的函数,快速创建多个类似的对象 使用场景:常规的 {...} 语法允许创建一个对象。比如我们创建了佩奇的对象,继续创建乔治的对象还需要重新写一 遍,此时可以通过构造函数来快速创建多个类似的对象。 两个约定:
- 它们的命名以大写字母开头。
- 它们只能由
new操作符来执行。
<script>
function Pig (uname ,age) {
this.name = uname
this.age = age
}
// console.log(new Pig('佩奇' , 9))
const p = new Pig('佩奇' , 9)
console.log(p) //Pig {name: '佩奇', age: 9}
</script>
总结:
- 使用
new关键字调用函数的行为被称为实例化 - 实例化构造函数时没有参数时可以省略
() - 构造函数的返回值即为新创建的对象
- 构造函数内部的
return返回的值无效!
注:实践中为了从视觉上区分构造函数和普通函数,习惯将构造函数的首字母大写。
练习:利用构造函数创建多个对象、
需求:
- 写一个Goods构造函数
- 里面包含属性 name 商品名称 price 价格 count 库存数量
- 实例化多个商品对象,并打印到控制台
例如 小米 1999 20 华为 3999 59 vivo 1888 100
<script>
function Goods(name,price,count){
this.name = name
this.price = price
this.count = count
}
const xiaomi = new Goods('小米',"1999","20")
const huawei = new Goods('华为',"3999","59")
const vivo = new Goods('vivo',"1888","100")
console.log(xiaomi) //Goods {name: '小米', price: '1999', count: '20'}
console.log(huawei) //Goods {name: '华为', price: '3999', count: '59'}
console.log(vivo) //Goods {name: 'vivo', price: '1888', count: '100'}
</script>
实例成员
通过构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员。
<script>
//【实例成员】:[实例对象]上的属性和方法属于实例对象
function Pig(name){
this.name = name
}
//【1】为构造函数传入参数,动态创建结构相同但值不同的对象
const peiqi = new Pig('佩奇')
const qiaozhi = new Pig('乔治')
//【2】构造函数创建的【实例对象】彼此独立互不影响
peiqi.name = '小猪佩奇' //实例属性
peiqi.sayHi = () =>{
console.log('hi~')
}
console.log(peiqi) //Pig {name: '小猪佩奇', sayHi: ƒ}
console.log(qiaozhi) //Pig {name: '乔治'}
console.log(peiqi === qiaozhi) //false
</script>
总结:
- 构造函数内部
this实际上就是实例对象,为其动态添加的属性和方法即为实例成员 - 为构造函数传入参数,动态创建结构相同但值不同的对象
注:构造函数创建的实例对象彼此独立互不影响。
静态成员
在 JavaScript 中底层函数本质上也是对象类型,因此允许直接为函数动态添加属性或方法,构造函数的属性和方法被称为静态成员。
<script>
function Pig(name){
this.name = name
}
Pig.eyes = 2 //静态属性
// 静态成员方法中的 this 指向构造函数本身
Pig.sayHi = function(){ //静态方法
console.log(this)
}
Pig.sayHi() //Pig
console.log(Pig.eyes) //2
</script>
总结:
- 静态成员指的是添加到构造函数本身的属性和方法
- 一般公共特征的属性或方法静态成员设置为静态成员
- 静态成员方法中的
this指向构造函数本身
内置构造函数
掌握各引用类型和包装类型对象属性和方法的使用。
在 JavaScript 中最主要的数据类型有 6 种:
基础数据类型: 分别是字符串、数值、布尔、undefined、null
引用类型: 对象
-
引用类型:Object,Array,RegExp,Date 等
-
包装类型:String,Number,Boolean 等
包装类型
问题来了: 字符串str , 数值num这些简单数据类型应该不能用方法,但却可以用
<script>
const str = 'pink'
console.log(str.length); //4
const num = 12
console.log(num.toFixed(2)); //12.00
// 其实字符串、数值、布尔、等基本类型也都有专门的构造函数,这些我们称为包装类型。
// const str1 = 'pink'
// js 底层完成, 把简单数据类型包装为了引用数据类型
const str1 = new String('pink')
</script>
在 JavaScript 中的字符串、数值、布尔具有对象的使用特征,如具有属性和方法.
之所以具有对象特征的原因是字符串、数值、布尔类型数据是 JavaScript 底层使用 Object 构造函数“包装”来的,被称为包装类型。
引用类型:Object,Array,RegExp,Date 等 包装类型:String,Number,Boolean 等
Object
Object 是内置的构造函数,用于创建普通对象。
推荐使用字面量方式声明对象,而不是 Object 构造函数。
<script>
// 通过构造函数创建普通对象
const user = new Object({name: '小明', age: 15})
// 这种方式声明的变量称为【字面量】
const o = {uname:'pink',age:18}
//【1 keys】获取所有的属性名
console.log(Object.keys(o)) //返回数组['uname', 'age']
//【2 values】获取所有的属性值
console.log(Object.values(o)) //['pink', 18]
//【3 assign】对象的拷贝
const oo = {} //空的,拷贝得到内容的那个
Object.assign(oo ,o)
console.log(oo) //{uname: 'pink', age: 18}
// 经常使用的场景给对象添加属性
Object.assign(o,{gender:'女'})
console.log(o) //{uname: 'pink', age: 18, gender: '女'}
</script>
。
总结:
- 推荐使用字面量方式声明对象,而不是
Object构造函数 Object.assign()静态方法创建新的对象Object.keys()静态方法获取对象中所有属性Object.values()表态方法获取对象中所有属性值
Array
Array 是内置的构造函数,用于创建数组。
创建数组建议使用字面量创建,不用 Array构造函数创建
核心方法:
| 方法 | 作用 | 说明 |
|---|---|---|
| forEach | 遍历数组 | 不返回,不改变值,用于查找打印打印输出值 |
| filter | 过滤数组 | 筛选数组元素,并生成新数组 |
| map | 迭代数组 | 返回新数组,新数组里面的的元素是处理之后的值 |
| reduce | 累计器 | 返回函数累计处理的结果,常用于求和等 |
<script>
// arr.reduce(function(累计值,当前元素){},起始值)
//【有初始值 =0 】
arr.reduce(function(prey,item){
console.log(prey)
return prey+item
},0)
// 【无初始值】
arr.reduce(function(prey,item){
console.log(prey)
return prey+item
})
// 【例子,用箭头函数来简化函数表达式】
const arr = [1,2,3]
const re =arr.reduce((prey,item) => prey+item)
console.log(re) //6
</script>
案例-员工涨薪计算成本
需求
- 给员工每人涨薪 30%
- 然后计算需要支出的费用
<script>
const arr = [{
name: '张三',
salary: 10000
}, {
name: '李四',
salary: 10000
}, {
name: '王五',
salary: 20000
},]
//给员工每人涨薪 30%
const money = arr.reduce(function(prev,current){
return prev + current.salary*1.3
},0)
//【箭头函数,简化函数表达式】
// const money = arr.reduce((prev,current) => prev += current.salary*1.3,0)
console.log(money) //12000
</script>
数组常见方法-其他方法(详情见MDN)
- 实例方法
join数组元素拼接为字符串,返回字符串(重点) - 实例方法
find查找元素, 返回符合测试条件的第一个数组元素值,如果没有符合条件的则返回 undefined(重点) - 实例方法
every检测数组所有元素是否都符合指定条件,如果所有元素都通过检测返回 true,否则返回 false(重点) - 实例方法
some检测数组中的元素是否满足指定条件 如果数组中有元素满足条件返回 true,否则返回 false - 实例方法
concat合并两个数组,返回生成新数组 - 实例方法
sort对原数组单元值排序 - 实例方法
splice删除或替换原数组单元 - 实例方法
reverse反转数组 - 实例方法
findIndex查找元素的索引值
<script>
//【find() 查找元素 】
const arr = ['red','blue','green']
const re = arr.find(function(item){
return item === 'blue'
})
console.log(re) //blue
const arr1 = [{
name: '小米',
price: 1999
},{
name: '华为',
price: 3999
},]
// 找小米 这个对象,并且返回这个对象
const mi = arr1.find(function(item){
/* console.log(item) //{name: '小米', price: 1999}
console.log(item.name) //小米 */
return item.name === '小米'
})
console.log(mi) //{name: '小米', price: 1999}
// [箭头函数]
const mii = arr1.find(item => item.name === '小米')
console.log(mii) //{name: '小米', price: 1999}
// 【every】每一个是否都符合条件,如果都符合返回 true ,否则返回false
const arr2 = [10,20,30]
const flag = arr2.every(item => item >= 20)
console.log(flag) //false
</script>
案例-join()案例-40cm*40cm/黑色
const spec = { size: '40cm*40cm' , color: '黑色'}
请将里面的值写到div标签里面,展示内容如下:
<body>
<div></div>
<script>
const spec = {size:'40cm*40cm',color:'黑色'}
// 1,获取属性值,Object.values() 返回的是数组
console.log(Object.values(spec)) // ['40cm*40cm', '黑色']
// 2转换成字符串,数组join('/')把数组根据分隔符转换为字符串
console.log(Object.values(spec).join('/')) //40cm*40cm/黑色
document.querySelector('div').innerHTML = Object.values(spec).join('/')
</script>
</body>
案例-join()案例---伪数组转换为真数组
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
// 静态方法Array.from() 把伪数组转换为真数组
const lis = document.querySelectorAll('ul li')
// console.log(lis) //NodeList(3) [li, li, li]
// lis.pop() //报错
const liss = Array.from(lis)
liss.pop()
console.log(liss) //[li, li]
</script>
</body>
String
String 是内置的构造函数,用于创建字符串。
<script>
//【1】split 把字符串 转换成 数组。和join()相反
const str = 'pink,red'
const arr = str.split(',')
console.log(arr) //['pink', 'red']
const str1 = '2022-4-8'
const arr1 = str1.split('-')
console.log(arr1) //['2022', '4', '8']
//【2】字符串的截取 substring(开始的索引号[,结束的索引号])
// 如果省略[结束的索引号],默认取到最后,[结束的索引号]不包含想要截取的部分
const str2 = '今年也是努力学习的一天啊'
console.log(str2.substring(4,8))
//【3】startWith判断是不是以某个字符开头
const str3 = 'i今年也是努力学习的一天啊'
console.log(str3.startsWith('i')) //true
//【4】include 判断某个字符是不是包含在一个字符串里面
const str4 = '今年也是努力学习learn的一天啊'
console.log(str4.includes('学习')) //true
</script>
总结:
- 实例属性
length用来获取字符串的度长(重点) - 实例方法
split('分隔符')用来将字符串拆分成数组(重点) - 实例方法
substring(需要截取的第一个字符的索引[,结束的索引号])用于字符串截取(重点) - 实例方法
startsWith(检测字符串[, 检测位置索引号])检测是否以某字符开头(重点) - 实例方法
includes(搜索的字符串[, 检测位置索引号])判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false(重点) - 实例方法
toUpperCase用于将字母转换成大写 - 实例方法
toLowerCase用于将就转换成小写 - 实例方法
indexOf检测是否包含某字符 - 实例方法
endsWith检测是否以某字符结尾 - 实例方法
replace用于替换字符串,支持正则匹配 - 实例方法
match用于查找字符串,支持正则匹配
注:String 也可以当做普通函数使用,这时它的作用是强制转换成字符串数据类型。
<script>
const num = 10
console.log(String(num))
console.log(num.toString())
</script>
案例-显示赠品练习
- 把字符串拆分为数组,这样两个赠品就拆分开了 用那个方法? split(‘ , ’)
- 利用map遍历数组,同时把数组元素生成到span里面,并且返回
- 因为返回的是数组,所以需要 转换为字符串, 用那个方法? join(‘’)
- p的innerHTML 存放刚才的返回值
<script>
const gift = '50g茶叶,清洗球'
//【1】把字符串拆分成数组
console.log(gift.split(',')) // ['50g茶叶', '清洗球']
//【2】根据数组元素的个数,生成对应 span 标签
const str = gift.split(',').map(function(item){
return `<span>【赠品】${item}</span><br>`
}).join('')
document.querySelector('div').innerHTML = str
//【简写】
document.querySelector('div').innerHTML = gift.split(',').map((item) => `<span>【赠品】${item}</span><br>`).join('')
</script>
Number
Number 是内置的构造函数,用于创建数值。
常用方法: toFixed() 设置保留小数位的长度
<script>
// 使用构造函数创建数值
let x = new Number('10')
let y = new Number(5)
// 字面量创建数值
const num = 10.12
console.log(num.toFixed()) //10
console.log(num.toFixed(1)) //10.1
const num1 = 10
console.log(num1.toFixed(2)) //10.00
</script>
总结:
- 推荐使用字面量方式声明数值,而不是
Number构造函数 - 实例方法
toFixed用于设置保留小数位的长度
案例——购物车
分析业务模块:
- 渲染图片、标题、颜色、价格、赠品等数据
先利用map来遍历,有多少条数据,渲染多少相同商品
- 可以先写死的数据
- 注意map返回值是 数组,我们需要用 join 转换为字符串
- 把返回的字符串 赋值 给 list 大盒子的 innerHTML
- 单价和小计模块
更换数据
- 先更换不需要处理的数据,图片,商品名称,单价,数量
- 采取对象解构的方式
- 注意 单价要保留2位小数, 489.00 toFixed(2)
更换数据 - 处理 规格文字 模块
- 获取 每个对象里面的 spec , 上面对象解构添加 spec
- 获得所有属性值是: Object.values() 返回的是数组
- 拼接数组是 join(‘’) 这样就可以转换为字符串了
更换数据 - 处理 赠品 模块
- 获取 每个对象里面的 gift , 上面对象解构添加 gift(详情见上面练习)
- 注意要判断是否有gif属性,没有的话不需要渲染
- 利用变成的字符串然后写到 p.name里面
:更换数据 - 处理 小计 模块
- 小计 = 单价 * 数量
- 小计名可以为: subTotal = price * count
- 注意保留2位小数
- 关于小数的计算精度问题: 0.1 + 0.2 = ?
- 解决方案: 我们经常转换为整数 (0.1100 + 0.2100)/ 100 === 0.3
- 总价模块
- 求和用到数组 reduce 方法 累计器
- 根据数据里面的数量和单价累加和即可
- 注意 reduce方法有2个参数,第一个是回调函数,第二个是 初始值,这里写 0