JS进阶学习记录(上)

以下是我JS进阶学习记录:

mdn手册:https://developer.mozilla.org/zh-CN/
文章内容源自b站的黑马程序员的pink老师:https://www.bilibili.com/video/BV1Y84y1L7Nn/?spm_id_from=333.999.0.0&vd_source=fb5a1624baac73f8cef6c60124746736


重点:
利用构造函数创建对象(构造函数实例化执行过程)
Object.keys()获得对象所有的属性名返回数组形式
Object.values()获得对象所有的属性值返回数组形式
数组的常用方法【forEach语法、filter筛选数组、reduce方法求和、map()、find()、every()、some()】
String常用方法【str.split()、str.substring()、starsWith()、includes()】
toFixed()保留小数点后几位


一、垃圾回收机制

1.1垃圾回收机制说明

1、全局变量一般不会回收(关闭页面才回收)
2、一般情况下局部变量,不用了,会被自动回收掉
3、内存泄漏:程序中分配的内存由于某种原因,程序未释放或无法释放叫做内存泄漏。
4、拓展 - js垃圾回收机制 - 算法说明
(1) 栈:由操作系统自动分配释放函数的参数值、局部变量等,基本数据类型放到栈里面。
(2) 堆:一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型放到堆里面。

1.2 介绍两种常见的浏览器垃圾回收算法:引用计数法和标记清除法

1.2.1 引用计数法 ( IE浏览器常用这个方法,现代浏览器一般不用了。)

有一个缺点:嵌套引用(循环引用),如果两个对象相互引用,尽管他们已不再使用,垃圾回收器不会进行回收,导致内存泄漏。

function fn(){
    let o1 = {}
    let o2 = {}
    o1.a = o2
    o2.a = o1
    return '引用计数无法回收'
}
fn()

1.2.2 标记清除法。

找到就给你标记起来,找不到就垃圾回收。

for(let i = 1;i<=3;i++){

}
let num =10
function fn(){
    const str = 'andy'
    // str = 'lily'
    console.log(str);
}
fn()

在这里插入图片描述

二、闭包

闭包简单来说就是:里层函数 + 外层函数的变量 形成一个闭包。

function outer() {
	// a 是外层函数的变量
    let a = 10
    // fn 是 里层函数
    function fn() {
        console.log(a);
    }
    fn()
}
outer()

那么看一下下面这个是不是闭包呢?

function outer() {
    function fn() {
        console.log(22);
    }
    fn()
}
outer()

这个并不是闭包哈,因为缺少了外层的变量。请大家睁大双眼仔细看哦!

常见的闭包形式:外部可以访问使用函数内部的变量

function outer(){
    let a = 100
    function fn(){
        console.log(a);
    }
    return fn
}
// outer() === fn === function fn(){}
// const fun = function fn(){}
const fun = outer()
fun() //调用函数
// 外面要使用这个100

我们说了那么久闭包,闭包到底用来干什么的呢?用来:统计函数调用的次数

let i = 0
function fn(){
    i++
    console.log(`函数被调用了${i}`);
}
fn() //1
fn() //2

由于以上的 i 是全局变量,容易被人纂改,所以就需要用闭包。

function fn2(){
    let i = 0
    function fun(){
		i++
		console.log(`函数被调用了${i}`);
    }
    return fun
}
const result = fn2()
result() //2
result() //3 

此处,本来 i 用完一次就应该被回收了,但是有 return ,又重新执行了一次,所以没有被回收,一直在使用,这就叫做内存泄漏了。所以闭包有可能会导致内存泄漏的风险。

因为 result 是全局作用域,只有关闭页面才会销毁,只要页面不关闭,他就一直执行,函数内部就会一直 return fun ,而return fun 就找到 i ,i 就内存泄漏了。

闭包简写:

function outer(){
    let i = 1
    return function(){
        console.log(i);
    }
}
const fun = outer()
fun() //调用fun

闭包的作用:
1、外部可以访问函数内部的变量,也可以实现数据私有。
2、闭包很有用,因为他允许将函数与其所操作的某些数据(环境)关联起来。

闭包的问题:容易引起内存泄漏

三、变量提升

3.1 变量提升

3.1.1 let / const 声明的变量不存在变量提升

3.1.2 把所有 var 声明的变量提升到当前作用域的最前面

3.1.3 只提升声明,不提升赋值

console.log(num + '件');  //undefined件
var num = 10

提升后相当于以下写法:

var num
console.log(num + '件');  //undefined件
num = 10

3.2 函数提升

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

3.2.2 只提升函数声明,不提升函数调用

fn()
function fn(){
	console.log('函数提升')
}

以下为提升后:

function fn(){
	console.log('函数提升')
}
fn()

3.2.3 函数表达式 必须先声明和赋值,后调用,否则报错。

fun()
var fun = function(){
	console.log('函数表达式') //报错
}

函数表达式提升后为:

var fun
fun()
fun = function(){
	console.log('函数表达式)   //报错
}

四、函数动态参数、函数剩余参数、展开运算符

4.1 函数动态参数

函数动态参数 arguments 只存在于 函数里面,并且是个伪数组,也就是有索引号下标,但是没有数组常用方法,有属于自己的方法

function getSum(){
	console.log(arguments) //控制台输出的是[2,3,4]和[1,2,3,4,5,6]
	let sum = 0
	for(let i = 0; i < arguments.length; i++){
		sum += arguments[i]
	}
	console.log(sum)  //控制台输出的是数组的和
}
getSum(2,3,4)
getSum(1,2,3,4,5,6)

4.2 函数剩余参数

剩余参数和动态参数的区别:
1、…是语法符号,置于最末函数形参之前,用于获取多余的实参。
2、借助 … 获取的是剩余实参,是个真数组。
3、开发中,建议多使用剩余参数,因为箭头函数没有arguments。

剩余参数
前面三个点 … 后面是数组变量名

function getSum(...arr){
	console.log(arr)
	let sum = 0
	for(let i = 0; i < arr.length; i++){
		sum += arr[i]
	}
	console.log(sum)
}
getSum(2,3)
getSum(1,2,3)

如果客户需要至少两个参数,也就是两个及以上。

function getSum(a,b,...arr){
	console.log(arr)  //使用的时候不需要写三个点...
}
getSum(1,2,3) //[3]
getSum(3,5) //[]
getSum(1,3,5,7,9,11)  //[5,7,9,11]

4.3 展开运算符

展开运算符(…)跟 函数剩余参数(…arr)特别相似,注意区分一下。
展开运算符(…)将一个数组进行展开,不会修改原数组
运用场景:求数组的最大值(最小值)、合并数组等。

const arr1 = [1,2,3]
console.log(...arr1) //1 2 3

4.3.1 求数组最大值

数组本身没有求最大值最小值的方法,但是 Math.max() 方法有。比如:console.log(Math.max(1,2,3)) //3

const arr1 = [1,2,3]
console.log(...arr1) //1 2 3
console.log(Math.max(...arr1))  //3
console.log(Math.min(...arr1))  //1

4.3.2 合并数组

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

五、箭头函数

5.1 箭头函数用于匿名函数,有匿名函数的地方就可以替换成箭头函数。

function fn(){
	console.log(123)
}

等价于:

const fn = function(){
	console.log(123)
}

箭头函数属于表达式函数,不存在函数提升。
普通函数有 arguments 动态参数
箭头函数没有 arguments 动态参数,但是有剩余参数 …args

const fn = () => {
	console.log(123)
}
fn()

5.2 箭头函数的参数

const fn = (x) => {
	console.log(x)
}
fn(1)

5.3 箭头函数的参数如果只有一个,可以省略小括号

const fn = x => {
	console.log(x)
}
fn(2)

5.4 箭头函数只有一行代码的时候,可以省略大括号

const fn = y => console.log(y)
fn(2)

5.5 箭头函数只有一行代码的时候,也可以省掉return

const fn = y => {
	return y+y
}
console.log(fn(2))

等价于:

const fn = y => y + y
console.log(fn(2))

5.6 阻止事件对象 用箭头函数的简写

const p = document.querySelector('p')
p.addEventListener('click',e => e.preventDefault())

5.7 箭头函数可以直接返回一个对象

const fn = function(uname){
	return {name:uname}
}
console.log(fn('某某某'))

等价于:
({属性名:属性值}),这里花括号对象外面还必须要包一层小括号,不然就是undefined

const fn = (uname) => ({name:uname})
console.log(fn('某某某'))

5.8 箭头函数求和

const getSum = (...arr) => {
    let sum = 0
    for (let i = 0; i < arr.length; i++) {
        sum += arr[i]
    }
    return sum
}
console.log(getSum(1, 2, 3))

5.9 箭头函数的 this 指向问题(重要)

以前 this 的指向:谁调用,this就指向谁。
箭头函数的 this :指向上一层作用域

5.9.1 普通的 this 指向

console.log(this); //window

普通函数:
因为 fn() = window.fn(),所以下面的代码也是指向window。

function fn(){
	console.log(this); //window
}

普通的对象的方法调用:

const obj = {
	name:'andy',
	sayHi:function(){
		console.log(this)  //因为是obj调用了这个方法,所以指向的是obj
	}
}
obj.sayHi()

5.9.2 箭头函数的 this 指向

函数:

const fn2 = () => {
	console.log(this) //指向window
}
fn2()

对象方法箭头函数:

const obj2 {
	uname:'谁谁谁',
	sayHi: () => {
		console.log(this); //window
		//指向上一层作用域的this,也就是谁调用了obj2,this就指向谁,所以是window.obj2.sayHi()
	}
}
obj2.sayHi()
const obj3 = {
	uname:'谁谁谁',
	sayHi: function(){
		console.log(this) //obj3
		let i = 10
		const count = () => {
			console.log(this) //obj3
		}
		count()
	}
}
obj3.sayHi()

使用箭头函数前需要考虑函数中的 this 的值,DOM 事件回调函数为了简便,还是不太推荐使用箭头函数。

比如:

普通函数,此时 this 指向了 DOM对象 btn

btn.addEventListener('click',function(){
	console.log(this)  //btn
})

箭头函数,此时 this 指向了 window

btn.addEventListener('click',() => {
	console.log(this)  //window
})

所以使用时需要小心这种情况。

六、数组解构

6.1 数组解构说明

数组解构:将数组的单元值快速批量赋值给一系列变量的简洁语法。

右侧数组的单元值将被赋值给左侧的变量。

const arr = [100, 60, 80]
//数组解构 赋值 一一对应
const [max, min, avg] = arr
console.log(max); //100
console.log(min); //60
console.log(avg); //80

1、数组解构的典型应用:交换两个变量
2、变量需要用 let 命名,变量声明完记得加分号;

必须加分号的两种情况:

(1)立即执行函数

(function(){})();
;(function(){})()
//分号加在前面或者后面都可以
//或者是
(function(){}());
;(function(){}())

(2)数组解构

数组开头的,特别是前面有语句的一定要注意加分号;

;[b, a] = [a, b]

交换两个变量:

let a = 1
let b = 2;
[b, a] = [a, b] //这里没有像上面那样加个const或者let声明,是应为前面两个a,b变量已经声明了。
console.log(a, b)

6.2 数组解构之数组遍历

[1,2,3].map(function(ele){
	console.log(ele)
})

6.3 数组解构细节

1、变量多,单元值少 undefined

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

2、变量少,单元值多

const [a,b] = [1,2,3]
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] 真数组

4、变量多,单元值少。防止 undefined 传递过来
声明时给个默认值

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

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

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

6、支持多维数组的解构

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

或者

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

或者 多维数组解构,只要二维数组里的3

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

七、对象解构

1、声明的变量名字和属性名字必须要一样

const {uname,age} = {uname: '谁谁谁',age: 18}
// 等价于 cosnt uname = obj.uname
console.log(uname);
console.log(age);

2、对象解构的变量名可以重新改名,防止跟普通变量名有冲突 旧变量名:新变量名

const {uname:username,age} = {uname:'谁谁谁',age:18}
console.log(username);
console.log(age);

3、解构数组对象
声明有中括号就写中括号,有花括号就写花括号。

const pig = [
    {
        uname: '佩奇',
        age: 5
    }
]
const [{uname,age}] = pig
console.log(uname);
console.log(age);

4、多级对象解构

const pig = {
    name: '佩奇',
    family: {
        mother: '猪妈妈',
        father: '猪爸爸',
        sister: '乔治'
    },
    age: 6
};
const {name,family:{mother,father,sister}} = pig
console.log(name);
console.log(mother);
console.log(father);
console.log(sister);

5、数组对象解构 + 多级解构

const person = [
    {
        name:'佩奇',
        family:{
            mother:'猪妈妈',
            father:'猪爸爸',
            sister:'乔治'
        },
        age:6
    }
]
const [{name,family:{mother,father,sister}}] = person
console.log(name);
console.log(mother);
console.log(father);
console.log(sister);

6、多级对象解构案例练习

// 1.这是后台传递过来的数据
const msg = {
    "code":200,
    "msg":"获取新闻列表成功",
    "data":[
        {
            "id":1,
            "title":"5G商用自己,三大运用商收入下降",
            "count":58
        },
        {
            "id":2,
            "title":"国际媒体头条速览",
            "count":56
        },
        {
            "id":3,
            "title":"乌克兰和俄罗斯持续冲突",
            "count":1669
        }
    ]
}

// 需求1: 请将以上 msg 对象采用对象解构的方式,只选出 data 方法后面使用渲染页面
// const {data} = msg
// console.log(data);

// 需求2: 上面msg是后台传递过来的数据,我们需要把data选出当做参数传递给函数
// 以前的写法或者思维
// const {data} = msg
// function render(arr){
//     console.log(arr);
// }
// render(data)

// 等价于

// function render(arr){
//     const {data} = arr
//     console.log(data);
// }
// render(msg)

// 传参的时候顺便解构了
// function render({data}){
//     console.log(data);
// }
// render(msg)

// 需求3:为了防止msg里面的data名字混淆,要求渲染函数里面的数据名改为myData
function render({data:myData}){
    // 要求将获取过来的 data数据 更名为myData
    console.log(myData);
}
render(msg)

// msg 虽然很多属性,但是我们利用解构只要data的值
// 改新名字的方法:旧的写前面,新的写后面

八、 forEach语法 <重点>

forEach 跟 map 很像,但是 map() 是需要返回值 return ,forEach没有return。

map数组遍历+return返回值 也是重点

forEach 只能遍历数组,不能遍历对象。

arr.map(function(){
	return
})

map会返回空数组[] , forEach则是 undefined

在forEach参数中,当前数组元素是必须要写的,索引号可选

forEach 是加强版的 for 循环,适合于遍历数组对象,数据越复杂,forEach 作用就越明显

const arr = ['red','green','pink']
const re = arr.forEach(function(item,index){
    console.log(item); //数组元素 red  green  pink
    console.log(index); //索引号 0 1 2
})
// console.log(re); //不返回值,所以结果是undefined

渲染商品列表案例(用到forEach遍历+解构)

const goodsList = [{
    id: '4001172',
    name: '逞心如意手摇咖啡磨豆机咖啡豆研磨机',
    price: '289.00',
    picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg'
},
{
    id: '4001594',
    name: '日式黑陶功夫茶组双侧把茶具礼盒装',
    price: '288.00',
    picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',
},
{
    id: '4001009',
    name: '竹制干泡茶盘正方形沥水茶台品茶盘',
    price: '109.00',
    picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
},
{
    id: '4001874',
    name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
    price: '488.00',
    picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
},
{
    id: '4001649',
    name: '大师监制龙泉青瓷茶叶罐',
    price: '139.00',
    picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
},
{
    id: '3997185',
    name: '与众不同的口感汝瓷白酒杯套组1壶4杯',
    price: '108.00',
    picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',
},
{
    id: '3997403',
    name: '手工吹制更厚实白酒杯壶套装6壶6杯',
    price: '99.00',
    picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',
},
{
    id: '3998274',
    name: '德国百年工艺高端水晶玻璃红酒杯2支装',
    price: '139.00',
    picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',
}

]
// 核心思路:有多少条数据,就渲染多少模块,然后生成对应的html结构标签,赋值给list标签即可
// 1.利用forEach遍历数组里面的数据
// 2.拿到数据,利用字符串拼接生成结构添加到页面中
// 3.注意:传递参数的时候,可以使用对象解构

// 1. 声明一个字符串变量
let str = ``
// 2. 遍历数据
goodsList.forEach(item=> {
// console.log(item); //可以得到每一个数组元素 对象
// const {id} = item   对象解构
const {name,price,picture} = item
str += `
<div class="item">
    <img src=${picture} alt="">
    <p class="name">${name}</p>
    <p class="price">${price}</p>
</div>
`
})
// 3. 生成的 字符串 添加给 list
document.querySelector('.list').innerHTML = str

九、filter 筛选数组<重点>

返回符合条件的新数组

const arr = [10,20,30]
const newArr = arr.filter(item => item>=20)
console.log(newArr); //[20,30]

价格筛选案例:

const goodsList = [{
    id: '4001172',
    name: '逞心如意手摇咖啡磨豆机咖啡豆研磨机',
    price: '289.00',
    picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg'
},
{
    id: '4001594',
    name: '日式黑陶功夫茶组双侧把茶具礼盒装',
    price: '288.00',
    picture: 'https://yanxuan-item.nosdn.127.net/3346b7b92f9563c7a7e24c7ead883f18.jpg',
},
{
    id: '4001009',
    name: '竹制干泡茶盘正方形沥水茶台品茶盘',
    price: '109.00',
    picture: 'https://yanxuan-item.nosdn.127.net/2d942d6bc94f1e230763e1a5a3b379e1.png',
},
{
    id: '4001874',
    name: '古法温酒汝瓷酒具套装白酒杯莲花温酒器',
    price: '488.00',
    picture: 'https://yanxuan-item.nosdn.127.net/44e51622800e4fceb6bee8e616da85fd.png',
},
{
    id: '4001649',
    name: '大师监制龙泉青瓷茶叶罐',
    price: '139.00',
    picture: 'https://yanxuan-item.nosdn.127.net/4356c9fc150753775fe56b465314f1eb.png',
},
{
    id: '3997185',
    name: '与众不同的口感汝瓷白酒杯套组1壶4杯',
    price: '108.00',
    picture: 'https://yanxuan-item.nosdn.127.net/8e21c794dfd3a4e8573273ddae50bce2.jpg',
},
{
    id: '3997403',
    name: '手工吹制更厚实白酒杯壶套装6壶6杯',
    price: '99.00',
    picture: 'https://yanxuan-item.nosdn.127.net/af2371a65f60bce152a61fc22745ff3f.jpg',
},
{
    id: '3998274',
    name: '德国百年工艺高端水晶玻璃红酒杯2支装',
    price: '139.00',
    picture: 'https://yanxuan-item.nosdn.127.net/8896b897b3ec6639bbd1134d66b9715c.jpg',
}]
// 1. 渲染函数 封装
function render(arr) {
	let str = ``
	arr.forEach(item => {
    	const {name,price,picture} = item
    	str += `
	    <div class="item">
	        <img src=${picture} alt="">
	        <p class="name">${name}</p>
	        <p class="price">${price}</p>
	    </div>
    	`
	})
	// 追加给list
	document.querySelector('.list').innerHTML = str
}
render(goodsList) //页面一打开就需要渲染

// 2. 过滤筛选
document.querySelector('.filter').addEventListener('click', e => {
	// e.target.dataset.index    e.target.tagName
	const {tagName,dataset} = e.target
	// 判断
	if (tagName === 'A') {
    	// arr返回的是新数组
    	// 为什么这里设置的不是空数组?因为如果点击的a不是1不是2不是3,那就是其他的,就直接跳到渲染函数,渲染函数调用的是arr,如果此时arr设置为空数组,则页面渲染为空,所以给goodslist好一点
    	let arr = goodsList
    	if(dataset.index === '1'){
        	arr = goodsList.filter(item=> item.price>=0 && item.price<=100)
    	}else if(dataset.index==='2'){
        	arr = goodsList.filter(item=>item.price>=100 && item.price <=300)
    	}else if(dataset.index==='3'){
        	arr = goodsList.filter(item=>item.price>=300)
    	}
    	// console.log(arr);
    	// 渲染函数
    	render(arr)
	}
})

在这里插入图片描述

十、创建对象(以构造函数为主进行讲解)【以下都是属于内置构造函数】

内置构造函数包括object、array、string、number

10.1 创建对象有三种方式

10.1.1 利用对象字面量创建对象

const o = {
	name:'佩奇'
}

10.1.2 利用 new Object 创建对象

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

10.1.3 利用构造函数创建对象

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

有两个约定:
1、函数的命名以大写字母开头
2、他们只能由 “new” 操作符来执行使用。

构造函数内部无须写return,写了也没用

function Pig(uname,age){
	//this 指向调用函数的对象 obj,uname是形参,name是属性
	this.name = uname
	this.age = age
}
console.log(new Pig('佩奇', 6))
console.log(new Pig('乔治', 3))
10.1.3.1 构造函数实例化执行过程 <重点>

1、创建新的空对象
2、构造函数 this 指向新的空对象
3、执行构造函数代码,修改 this,添加新的属性
4、返回新的对象,构造函数里面不需要写return

10.1.3.2 实例成员和静态成员

1、实例成员:实例对象上的属性和方法属于实例成员。

function Pig(name){
	this.name = name
}
const peiqi = new Pig('佩奇')
const qiaozhi = new Pig('乔治')
peiqi.name = '小猪佩奇'  //peiqi.name的 name 就是实例属性
peiqi.sayHi = () => {  //实例方法
	console.log('hi~')
}
//为构造函数传入参数,创建结构相同但值不同的对象
console.log(peiqi)
console.log(qiaozhi)

2、静态成员:构造函数上的属性和方法称为静态成员

function Pig(name){
	this.name = name
}
Pig.eyes = 2 //静态属性
Pig.sayHi = function(){
	console.log(this)   //指向Pig构造函数
}
Pig.sayHi()   //静态方法
console.log(Pig.eyes)  //2

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

静态方法中的 this 指向构造函数。

十一、基本包装类型

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

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

比如:

const str = 'red'
console.log(str.length) //3
const num = 12
console.log(num.toFixed(2)) //12.00 保留两位小数点

js底层完成,把简单数据类型包装为引用数据类型

const str = new String('red')

内置构造函数:
引用类型:Object、Array、RegExp、Date等
包装类型:String、Number、Boolean等。

十二、Object静态方法

12.1 Object.keys()获得对象所有的属性名,返回数组形式<重点>

const o = {
	uname:'pink',
	age:18
}
//获得对象所有的属性名
console.log(Object.keys(o)); //返回数组['uname','age']

12.2 Object.values()获得对象所有的属性值,返回数组形式<重点>

const o = {
	uname:'pink',
	age:18
}
//获得对象所有的属性名
console.log(Object.values(o)); //返回数组['pink',18]

12.3 Object.assign()对象的拷贝以及给对象添加属性

12.3.1 拷贝对象

const o = {
	uname:'red',
	age:18
}
const oo = {}
Object.assign(oo,o) //将o对象拷贝给oo对象
console.log(oo)

12.3.2 给对象添加属性

const o = {
	uname:'pink',
	age:18
}
Object.assign(o,{gender:'女'})
console.log(o); 

结果是:

在这里插入图片描述

十三、数组reduce方法:求和 <重点>

基本语法:

const arr = [1,3,5]
arr.reduce(function(上一次值,当前值){}, 初始值)

13.1 没有初始值

const arr = [1, 3, 5]
const total = arr.reduce(function(prev, current){
	return prev + current
})
console.log(total) //9

13.2 有初始值(除了把数组里的数字相加外,还要加上初始值)

const arr = [1, 3, 5]
const total = arr.reduce(function(prev, current){
	return prev + current
},10)
console.log(total)  //19

13.3 利用箭头函数的写法

const arr = [1, 3, 5]
const total = arr.reduce((prev, current) => prev + current,10)
console.log(total)

13.4 reduce的执行过程:

1、如果没有起始值,则上一次值以数组的第一个数组元素的值
2、每一次循环,把返回值给作为下一次循环的 上一次值
3、如果有起始值,则起始值作为上一次值。

在这里插入图片描述
在这里插入图片描述

在数组对象中使用reduce计算薪资案例

const arr = [{
            name: '张三',
            salary: 10000
        }, {
            name: '李四',
            salary: 10000
        }, {
            name: '王五',
            salary: 10000
        }]
        // 计算薪资案例
        const result = arr.reduce((prev, current) => prev + current.salary, 0)
        console.log(result);  //30000
        // 工资提升 30%
        const up = arr.reduce((prev, current) => prev + current.salary * 1.3, 0)
        console.log(up);  //39000

十四、Array常用方法

数组常见的其他方法如下:

在这里插入图片描述

14.1 find() <重点>

find() 查找元素,返回符合测试条件的第一个数组元素值,如果没有符合条件的则返回undefined

在数组查找:

const arrs = ['red','blue','green']
const re = arrs.find(function(item){
    return item === 'blue'
})
console.log(re); //blue

在数组对象查找:

const arr = [{
    name: '小米',
    price: 1999
}, {
    name: '华为',
    price: 3999
}]
const mi = arr.find(item => item.name === '小米')
console.log(mi)

14.2 every() <重点>

every 每一个是否都符合条件,如果都符合返回true,否则返回false

const arr1 = [10,20,30]
const flag = arr1.every(item => item >=10) //全部都大于等于10,就返回true
console.log(flag);  //true
const flag2 = arr1.every(item => item >=20) 
console.log(flag2)  //false

14.3 some() <重点>

some() 只要有一个符合条件,返回true,否则返回false

const arr2 = [10,20,30]
const flag2 = arr2.some(item => item >=20) //只要有一个大于等于20,就返回true
console.log(flag2); //true

14.4 Array.from() 将伪数组转换为真数组

先插播一个无关的小案例。
将size和color里面的值拼接为字符串之后,写到div标签里面。
思路:获得所有的属性值,然后拼接字符串就可以了。
1、获得所有属性值:Object.values() 返回的是数组。
2、拼接数组是join(’ ') 这样就可以转换为字符串了。

const spec = { size:'40cm*40cm',color:'黑色' }
document.querySelector('div').innerHTML = Object.values('spec').join('/')

注意:join(‘’) 是 数组 转换成 字符串 。split(‘’) 是 字符串 转换为 数组。两个是死对头

14.4.1 Array.from(arr) 把伪数组转换为真数组

html部分:

<ul>
	<li>1</li>
	<li>2</li>
	<li>3</li>
</ul>

javascript:

const lis = document.querySelectorAll('ul li')
const liss = Array.from(lis)
//如果是伪数组用 pop() 方法,会报错。现在转换为了真数组,就不会报错了。
liss.pop() //删除数组最后一个元素 li
console.log(liss)

十五、String常见方法

15.1 str.split()

str.split() 字符串转换为数组 和join()相反

const str = 'pink, red'
const arr = str.split(',')
console.log(arr)  //字符串转换为数组,以逗号分隔
const str1 = '2024-11-28'
const arr1 = str1.split('-') //字符串转换为数组,以-分隔
console.log(arr1)  //['2024', '11', '28']

15.2 str.substring()

字符串的截取 , 以前用substr() 已废弃,现在用 substring(开始的索引号[, 结束的索引号]), 结束索引号可选可不选。

const str = '我今天又要上班了'
console.log(str.substring(5,6)) //上

15.2.1 如果省略了 结束索引号 ,默认取到最后

const str = '我今天又要上班了'
console.log(str.substring(5)) //上班了

15.2.2 结束的索引号不包含想要截取的部分

比如想要获取到 “上班” 两个字。

const str = '我今天又要上班了'
console.log(str.substring(5,7)) //上班  如果结束索引号取6,是不包含6的,所以取7才能取到班字

15.3 startsWith()

startsWidth() 判断是不是以某个字符开头,还有个可选的索引号,表示从哪开始检索

const str = 'pink老师上课中'
console.log(str.startsWith('pink')) //true
console.log(str.startsWith('pink',2)) //false
console.log(str.startsWith('老师',4)) //true

15.4 includes()

includes() 判断一个字符是否包含在一个字符串中,返回 true 或 false 。开始查找的索引号是可选可不选的。

const str = '我是pink老师'
console.log(str.includes('pink')); //true
console.log(str.includes('pink',2)); //true

15.5 小案例 - 赠品

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

const gift = '50g的茶叶,清洗球'
document.querySelector('div').innerHTML = gift.split(',').map(item => `<span>【赠品】 ${item}</span><br>`).join('')

运行结果:
在这里插入图片描述

十六、toFixed()

toFixed() 是Number 内置的构造函数,用于创建数值。
toFixed() 可以让数字指定保留的小数位数。
还会四舍五入

const num = 10,123
console.log(num.toFixed())  //10
const num = 10.923
console.log(num.toFixed()) //11
const num = 10.923
console.log(num.toFixed(2)) //10.92

十七、数字强制转换为字符串的两种方法

const num = 10
console.log(String(num)) //1、String()
console.log(num.toString()) //2、num.toString()

购物车展示案例

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


    // 1. 先利用map来遍历,有多少条数据,就渲染多少相同商品
    // ---可以先写死数据
    // ---注意map返回值是数组,我们需要用join转换为字符串
    // ---把返回的字符串 赋值 给 list大盒子 的 innerHTML

    // 2. 更换数据
    // ---先更换不需要处理的数据 ,图片 ,商品名称, 单价 , 数量
    // ---采取对象解构的方式
    // ---注意 单价要保留2位小数,488.00   toFixed(2)

    // 2. 更换数据 - 处理 规格文字 模块
    // ---获取 每个对象里面的spec,上面对象解构添加spec
    // ---获得所有属性值是:Object.values() 返回的是数组
    // ---拼接数组是join('') 这样就可以转换为字符串了

    // 2. 更换数据 - 处理 赠品 模块
    // ---获取 每个对象里面的gift,上面对象解构添加gift
    // ---判断是否有gift属性,没有的话不需要渲染
    // ---利用变成的字符串然后写到p.name里面


    // 3. 分析业务模块:
    // ---计算 合计 模块
    // ---求和用到数组 reduce 方法 累计器
    // ---根据数据里面的数量和单价累加和即可
    // ---注意 reduce 方法有2个参数,第一个是回调函数,第二个是初始值,这里写0
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {padding: 0;margin: 0;box-sizing: border-box;border: 0;}
        .list {width: 990px;margin: 100px auto 0;}
        .item {padding: 15px;transition: all 0.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>
    <div class="total">
        <div>合计:<span class="amount">1000.00</span></div>
    </div>
    <script>
        const goodsList = [{
            id: '4001172',
            name: '逞心如意手摇咖啡磨豆机咖啡豆研磨机',
            price: 289,
            picture: 'https://yanxuan-item.nosdn.127.net/84a59ff9c58a77032564e61f716846d6.jpg',
            count: 2,
            spec: {color: '白色'}
        },
        {
            id: '4001009',
            name: '竹制干泡茶盘正方形沥水茶台品茶盘',
            price: 109,
            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); //每一条对象
            // 对象解构
            const {picture,name,count,price,spec,gift} = item
            // 规格文字模块处理
            const text = spec? Object.values(spec).join('/'):''
            // 计算小计模块 单价 * 数量  保留两位小数
            // 关于小数的计算精度问题:0.1+0.2=0.3000000004
            // 解决方案:乘10再除10
            // (0.1*100 + 0.2*100) / 100 === 0.3
            // 而两位小数点就是要 *100
            const subTotal = ((price * 100 * count) / 100).toFixed(2)
            // 处理赠品模块
            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)
        document.querySelector('.amount').innerHTML = total.toFixed(2)
    </script>
</body>
</html>

持续学习中。。。

javascript进阶学习记录(下): https://blog.youkuaiyun.com/huang_99/article/details/144718982

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值