深入对象
注意 ,这里的感叹号和doctype间不要加空格。
创建对象的三种方式
注意对象里面得用单引号把字符包起来
第一种就是我们常用的字面量创造对象
第二种是new Object创造对象,其中我们可以直接在括号内添加对象
第三种就是构造函数,其实用newObject()也是一种构造函数,只是官方固定了写法
构造函数
1-构造函数是一个特殊的函数,它的作用是初始化对象,通过它可以快速生成多个有相同属性类似的对象。
2-行业约定,构造函数名称首字母大写,必须用new操作符来执行。
<script>
function Awesome(name,age){
this.name = name
this.age = age
}
console.log(new Awesome('zdq',20))
</script>
this.name =name,后面那个是形参,前面那个是对象的属性,其中this谁调用就是谁。这里是创造对象,所以这个this就是创造的那个对象。
这个name随便你命名的,属性和参数一般写成一样,便于使用区分
构造函数里面不要写return返回值,写了也无效,因为构造函数默认返回生成的对象。
当构造函数没有参数,小括号可以省略,一般不省
new关键字调用函数的行为就叫做实例化
<script>
function Goods(name, price, count) {
this.name = name
this.price = price
this.count = count
}
console.log(new Goods('小米', 1999, 20))
console.log(new Goods('小米', 3999, 50))
const hw = new Goods('小米', 5999, 100)
console.log(hw)
</script>
实例化执行过程
为什么this就是那个生成的对象?用上面的代码做讲解
1-我们起初写了一个构造函数
function Goods(name, price, count) {
this.name = name
this.price = price
this.count = count
}
2-虽然写了函数,但是不调用它是不执行的。所以我们要调用
const hw = new Goods('小米', 5999, 100)
new Goods(‘小米’, 5999, 100)就等于调用了,注意因为这里是构造函数,所以必须加上new关键字
3-当调用后,就会立马自动生成一个空对象,所以函数里面的this是指向这个空对象的
4-因为我们调用函数的时候,里面写了参数,所以这个时候就会为对象添加新的属性方法等。
5-最后这个构造函数会返回生成的这个新对象。
实例成员&静态成员
1-通过构造函数生成的对象叫做实例对象,这个实例对象里面的方法和属性叫做实例成员。
上面的hw就是实例对象,this.name就是实例成员
2-构造函数的方法和属性叫做静态成员,如下直接给函数添加方法和属性(这个函数也是一个对象)
Goods.num = 10
Goods.sayhi=function(){}
内置的构造函数
const str = 'pink'
console.log(str.length)
const num = 12
console.log(num.toFixed(2))
如上,为什么这基本的简单数据类型也有对象一样的 方法和属性呢?
因为js底层给它们进行了包装,都实例化了一次,当你写了一段代码
const str = 'zdq'
底层执行的是一个构造函数
const str = new String('zdq')
Object
const o = { uname: 'pink', age: 18 }
// 1.获得所有的属性名
console.log(Object.keys(o)) //返回数组['uname', 'age']
// 2. 获得所有的属性值
console.log(Object.values(o)) // ['pink', 18]
// 3. 对象的拷贝
// const oo = {}
// Object.assign(oo, o)
// console.log(oo)
Object.assign(o, { gender: '女' })
console.log(o)
</script>
注意这些都是静态方法,所以是 构造函数.方法
keys是获取对象中所有的属性与方法名字,返回一个数组
values是获取所有属性和方法值
assign是拷贝追加,其中两个参数,把后面的追加给前面的,和直接添加差不多。
Array
字面量创造方法
const arr =[1,2,3]
构造函数方法
const arr = new Array (1,2,3)
其中这个forEach究竟是上面玩意呢,在高级第一天还是没搞清楚
其实它就是在底层封装了一个for循环在forEach里面,然后我们调用这个方法,写的参数也是一个函数(一般就写找一个,也有其他参数),函数里面规定了三个变量,分别是项值,索引,数组(就是原数组,forEach不返回数组但是改变原数组)。
<script>
let arr = [1, 2, 3]
arr.forEach(function (a, b, arr) {
arr[b] = a - 1
console.log(a)
console.log(b)
console.log(arr)
});
</script>
arr.reduce()方法
累计求和用reduce
函数内的索引号和源数组可以不写,累计值和当前元素必须写,你写了其实就等于声明了一个函数变量,这个函数变量会被reduce方法的底层运行机制赋值,你可以操作这个函数变量。
问题
不是说map和reduce有返回值,合着还需要我自己在参数函数中写个返回语句?
不管是map还是reduce还是filter还是forEach方法(底层没提供参数值返回所以无法自己return),不是说reduce就是用来求和的,它的作用取决于你自己在函数参数中写的语句,如下
const arr = [1, 2, 3]
const re = arr.reduce((sum, item) => sum + item)
console.log(re)
这一段就是返回累加和,因为你写的返回值是prev+item
原理:reduce底层封装的程序就是把我们每次循环返回的值传递给第一个函数参数(这里就不用操心为什么了,它内置的语句就是这个功能),如下的sum,当没有写起始值,由数组第一个元素代替,最后reduce方法返回这个最终sum的值。
<script>
const arr = [1,22,3,4,6,323]
const re = arr.reduce(function(sum,item){
return sum+2
})
console.log(re);
</script>
这一段代码,结果就是1+2+2+2+2+2+2=11
因为没有写起始值所以起始值是数组第一个为1(因为已经取到数组中的第一个值了,所以循环会少一次),后面因为我们写的是 return sum+2,所以每次+2
2-map方法的原理就是每次把你自己在方法参数那个回调函数中写的语句最终的返回值全部赋予到一个数组,然后这个方法就返回这个新数组。
案例
<script>
const arr = [{
name: '张三',
salary: 10000
}, {
name: '李四',
salary: 10000
}, {
name: '王五',
salary: 20000
},
]
const[{salary:s1},{salary:s2},{salary:s3}] =arr
const sum = (s1+s2+s3)*0.3
console.log(sum);
</script>
方法二
let num = arr.reduce(function(sum,item){
// 这里的item在这个方法底层中设置好了,就是数组项,这个数组项是一个对象,所以item.salary
//这里不能省略起始值,如果省略就用数组第一个为起始值,它是一个对象,肯定就会出问题,所以起始值写0
return sum+item.salary*0.3
},0)
console.log('如果三人每人涨百分之三十工资,需要多出'+num+'元');
数组的常见方法
常用方法有很多,不可能全部精通,不会的话查mdn文档即可
数组的find方法
const arr = [{
name: '张三',
salary: 10000
}, {
name: '李四',
salary: 10000
}, {
name: '王五',
salary: 20000
},
]
let result = arr.find(function(item){
return item.name=='张三'
})
console.log(result); //{name: '张三', salary: 10000}
find方法也有很多个参数,常用的就是写一个回调函数的参数,当函数中返回true则停止遍历,此方法返回的是找到的数据对应的数组项。
问:你不是返回item.name==’张三’嘛?应该是个true或者false呀,怎么又是个数组项?
true或者fasle是那个回调函数返回给方法的,方法里面内置了语句我们看不到,作用就是当回调函数返回true则返回此数组项(这个数组项怎么来的,索引值咋记录的都是内置的语句写好了的,不需要我们来操心)。
every和some方法
every是遍历的数组每一个项都符合条件则返回true,some是其中一个符合就true,它和filter都可以进行条件筛选,但是filter返回的成立条件的数组,every和true是返回的布尔值。
<script>
const arr = [{
name: '张三',
salary: 10000
}, {
name: '李四',
salary: 10000
}, {
name: '王五',
salary: 20000
},
]
// let result = arr.every(function(item){
// return item.salary >= 10000
// })
let result = arr.every(item=>item.salary>=10000)
console.log(result);
</script>
some的用法和every基本上一样,改个方法名就行了,当一个数组项可以成立就返回true
数组的join方法
把数组中的所有数据项元素拼接为字符串,再返回此字符串。
<div></div>
<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>
join中的参数为一个分隔符,也就是把数组中各数组项由什么隔开,也可以不写,就会默认逗号隔开。
from方法把伪数组转换为真数组
目前学的伪数组有argument和document.querySelctorALL获取的元素对象伪数组
真数组才有pop出和push入的方法等
// 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>
string的常用方法
split
str.split()是把字符串转换伪数组,arry.join()是把数组转化为字符串
怎么记忆呢,把数组项一个个组合到一起,加入join到一起就形成了字符串
把字符串分开成一个个数组项就是split分开
<script>
const str ='11,22'
const arr =str.split(',')
console.log(arr) //(2) ['11', '22']
console.log(str.length); //5
</script>
这里是用逗号分隔,如果字符串里面有逗号,就分为两个数组项,如上如果str=‘1122’那么就只有一个数组项[‘1122’]而不是[‘11’, ‘22’]
substring字符串的截取
返回截取的内容
str.substring(indexStart[, indexEnd])
就是截取字符的索引号到结束索引号的值,不写结束默认取到最后
indexend当前项是不包含在截取的字符串内的,所以需要往后面写一个
<script>
let str = '养一方正气,镇四方之淫邪'
console.log(str.substring(0, 8)); //养一方正气,镇四 (取到第八个这个‘方’子呢?其实endindex是不包含在截取中的)
</script>
startsWith方法
语法
str.startsWith(searchString[, position])
检测是否字符串以某个字符开头,返回true或者fasle
后面的position可以设置开始检测开头的位置。
var str = "To be, or not to be, that is the question.";
alert(str.startsWith("To be")); // true
alert(str.startsWith("not to be")); // false
alert(str.startsWith("not to be", 10)); // true
includes方法
数组和字符串都有实例方法includes(),它的包含是区分大小写的
str.includes(searchString[, position])
var str = 'To be, or not to be, that is the question.';
console.log(str.includes('To be')); // true
console.log(str.includes('question')); // true
console.log(str.includes('nonexistent')); // false
console.log(str.includes('To be', 1)); // false
console.log(str.includes('TO BE')); // false
案例
<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>
number的toFixed()方法
如果参数内不写,默认四舍五入。
作用是设置保留小数位长度
<script>
let i = 11.23232
console.log(i.toFixed(2));
</script>
综合案例
<!DOCTYPE html>
<html lang="en">
<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
//spec解构后就是声明赋值了一个对象
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茶叶,清洗球'
//这里要判断有没有gift,如果没有赠品,你去用就会报错
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>
</html>