一,作用域
目录
1.1,局部作用域
函数作用域:
块作用域
1.2,全局作用域
1.3,作用域链
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let a = 1
let b = 2
function f() {
let a = 1
console.log(a);
function g() {
// let a = 2
console.log(a);
}
g()
}
f()
</script>
</body>
</html>
思考上面的结果
1.4,js垃圾回收机制
引用计数法 :
标记清除法:
1.5,闭包
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function outer() {
let a = 10
function fn() {
console.log(a);
}
return fn
}
const func = outer()
func()
</script>
</body>
</html>
闭包 就无法修改这个变量了
总结:
1.6,变量提升
二,函数进阶
2.1,函数提升
<script>
//会把所有函数声明提升到当前作用域的最qianmian
//只提升函数声明 不提升函数调用
fn()
function fn() {
console.log('函数提升');
}
//函数表达式必须先声明后调用
</script>
2.2,函数参数
动态参数:(伪数组)
function foo() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
foo('Hello', 'World', '!');
剩余参数:(真数组)
function sum(...numbers) {
let total = 0;
for (let number of numbers) {
total += number;
}
return total;
}
console.log(sum(1, 2, 3)); // 输出 6
console.log(sum(4, 5, 6, 7, 8)); // 输出 30
动态参数是指在定义或调用函数时,不需要指定参数的个数和名称,而是可以根据实际情况传递任意数量和类型的参数。js中有两种常用的方式来处理动态参数:arguments对象和剩余参数语法。
arguments对象是一个类数组对象,它包含了传给函数的所有实参,无论是否有对应的形参。arguments对象可以通过索引访问每个实参的值,也可以通过length属性获取实参的个数。arguments对象还有一些其他的属性和方法,例如callee属性和caller属性等。arguments对象只在函数内部有效,可以用来实现一些高级的功能,例如递归调用、重载等。
剩余参数语法是ES6引入的一种新特性,它使用扩展运算符(...)来收集动态参数并将其存储在一个数组中。剩余参数语法可以让我们将一个不定数量的参数表示为一个数组,而不需要使用arguments对象。剩余参数只包含那些没有对应形参的实参,而arguments对象包含了传给函数的所有实参。剩余参数是一个真正的数组,可以直接使用所有的数组方法,例如sort、map、forEach或pop等。
动态参数和剩余参数语法都可以让我们更灵活地定义和调用函数,但它们也有一些区别和注意事项。以下是一些示例代码和网页链接,你可以参考学习:
• 使用arguments对象处理动态参数https://bing.com/search?q=js%E4%B8%AD%E5%8A%A8%E6%80%81%E5%8F%82%E6%95%B0%E5%92%8C%E5%89%A9%E4%BD%99%E5%8F%82%E6%95%B0&form=SKPBOT:
// 定义一个函数,不指定形参
function dynamicParams() {
// 使用arguments对象迭代输出所有传递的参数
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
// 调用函数,传递任意数量和类型的实参
dynamicParams(1, 2, 3); // 输出 1 2 3
dynamicParams("a", "b", "c"); // 输出 a b c
dynamicParams(true, false, null, undefined); // 输出 true false null undefined
• 使用剩余参数语法处理动态参数https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Rest_parameters:
// 定义一个函数,使用扩展运算符收集剩余参数
function dynamicParams(...args) {
// args是一个数组,可以直接使用数组方法
args.forEach(function (element) {
console.log(element);
});
}
// 调用函数,传递任意数量和类型的实参
dynamicParams(1, 2, 3); // 输出 1 2 3
dynamicParams("a", "b", "c"); // 输出 a b c
dynamicParams(true, false, null, undefined); // 输出 true false null undefined
• 剩余参数 - JavaScript | MDNhttps://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Rest_parameters:这是一个介绍剩余参数语法的网页,它有详细的概述、语法、描述、示例和规范等内容。
• js动态参数arguments和剩余参数、展开运算符https://blog.csdn.net/lxllxl211/article/details/129359549:这是一篇博客文章,它介绍了js中动态参数、剩余参数和展开运算符的概念、用法和区别等内容。
2.3,展开运算符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const arr = [1, 2, 3]
//展开运算符
// console.log(...arr);
console.log(Math.max(...arr));
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const arr1 = [1, 2, 3]
//展开运算符
// console.log(...arr);
// 求数组最大值
console.log(Math.max(...arr));
// 合并数组
const arr2 = [3,4,5]
const arr = [...arr1,...arr2]
console.log(arr);
</script>
</body>
</html>
展开运算符(spread operator)是一种用三个点(...)表示的语法,它可以将一个可迭代的对象(如数组、字符串、集合等)在某处展开,变成多个参数或元素。展开运算符可以用在以下几种场合:
• 在函数调用时,可以将一个数组或字符串展开为多个参数,而不需要使用apply方法。例如:
function add(a, b, c) {
return a + b + c;
}
var arr = [1, 2, 3];
// 不使用展开运算符,需要使用apply方法
console.log(add.apply(null, arr)); // 6
// 使用展开运算符,直接将数组展开为参数
console.log(add(...arr)); // 6
• 在构造字面量数组时,可以将一个或多个数组或字符串展开为多个元素,而不需要使用concat方法。例如:
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
// 不使用展开运算符,需要使用concat方法
var arr3 = arr1.concat(arr2); // [1, 2, 3, 4, 5, 6]
// 使用展开运算符,直接将数组展开为元素
var arr4 = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
• 在解构赋值时,可以将一个数组或字符串展开为多个变量,而不需要使用slice方法。例如:
var str = "hello";
// 不使用展开运算符,需要使用slice方法
var [a, b] = str.slice(0, 2); // a = "h", b = "e"
// 使用展开运算符,直接将字符串展开为字符
var [c, d] = [...str]; // c = "h", d = "e"
• 在ES2018中,还可以在构造字面量对象时,将一个或多个对象展开为多个属性,而不需要使用Object.assign方法。例如:
var obj1 = {a: 1, b: 2};
var obj2 = {c: 3, d: 4};
// 不使用展开运算符,需要使用Object.assign方法
var obj3 = Object.assign({}, obj1, obj2); // {a: 1, b: 2, c: 3, d: 4}
// 使用展开运算符,直接将对象展开为属性
var obj4 = {...obj1, ...obj2}; // {a: 1, b: 2, c: 3, d: 4}
2.4,箭头函数
• 箭头函数使用=>符号来表示,它可以接受一个或多个参数,也可以不接受任何参数。例如:
// 无参数的箭头函数
() => {
// 函数体
}
// 一个参数的箭头函数
param => {
// 函数体
}
// 多个参数的箭头函数
(param1, param2, ...) => {
// 函数体
}
• 箭头函数的函数体可以是一个表达式或一个语句块。如果是一个表达式,那么函数会隐式地返回表达式的值。如果是一个语句块,那么需要使用return语句来返回值。例如:
// 表达式作为函数体,隐式返回
param => param + 1
// 语句块作为函数体,需要显式返回
param => {
let result = param + 1;
return result;
}
• 箭头函数不绑定自己的this值,而是继承外层作用域的this值。这样可以避免一些常见的this指向问题,例如在回调函数或对象方法中。例如:
// 普通函数中的this指向问题
var obj = {
name: "obj",
sayName: function () {
setTimeout(function () {
console.log(this.name); // this指向window,输出undefined
}, 1000);
}
};
obj.sayName();
// 箭头函数中的this继承问题
var obj = {
name: "obj",
sayName: function () {
setTimeout(() => {
console.log(this.name); // this指向obj,输出"obj"
}, 1000);
}
};
obj.sayName();
• 箭头函数不能用作构造函数,也就是说不能用new关键字来调用它们,否则会抛出错误。这是因为箭头函数没有自己的原型属性和构造器。例如:
// 尝试用new调用箭头函数
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
• 箭头函数也不绑定自己的arguments对象,而是继承外层作用域的arguments对象。这样可以避免一些常见的arguments使用问题,例如在嵌套函数或默认参数中。例如:
// 普通函数中的arguments对象问题
function foo(a) {
var f = function (b) {
return arguments[0]; // arguments指向f的实参,而不是foo的实参
};
return f(a + 1);
}
console.log(foo(1)); // 输出2,而不是1
// 箭头函数中的arguments对象继承
function foo(a) {
var f = (b) => {
return arguments[0]; // arguments指向foo的实参,而不是f的实参
};
return f(a + 1);
}
console.log(foo(1)); // 输出1,而不是2
<script>
//箭头函数
const fn = () => {
console.log(123);
}
fn()
</script>
<script>
//箭头函数
const fn = x => {
console.log(x);
}
fn(14)
//只有一个形参的时候括号可以省
</script>
<script>
//箭头函数
const fn = x => console.log(x);
fn(14)
//只有一个形参的时候括号可以省 函数体只有一行的时候大括号可以省
</script>
<script>
//箭头函数
const fn = x => x+x ;
//只有一行代码可以省略return
console.log(fn(1))
//只有一个形参的时候括号可以省 函数体只有一行的时候大括号可以省
</script>
<script>
//箭头函数
// const fn = x => x+x ;
//只有一行代码可以省略return
// console.log(fn(1))
//只有一个形参的时候括号可以省 函数体只有一行的时候大括号可以省
//返回一个对象
const fn = (uname) => ({ uname: uname })
console.log(fn('bestwishes'));
</script>
2.5,箭头函数参数
箭头函数没有动态参数 有剩余参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const getSum = (...arr) => {
let sum = 0
for (let i = 0; i < arr.length; i++) {
sum += arr[i]
}
return sum
}
const res = getSum(2, 3, 4)
console.log(res);
</script>
</body>
</html>
2.6,箭头函数的this
<script>
//指向window
console.log(this);
function fn() {
console.log(this); //指向window
}
fn()
const obj = {
// 属性
name:'bestiwhiuse',
//方法
siHello:function(){
console.log(this);
}
}
obj.siHello() //指向obj
</script>
<script>
//指向window
console.log(this);
function fn() {
console.log(this); //指向window
}
fn()
const obj = {
// 属性
name:'bestiwhiuse',
//方法
siHello:function(){
console.log(this);
}
}
obj.siHello() //指向obj
//箭头函数中的this
const fn = () => {
console.log(this); //window
}
fn() //指向window this 往上一层找 上一层就指向window 本层没有
//对象方法的箭头函数的this
const obj2 ={
name:'bestwishes',
sayHi:() => {
console.log(this); // this指向window
}
}
obj2.sayHi()
</script>
<script>
//指向window
console.log(this);
function fn() {
console.log(this); //指向window
}
fn()
const obj = {
// 属性
name:'bestiwhiuse',
//方法
siHello:function(){
console.log(this);
}
}
obj.siHello() //指向obj
//箭头函数中的this
const fn = () => {
console.log(this); //window
}
fn() //指向window this 往上一层找 上一层就指向window 本层没有
//对象方法的箭头函数的this
const obj2 ={
name:'bestwishes',
sayHi:() => {
console.log(this); // this指向window
},
Hello:function(){
let i = 0
const count = () =>{
console.log(this); //指向 obj 指向对象 指向调用者
}
}
}
obj2.sayHi()
</script>
三,解构赋值
3.1,数组解构
应用
<script>
//交换两个变量
let a = 1
let b = 2; //必须加分号
[b, a] = [a, b]
console.log(a, b);
</script>
<script>
const str = 'pink'; //必须加分号
[1, 2, 3].map(function (item) {
console.log(item);
})
//交换两个变量
let a = 1
let b = 2;
[b, a] = [a, b]
console.log(a, b);
</script>
<script>
const pc = ['海尔', '联想', '小米', '方正']
[hr, lx, mi, fz] = ['海尔', '联想', '小米', '方正']
console.log(pc[0]);
const [max,min] = getValue()
function getValue(){
return [20,10]
}
</script>
const arr = [1, 2, [3, 4]] //二维数组
console.log(arr[2][0]);
const [a, b, [c, d]] = [1, 2, [3, 4]]
console.log(a);
console.log(b);
console.log(c);
console.log(d);
3.2,对象解构
// 对象解构 等价于 const uname = obj.uname
//要求对象名和属性名必须一致
const { uname, age } = { uname: 'bestwishes', age: 18 }
console.log(uname);
console.log(age);
const { uname: username, age } = { uname: 'bestwishes', age: 18 }
console.log(username);
console.log(age);
例子:
<script>
// const obj ={
// uname:'bestwishes',
// age:18
// }
// 对象解构 等价于 const uname = obj.uname
//要求对象名和属性名必须一致
// const { uname, age } = { uname: 'bestwishes', age: 18 }
// console.log(uname);
// console.log(age);
// const { uname: username, age } = { uname: 'bestwishes', age: 18 }
// console.log(username);
// console.log(age);
// const pig = {name:"帕奇",age:6}
const { name, age } = { name: "帕奇", age: 6 }
console.log(name);
console.log(age);
// const goods = {
// goodsName:'小米',
// price:1999
// }
const { goodsName: gName, price: p } = { goodsName: '小米', price: 1999 }
console.log(gName);
console.log(p);
</script>
const pig = {
name:"bes",
family:{
mother:'ma',
father:'fa',
sister:'si'
},
age:6
}
//对象解构
const {name,family:{mother,father,sister}} = pig
案例:
const msg = {
"code": 200,
"msg": "获取新闻列表成功",
"data": [
{
"id": 1,
"title": "5G商用自己,三大运用商收入下降",
"count": 58
},
{
"id": 2,
"title": "国际媒体头条速览",
"count": 56
},
{
"id": 3,
"title": "乌克兰和俄罗斯持续冲突",
"count": 1669
},
]
}
解构data:
// 需求1: 请将以上msg对象 采用对象解构的方式 只选出 data 方面后面使用渲染页面
const { data } = msg
function render(arr) {
console.log(arr);
}
render(msg)
// // 需求2: 上面msg是后台传递过来的数据,我们需要把data选出当做参数传递给 函数
function render({ data }) {
console.log(data);
}
render(msg)
// 需求3, 为了防止msg里面的data名字混淆,要求渲染函数里面的数据名改为 myData
function render({ data: myData }) {
console.log(myData);
}
render(msg)
遍历数组forEach方法(重点)
渲染案例
<script>
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',
},
]
</script>
+
//声明空字符变量
let str = ''
const { name, price, picture } = goodsList //列表解构
goodsList.forEach(index => {
//渲染
str += `
<div class="item">
<img src="${picture}" alt="">
<p class="name">${name}</p>
<p class="price">${price}</p>
</div>
`
// 追加到大盒子去
document.querySelector('.list').innerHTML = str
})
数组中嵌套 对象 解构时 解构名和对象属性名相同
综合案例:
css实现
/* tab栏切换 */
.filter a:active,
.filter a:focus {
background: #05943c;
color: #fff;
}
<script>
// 2. 初始化数据
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',
},
]
</script>
补充 Filter方法:
<script>
// 2. 初始化数据
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',
},
]
//渲染函数
function render() {
let str = ''
goodsList.forEach(item => {
const { name, price, picture, id } = goodsList
str += `
<div class="item">
<img src="${picture}" alt="">
<p class="name">${name}</p>
<p class="price">${price}</p>
</div>
`
document.querySelector('.list').innerHTML = str
})
}
render(goodsList)
//过滤筛选
document.querySelector('.filter').addEventListener('click',e => {
//解构e.target
const {dataset,tagName} = e.target
let arr = goodsList
if(tagName ==='A'){
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)
}
}
})
render(arr)
</script>
三,方法
- 构造函数&&常用方法
- 创建对象三种方式
构造函数:
<script>
function Pig(uname, age) {
this.uname = uname
this.age = age
}
const p = new Pig('佩奇', 6)
</script>
<script>
function Pig(uname, age) {
this.uname = uname
this.age = age
}
const p1 = new Pig('佩奇', 6)
const p2 = new Pig('佩', 7)
console.log(p1 === p2); //false
//构造函数创建的对象互不影响
</script>
实例成员是指没有用static修饰的类成员,例如实例变量和实例方法。实例成员属于类的对象,每个对象都有自己的实例成员的副本。实例成员只能通过对象来访问和调用,不能直接通过类名来访问和调用。例如:
class Person {
// 实例变量
String name;
int age;
// 实例方法
void sayHello() {
System.out.println("Hello, I am " + name);
}
}
// 创建一个Person对象
Person p1 = new Person();
// 通过对象访问和修改实例变量
p1.name = "Alice";
p1.age = 20;
// 通过对象调用实例方法
p1.sayHello(); // 输出 Hello, I am Alice
静态成员是指用static修饰的类成员,例如静态变量和静态方法。静态成员属于类本身,不属于任何一个对象,所有对象共享同一个静态成员。静态成员可以直接通过类名来访问和调用,也可以通过对象来访问和调用,但是推荐使用前者。例如:
class Person {
// 静态变量
static int count;
// 静态方法
static void showCount() {
System.out.println("There are " + count + " persons.");
}
}
// 直接通过类名访问和修改静态变量
Person.count = 10;
// 直接通过类名调用静态方法
Person.showCount(); // 输出 There are 10 persons.
// 创建一个Person对象
Person p1 = new Person();
// 通过对象访问和修改静态变量
p1.count = 20;
// 通过对象调用静态方法
p1.showCount(); // 输出 There are 20 persons.
实例成员和静态成员的区别主要有以下几点:
• 实例成员需要创建对象后才能使用,而静态成员不需要创建对象就能使用。
• 实例成员在内存中为每个对象分配一份空间,而静态成员在内存中只占一份空间。
• 实例成员可以访问静态成员和其他实例成员,而静态成员只能访问其他静态成员,不能访问实例成员。
• 静态成员在类加载时就初始化,而实例成员在创建对象时才初始化
实例成员是指没有用static修饰的类成员,例如实例属性和实例方法。实例成员属于类的对象,每个对象都有自己的实例成员的副本。实例成员只能通过对象来访问和调用,不能直接通过类名来访问和调用。例如:
class Person {
// 实例属性
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例方法
sayHello() {
console.log(`Hello, I am ${this.name}`);
}
}
// 创建一个Person对象
let p1 = new Person("Alice", 20);
// 通过对象访问和修改实例属性
p1.name = "Bob";
p1.age = 21;
// 通过对象调用实例方法
p1.sayHello(); // 输出 Hello, I am Bob
静态成员是指用static修饰的类成员,例如静态属性和静态方法。静态成员属于类本身,不属于任何一个对象,所有对象共享同一个静态成员。静态成员可以直接通过类名来访问和调用,也可以通过对象来访问和调用,但是推荐使用前者。例如:
class Person {
// 静态属性
static count = 0;
// 静态方法
static showCount() {
console.log(`There are ${Person.count} persons.`);
}
// 实例属性
constructor(name, age) {
this.name = name;
this.age = age;
// 每创建一个对象,静态属性加一
Person.count++;
}
}
// 直接通过类名访问和修改静态属性
Person.count = 10;
// 直接通过类名调用静态方法
Person.showCount(); // 输出 There are 10 persons.
基本包装类型:
内置构造函数
Object静态方法:
<script>
const o = { uname: 'pink', age: 18 }
console.log(Object.keys(o)); //返回数组['uname','age']
//获得所有的属性
console.log(Object.values(o)); //['pink',18]
</script>
拷贝对象
<script>
const o = { uname: 'pink', age: 18 }
console.log(Object.keys(o)); //返回数组['uname','age']
//获得所有的属性
console.log(Object.values(o)); //['pink',18]
//拷贝对象
const oo = {}
Object.assign(oo, o)
console.log(oo);
</script>
数组常用方法
reduce方法
<script>
const arr = [1, 5, 8]
//没有初始值
const total = arr.reduce(function (prev, current) {
return prev + current
})
console.log(total);
</script>
<script>
const arr = [1, 5, 8]
//没有初始值
// const total = arr.reduce(function (prev, current) {
// return prev + current
// })
// console.log(total);
//有初始值
const total = arr.reduce(function (prev, current) {
return prev + current
}, 10)
console.log(total);
</script>
<script>
const arr = [1, 5, 8]
//没有初始值
// const total = arr.reduce(function (prev, current) {
// return prev + current
// })
// console.log(total);
//有初始值
// const total = arr.reduce(function (prev, current) {
// return prev + current
// }, 10)
// console.log(total);
const total = arr.reduce( (prev, current)=> prev + current
, 10)
console.log(total);
</script>
<script>
// const arr = [1, 5, 8]
//没有初始值
// const total = arr.reduce(function (prev, current) {
// return prev + current
// })
// console.log(total);
//有初始值
// const total = arr.reduce(function (prev, current) {
// return prev + current
// }, 10)
// console.log(total);
// const total = arr.reduce( (prev, current)=> prev + current
// , 10)
// console.log(total);
//上一次值 当前值 返回值
//
const arr = [
{
name: 'z',
salary: 10000
}, {
name: 'z',
salary: 10000
} ,{
name: 'z',
salary: 10000
}
]
const total = reduce((prev,current)=> prev + current.salary*13,0)
</script>
常见的方法(前三个知道,后面几个了解)
every 方法:
const arr = [10, 20, 30, 40]
const flag = arr.every(item => item >= 10)
console.log(flag);
<script>
const spec = { size: '40com*40com', color: '黑色' }
//拿到所有值的数组
// Object.values(spec)
// console.log(Object.values(spec));
document.querySelector('div').innerHTML = Object.values(spec).join('/')
</script>
将伪数组转转换为真数组
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
const lis = document.querySelector('ul li') //伪数组
const liss = Array.from(lis) //转为真数组
console.log(liss);
</script>
</body>
String
• startswith和endswith方法都接受一个字符串类型的参数,用于指定要检索的子字符串。
• startswith和endswith方法都返回一个布尔值,如果字符串以参数值为开头或结尾则返回true,否则返回false。
• startswith和endswith方法都区分大小写,如果参数值和字符串的大小写不一致,则返回false。
• startswith和endswith方法都可以接受一个可选的第二个参数,用于指定字符串的长度。如果提供了第二个参数,那么只会在字符串的前length个字符中进行检索。
以下是一些使用startswith和endswith方法的示例代码和网页链接,你可以参考学习:
• 使用startswith和endswith方法判断字符串https://www.x1y1z1.com/javascript/startsendwith.html:
let text = "Hello world!";
let result1 = text.startsWith("Hello"); // true
let result2 = text.startsWith("hello"); // false
let result3 = text.endsWith("world!"); // true
let result4 = text.endsWith("World!"); // false
• 使用startswith和endswith方法指定字符串长度https://www.runoob.com/jsref/jsref-endswith.html:
let text = "Hello world!";
let result1 = text.startsWith("world", 6); // true
let result2 = text.startsWith("world", 5); // false
let result3 = text.endsWith("Hello", 5); // true
let result4 = text.endsWith("Hello", 6); // false
• substring方法接受两个参数,分别是开始索引和结束索引,它会返回从开始索引到结束索引(不包括)之间的子字符串。
• substring方法不会修改原始字符串,而是返回一个新的字符串。
• 如果开始索引大于结束索引,substring方法会自动交换两个参数的位置,这意味着substring(4, 1)等同于substring(1, 4)。
• 如果开始索引或结束索引为负数或NaN,substring方法会将它们视为0。
• substring方法和substr方法、slice方法都可以用来提取子字符串,但它们有一些区别和注意事项。
以下是一些使用substring方法的示例代码和网页链接,你可以参考学习:
• 使用substring方法提取子字符串https://www.w3school.com.cn/jsref/jsref_substring.asp:
let text = "Hello world!";
let result = text.substring(1, 4); // "ell"
• 使用substring方法交换两个参数https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/substring:
let text = "Hello world!";
let result = text.substring(4, 1); // "ell"
• 使用substring方法处理负数或NaNhttps://bing.com/search?q=js%E4%B8%AD%E7%9A%84substring%E6%96%B9%E6%B3%95&form=SKPBOT:
let text = "Hello world!";
let result = text.substring(-3); // "Hello world!
小案例:
<body>
<div></div>
<script>
// const lis = document.querySelector('ul li') //伪数组
// const liss = Array.from(lis) //转为真数组
// console.log(liss);
//split 将 字符串转换为数组
const gift = '50g的茶叶,清洗球'
// const arr = gift.split(',').map(function (item) {
// return `<span>【赠品】${item}</span> <br>`
// }).join()
// document.querySelector('div').innerHTML = arr
// console.log(arr);
document.querySelector('div').innerHTML = gift.split(',').map(item => `<span>【赠品】${item}</span> <br>`)
</script>
</body>
Number:
• toFixed方法接受一个参数,表示要保留的小数位数,它是0到20之间的整数,包括0和20。如果省略了该参数,或者提供了非法的值,将默认使用0。
• toFixed方法返回一个新的字符串,不会修改原始的数字。返回的字符串可能会用0来填充小数部分,以达到指定的长度。
• toFixed方法在进行四舍五入时可能会产生一些不准确的结果,这是因为toFixed方法在处理浮点数时,实际上使用的是舍入到最近的偶数(银行家舍入)策略,而不是标准的四舍五入。这种舍入策略是为了在大量运算时减小累积误差。
目录
以下是一些使用toFixed方法的示例代码和网页链接,你可以参考学习:
• 使用toFixed方法转换数字https://www.w3school.com.cn/jsref/jsref_tofixed.asp:
let num = 5.56789;
let n = num.toFixed(2); // "5.57"
• 使用toFixed方法处理非法参数https://www.runoob.com/jsref/jsref-tofixed.html:
let num = 5.56789;
let n = num.toFixed(-1); // "6"
• 使用toFixed方法产生不准确结果https://bing.com/search?q=js+tofixed+%E6%96%B9%E6%B3%95&form=SKPBOT:
let num = 0.615;
let n = num.toFixed(2); // "0.61" 而非 "0.62"
案例:
<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 => {
//对象 解构
const { name, price, picture, spec, gift, count } = item
//赠品模块
const text = gift ? gift.split(',').map(item => `<span class="tag">【赠品】${item}</span>`).join() : ''
const spe = Object.values(spec).join('/')
//总金额
const sub_total = ((price * 100 * count) / 100).toFixed(2) //乘除100处理精度问题.
// 合计模块
// const total = price.reduce((prev,current) =>{(prev*100*current)/100}) 写外面
return `
<div class="item">
<img src=${picture} alt="">
<p class="name">${name} <span class="tag">【赠品】${text}</span></p>
<p class="spec">${spe}</p>
<p class="price">${price.toFixed(2)}</p>
<p class="count">${count}</p>
<p class="sub-total">${sub_total}</p>
</div>
`
}).join('') //将返回的数组转换为字符串
// const { price, count } = current
// 有bug
document.querySelector('.amount').innerHTML = goodsList.reduce((prev, current) => {
const { price, count } = current
//prev + (price * count).toFixed(2)
return prev + (price * count).toFixed(2)
}, 0)
</script>
四,面向对象编程
1.2,数组扩展最大值和求和方法
自定义数组方法
<script>
const arr = [1, 2, 3]
//求最大
Array.prototype.max = function () {
return Math.max(...this) //this -> arr
}
//求最小
Array.prototype.min = function () {
return Math.min(...this) //this -> arr
}
console.log(arr.max());
console.log(arr.min());
//求和
Array.prototype.sum = function () {
return this.reduce((prev, item) => prev + item, 0)
}
console.log(arr.sum());
</script>
1.3,总结
<script>
//constructor
function Star() {
}
const p1 = new Star()
console.log(Star.prototype.constructor === Star);
Star.prototype.sing = function () {
console.log('唱歌');
}
Star.prototype.dance = function () {
console.log('跳舞');
}
Star.prototype = {
//重新指回Star 构造函数
constructor:Star,
sing:function(){
console.log('cg');
},
dance:function(){
console.log('tw');
}
}
</script>
1.4,原型继承
<script>
// 公共的部分放到原型上
const Person = {
age: 18,
eyes: 2
}
// 女人
function Wonman() {
}
Wonman.prototype = Person //继承Person 的属性 继承后就覆盖coonstructor类了 要重新指回类
//指回类 原来的构造函数
Wonman.prototype.constructor = Wonman
//实例化对象
const w1 = new Wonman()
console.log(w1);
//男人
function Man() {
}
Man.prototype = Person //继承Person 的属性
Man.prototype.constructor = Man
//实例化对象
const m1 = new Man()
console.log(m1);
</script>
添加新方法出现问题 woman 和man 都被添加这个方法
<script>
// 公共的部分放到原型上
const Person = {
age: 18,
eyes: 2
}
// 女人
function Wonman() {
}
Wonman.prototype = Person //继承Person 的属性 继承后就覆盖coonstructor类了 要重新指回类
//指回类 原来的构造函数
Wonman.prototype.constructor = Wonman
//添加方法
Wonman.prototype.baby = function () {
console.log('baby');
}
//实例化对象
const w1 = new Wonman()
console.log(w1);
//男人
function Man() {
}
Man.prototype = Person //继承Person 的属性
Man.prototype.constructor = Man
//实例化对象
const m1 = new Man()
console.log(m1);
</script>
所以要抽取一个父类
<script>
//父类
function Person() {
this.age = 18
this.eyes = 2
}
console.log(new Person);
// 女人
function Wonman() {
}
Wonman.prototype = new Person() //继承Person 的属性 继承后就覆盖coonstructor类了 要重新指回类
//指回类 原来的构造函数
Wonman.prototype.constructor = Wonman
//添加方法
Wonman.prototype.baby = function () {
console.log('baby');
}
//实例化对象
const w1 = new Wonman()
console.log(w1);
//男人
function Man() {
}
Man.prototype = new Person() //继承Person 的属性
Man.prototype.constructor = Man
//实例化对象
const m1 = new Man()
console.log(m1);
</script>