JavaScript 基础入门:从零开始学 JS

一、JavaScript 简介

JavaScript(简称 JS)是一种高级的、解释型的编程语言,由 Netscape 公司的 Brendan Eich 在 1995 年开发,最初命名为 LiveScript,后因与 Java 的合作关系而改名为 JavaScript。作为 Web 开发的三大核心技术之一(其他两个是 HTML 和 CSS),JavaScript 在现代网页中扮演着至关重要的角色。

JS 的主要特点包括:

  1. 客户端脚本语言:直接在用户的浏览器中执行,无需服务器处理
  2. 动态类型:变量类型在运行时确定
  3. 基于原型的面向对象特性
  4. 函数是一等公民
  5. 支持异步编程(通过 Promise 和 async/await)

与 HTML(超文本标记语言)负责页面结构、CSS(层叠样式表)负责页面样式不同,JavaScript 主要负责页面的行为和交互功能。典型的应用场景包括:

  • 表单验证:检查用户输入是否符合要求(如邮箱格式验证)
  • 动态内容更新:无需刷新页面即可加载新内容(如社交媒体信息流)
  • 动画效果:创建平滑的页面过渡和交互效果
  • 用户交互响应:处理点击、滚动等用户事件
  • 与后端 API 通信:通过 AJAX 或 Fetch API 获取数据

现代 JavaScript 已经发展出多个框架和库(如 React、Vue、Angular),使得开发复杂的前端应用变得更加高效。根据 Stack Overflow 2022 开发者调查,JavaScript 已连续10年成为最常用的编程语言。

示例代码展示基本的 DOM 操作:

// 获取页面元素
const button = document.getElementById('myButton');
// 添加点击事件监听器
button.addEventListener('click', function() {// 修改元素内容this.textContent = '已点击';// 改变样式this.style.backgroundColor = 'blue';
});

二、JavaScript 的引入方式

1. 内嵌式 JavaScript

内嵌式是最基础的 JavaScript 引入方式,直接在 HTML 文件中使用 <script> 标签包裹 JavaScript 代码。这种方式的优点是简单直接,适合快速测试和小型脚本。

典型应用场景

  • 快速原型开发
  • 小型网站或单页应用
  • 需要立即执行的初始化代码

示例代码详解

<!DOCTYPE html>
<html>
<head><title>内嵌式JS</title><script>// 这里是JavaScript代码function init() {alert("页面加载完成,这是内嵌式JavaScript");console.log("调试信息输出到控制台");}// 当DOM加载完成后执行document.addEventListener('DOMContentLoaded', init);</script>
</head>
<body><!-- 页面内容 -->
</body>
</html>

特性说明

  • 代码会按照在HTML中的出现顺序执行
  • 可以放在<head><body>中,位置不同会影响执行时机
  • 适合少量脚本,但不利于代码维护和复用

2. 外链式 JavaScript

外链式是将 JavaScript 代码写在单独的.js文件中,然后在 HTML 中通过<script>标签引入。这是现代Web开发推荐的方式。

典型应用场景

  • 大中型项目开发
  • 需要复用的组件或库
  • 需要代码分离和模块化的项目

示例代码详解

HTML文件:

<!DOCTYPE html>
<html>
<head><title>外链式JS</title><!-- 推荐放在body结束前,避免阻塞渲染 --><script src="assets/js/myScript.js" defer></script><!-- 或者使用async属性实现异步加载 -->
</head>
<body><!-- 页面内容 -->
</body>
</html>

myScript.js文件内容:

// 使用严格模式
'use strict';// 定义模块
const App = {init: function() {alert("这是外链式JavaScript");this.bindEvents();},bindEvents: function() {// 事件绑定代码}
};// 当DOM加载完成后初始化应用
document.addEventListener('DOMContentLoaded', function() {App.init();
});

最佳实践

  1. 文件命名要有意义,如main.jsapp.js
  2. 使用deferasync属性优化加载性能
  3. 合理组织目录结构,如js/assets/js/
  4. 考虑使用模块化开发工具(如Webpack、Rollup)

3. 行内式 JavaScript

行内式是将JavaScript代码直接写在HTML标签的事件属性中,这种方式虽然简单但不推荐大量使用。

典型应用场景

  • 快速测试某个事件处理
  • 简单的交互效果
  • 传统老式网站维护

示例代码详解

<!DOCTYPE html>
<html>
<head><title>行内式JS</title><style>.btn {padding: 10px 20px;background-color: #4CAF50;color: white;border: none;cursor: pointer;}</style>
</head>
<body><!-- 简单的事件处理 --><button class="btn" onclick="alert('这是行内式JavaScript'); this.textContent='已点击'">点击我</button><!-- 表单验证示例 --><form onsubmit="return validateForm()"><input type="text" id="username" required><button type="submit">提交</button></form><script>// 可以配合使用的函数function validateForm() {const input = document.getElementById('username');if(input.value.length < 3) {alert('用户名至少3个字符');return false;}return true;}</script>
</body>
</html>

注意事项

  1. 这种方式使HTML和JavaScript高度耦合,不利于维护
  2. 违反了关注点分离(Separation of Concerns)原则
  3. 现代开发中推荐使用事件监听器而非行内事件
  4. 在React等框架中的"行内事件"实际上是语法糖,原理不同

三、变量

变量是用于存储数据的容器

在编程中,变量是存储数据的基本单元,相当于一个带标签的盒子,我们可以把数据放进去,需要时再取出来使用。JavaScript 提供了三种声明变量的方式:varletconst

1. 声明和赋值详解

1.1 使用 var 声明变量(ES5及之前的方式)

var 是 JavaScript 最早使用的变量声明方式,具有函数作用域:

// 1. 先声明后赋值
var a;    // 声明变量a,此时a的值为undefined
a = 10;   // 给变量a赋值为10// 2. 声明同时赋值
var b = 20;  // 声明变量b并赋值为20// 3. 变量提升现象
console.log(c); // 输出undefined,不会报错
var c = 30;

1.2 使用 let 声明变量(ES6新增)

let 是 ES6 引入的声明方式,具有块级作用域,解决了 var 的一些问题:

// 1. 基本用法
let x = 100;  // 声明并赋值// 2. 块级作用域示例
{let y = 200;console.log(y); // 200
}
// console.log(y); // 报错,y不在作用域内// 3. 不存在变量提升
console.log(z); // 报错
let z = 300;

1.3 使用 const 声明常量(ES6新增)

const 用于声明不可变的常量,必须初始化时就赋值:

// 1. 基本用法
const PI = 3.14159;  // 声明常量PI// 2. 不可重新赋值
// PI = 3.14; // 报错,不能修改常量// 3. 对于对象和数组
const colors = ['red', 'green'];
colors.push('blue'); // 允许,因为修改的是数组内容
// colors = ['yellow']; // 报错,不能重新赋值

2. 变量命名规则详解

JavaScript 变量命名需要遵循以下规则:

  1. 组成字符

    • 允许使用字母(a-z, A-Z)
    • 数字(0-9),但不能以数字开头
    • 下划线(_)
    • 美元符号($)
  2. 命名示例

    • 合法:userName, _count, $price, num1
    • 非法:1stPlace(数字开头),my-name(含连字符)
  3. 关键字限制

    • 不能使用 JavaScript 保留的关键字,如:
      // let if = 10;  // 报错,if是关键字
      // let for = 20; // 报错,for是关键字
      

  4. 大小写敏感

    • firstNameFirstName 是两个不同的变量
    • ageAGE 也是不同的变量
  5. 命名建议

    • 使用驼峰命名法(如 userAge
    • 常量通常全大写(如 MAX_SIZE
    • 使用有意义的名称(避免单字母变量名)

举例说明:

let userAge = 25;         // 正确
const MAX_USERS = 100;    // 正确
let $price = 99.9;        // 正确
// let 2ndPlace = "John"; // 错误:数字开头
// let first-name = "Tom";// 错误:包含连字符

四、数据类型

1. 基本数据类型

字符串(String)

字符串是表示文本的数据类型,可以用单引号('')、双引号("")或反引号(``)定义。ES6引入的模板字符串(反引号)支持多行文本和字符串插值。

let str1 = "Hello"; // 双引号
let str2 = 'World'; // 单引号
let str3 = `Hello ${str2}`; // 模板字符串,输出"Hello World"
let multiLine = `这是
多行
字符串`; // 支持换行

数字(Number)

JavaScript 只有一种数字类型,包括整数和浮点数,采用IEEE 754标准的64位双精度浮点数格式表示。

let num1 = 100;    // 整数
let num2 = 3.14;   // 浮点数
let num3 = 0.1 + 0.2; // 0.30000000000000004(浮点数精度问题)
let hex = 0xff;    // 十六进制
let oct = 0o10;    // 八进制
let bigNum = 1e6;  // 科学计数法,表示1000000

布尔值(Boolean)

布尔值表示逻辑实体,只有两个值:true和false。常用于条件判断。

let isTrue = true;    // 真值
let isFalse = false;  // 假值
let isGreater = 10 > 5; // 比较运算返回布尔值

空值(Null)

Null类型只有一个值null,表示一个空对象引用。通常用于表示变量有意为空值。

let nullValue = null; // 明确赋值为空
let element = document.getElementById('not-exist'); // 返回null

未定义(Undefined)

Undefined类型表示变量已声明但未赋值,或访问对象不存在的属性。

let undefinedValue; // 只声明未赋值
let obj = {};
console.log(obj.noProperty); // 访问不存在的属性返回undefined

Symbol(ES6新增)

Symbol表示唯一的、不可变的值,主要用作对象属性的标识符。

let sym1 = Symbol('description');
let sym2 = Symbol('description');
console.log(sym1 === sym2); // false,每个Symbol都是唯一的

BigInt(ES2020新增)

BigInt表示任意精度的整数,可以表示大于2^53的整数。

let bigInt = 9007199254740991n; // 末尾加n表示BigInt
let bigInt2 = BigInt("9007199254740991"); // 使用BigInt函数

2. 引用数据类型

对象(Object)

对象是键值对的集合,用于存储复杂数据结构。对象属性可以是基本类型值或其他对象。

let person = {name: "张三",age: 20,address: {city: "北京",street: "长安街"},sayHello: function() {console.log("你好!");}
};// 访问属性
console.log(person.name); // 点表示法
console.log(person['age']); // 方括号表示法
person.sayHello(); // 调用方法

数组(Array)

数组是有序的值集合,可以包含不同类型的元素,长度动态可变。

let arr = [1, "two", true, {name: "数组元素"}];
arr.push(5); // 添加元素到末尾
arr.unshift(0); // 添加元素到开头
let first = arr[0]; // 通过索引访问
let length = arr.length; // 获取数组长度// 数组遍历
arr.forEach(function(item) {console.log(item);
});

函数(Function)

函数是可执行代码块,可以接收参数并返回值。JavaScript中函数是一等公民。

// 函数声明
function add(a, b) {return a + b;
}// 函数表达式
let multiply = function(x, y) {return x * y;
};// 箭头函数(ES6)
let divide = (x, y) => x / y;// 调用函数
let sum = add(5, 3); // 8
let product = multiply(4, 6); // 24
let quotient = divide(10, 2); // 5

其他引用类型

还包括Date、RegExp、Map、Set等特殊对象类型。

// Date对象
let now = new Date();
console.log(now.getFullYear());// RegExp正则表达式
let pattern = /hello/i;
console.log(pattern.test("Hello World")); // true// Map集合
let map = new Map();
map.set('name', '李四');
console.log(map.get('name'));// Set集合
let set = new Set([1, 2, 3, 3, 4]);
console.log(set.size); // 4(自动去重)

3. 数据类型检测与转换

类型检测

// typeof运算符
console.log(typeof "Hello"); // "string"
console.log(typeof 100); // "number"
console.log(typeof true); // "boolean"
console.log(typeof null); // "object"(历史遗留问题)
console.log(typeof undefined); // "undefined"
console.log(typeof {name: "张三"}); // "object"
console.log(typeof [1, 2, 3]); // "object"(数组也是对象)
console.log(typeof function(){}); // "function"// instanceof运算符(检测对象类型)
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(function(){} instanceof Function); // true// Object.prototype.toString方法(更准确的类型检测)
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"

类型转换

// 显式类型转换
let numStr = "123";
let num = Number(numStr); // 字符串转数字
let str = String(123); // 数字转字符串
let bool = Boolean(1); // 真值转换// 隐式类型转换
let result = "5" + 2; // "52"(字符串拼接)
let sum = "5" - 2; // 3(数字运算)
let isTrue = !!1; // true(布尔转换)// 特殊转换案例
console.log(Number("")); // 0
console.log(Number("123abc")); // NaN
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN

五、运算符

1. 算术运算符

JavaScript 提供了多种算术运算符用于数值计算,包括:

  • + 加法运算
  • - 减法运算
  • * 乘法运算
  • / 除法运算
  • % 取余运算(求模)
  • ++ 自增运算(分为前自增和后自增)
  • -- 自减运算(分为前自减和后自减)

示例代码

let a = 10;
let b = 5;// 基本运算
console.log(a + b); // 15,加法运算
console.log(a - b); // 5,减法运算
console.log(a * b); // 50,乘法运算
console.log(a / b); // 2,除法运算
console.log(a % b); // 0,取余运算(10除以5余0)// 自增运算(后自增)
a++; // 等价于 a = a + 1
console.log(a); // 11// 自减运算(后自减)
b--; // 等价于 b = b - 1
console.log(b); // 4// 前自增与前自减
let x = 5;
let y = ++x; // 先自增再赋值
console.log(y); // 6let m = 5;
let n = m++; // 先赋值再自增
console.log(n); // 5
console.log(m); // 6

2. 赋值运算符

赋值运算符用于给变量赋值,包括:

  • = 基本赋值
  • += 加后赋值
  • -= 减后赋值
  • *= 乘后赋值
  • /= 除后赋值
  • %= 取余后赋值

示例代码

let c = 10; // 基本赋值// 复合赋值运算
c += 5; // 相当于 c = c + 5,结果为15
console.log(c); // 15c -= 3; // 相当于 c = c - 3,结果为12
console.log(c); // 12c *= 2; // 相当于 c = c * 2,结果为24
console.log(c); // 24c /= 4; // 相当于 c = c / 4,结果为6
console.log(c); // 6c %= 2; // 相当于 c = c % 2,结果为0
console.log(c); // 0// 字符串连接赋值
let str = "Hello";
str += " World"; // 相当于 str = str + " World"
console.log(str); // "Hello World"

3. 比较运算符

比较运算符用于比较两个值的大小或相等性,返回布尔值:

  • == 等于(会自动类型转换)
  • === 严格等于(不进行类型转换)
  • != 不等于
  • !== 严格不等于
  • > 大于
  • < 小于
  • >= 大于等于
  • <= 小于等于

示例代码

// 松散比较(会进行类型转换)
console.log(10 == "10"); // true,因为字符串"10"会被转换为数字10
console.log(1 == true); // true,true会被转换为1// 严格比较(不进行类型转换)
console.log(10 === "10"); // false,类型不同
console.log(10 === 10); // true,值和类型都相同// 数值比较
console.log(10 > 5); // true
console.log(10 < 5); // false
console.log(10 >= 10); // true
console.log(10 <= 9); // false// 不等于比较
console.log(10 != "10"); // false,因为松散比较会转换类型
console.log(10 !== "10"); // true,因为严格比较类型不同// 特殊比较
console.log(null == undefined); // true
console.log(null === undefined); // false
console.log(NaN == NaN); // false,NaN不等于任何值包括它自己

4. 逻辑运算符

逻辑运算符用于处理布尔值,包括:

  • && 逻辑与(两个操作数都为true时返回true)
  • || 逻辑或(至少一个操作数为true时返回true)
  • ! 逻辑非(反转操作数的布尔值)

示例代码

// 逻辑与
console.log(true && false); // false
console.log(true && true); // true
console.log(false && false); // false// 逻辑或
console.log(true || false); // true
console.log(false || false); // false
console.log(true || true); // true// 逻辑非
console.log(!true); // false
console.log(!false); // true// 短路求值特性
let x = 10;
(x > 5) && console.log("x大于5"); // 会输出,因为第一个条件为true
(x < 5) && console.log("这不会输出"); // 不会输出,因为第一个条件为false// 实际应用:条件赋值
let name = "";
let displayName = name || "匿名用户";
console.log(displayName); // "匿名用户"let user = { name: "张三" };
let userName = user && user.name;
console.log(userName); // "张三"

六、流程控制

JavaScript 条件语句和循环语句详解

1. 条件语句

if 语句

if 语句是最基本的条件控制结构,用于根据条件执行不同的代码块。

let score = 80;if (score >= 60) {console.log("及格了");  // 当score>=60时执行
} else {console.log("没及格");  // 当score<60时执行
}

应用场景:判断用户是否登录、表单验证、成绩评定等。

if-else if-else 语句

当需要判断多个条件时,可以使用多分支结构。

let grade = 85;if (grade >= 90) {console.log("优秀");     // 90分以上
} else if (grade >= 80) {console.log("良好");     // 80-89分
} else if (grade >= 60) {console.log("及格");     // 60-79分
} else {console.log("不及格");   // 60分以下
}

执行流程:从上到下依次判断条件,当某个条件满足时执行对应代码块并退出整个判断结构。

switch 语句

switch 语句适用于多条件等值判断的场景,比多个if-else更清晰。

let day = 3;switch (day) {case 1:console.log("星期一");break;  // 必须使用break退出switch结构case 2:console.log("星期二");break;case 3:console.log("星期三");  // 本例会输出这个结果break;default:console.log("其他星期");  // 当所有case都不匹配时执行
}

注意事项:

  1. 每个case后面必须加break,否则会继续执行下一个case
  2. default分支是可选的,用于处理未匹配的情况
  3. switch使用严格比较(===)

2. 循环语句

for 循环

for循环是最常用的循环结构,适合已知循环次数的场景。

for (let i = 0; i < 5; i++) {console.log(i); // 依次输出0、1、2、3、4
}

循环步骤:

  1. 初始化变量(let i = 0)
  2. 检查条件(i < 5)
  3. 执行循环体
  4. 更新变量(i++)
  5. 重复步骤2-4直到条件不满足

while 循环

while循环在不确定循环次数时使用,先判断条件再执行循环体。

let j = 0;
while (j < 5) {console.log(j); // 依次输出0、1、2、3、4j++;
}

应用场景:读取文件直到结束、处理用户输入直到满足条件等。

do-while 循环

do-while循环至少执行一次循环体,然后再判断条件。

let k = 0;
do {console.log(k); // 先输出0,然后输出1、2、3、4k++;
} while (k < 5);

特点:无论条件是否成立,循环体至少执行一次。适合需要先执行操作再检查条件的场景,如菜单显示和用户交互。

七、函数

函数的概念与重要性

函数是编程中的基本构建块,它是一段可重复使用的代码,用于执行特定的任务。合理使用函数可以带来多重好处:

  • 提高代码可维护性:将复杂逻辑分解为多个小函数,便于理解和修改
  • 增强代码复用性:避免重复代码,一处定义多处调用
  • 降低耦合度:函数间通过明确接口通信,减少相互依赖
  • 便于调试:可以单独测试每个函数的功能

1. 函数的声明和调用

在JavaScript中,函数可以通过多种方式声明和调用,每种方式都有其适用场景。

基本函数声明

// 声明一个名为sayHello的函数
// 它接受一个name参数,用于个性化问候
function sayHello(name) {// 使用console.log输出问候语// 字符串拼接可以使用+运算符console.log("Hello, " + name + "!");// 也可以使用ES6的模板字符串console.log(`Hello, ${name}!`);
}// 调用函数并传入参数"张三"
sayHello("张三"); 
// 输出: 
// Hello, 张三!
// Hello, 张三!// 再次调用传入不同参数
sayHello("李四"); 
// 输出: 
// Hello, 李四!
// Hello, 李四!

带多个参数的函数

// 声明一个包含多个参数的函数
// 参数可以是任意类型:字符串、数字、布尔值、对象等
function introduce(name, age, job) {// 使用模板字符串构建自我介绍console.log(`大家好,我是${name},今年${age}岁,职业是${job}。`);// 可以添加更多逻辑if (age < 18) {console.log("我还是个未成年人~");}
}// 调用函数并传入三个参数
introduce("王五", 28, "工程师"); 
// 输出:
// 大家好,我是王五,今年28岁,职业是工程师。introduce("小明", 16, "学生");
// 输出:
// 大家好,我是小明,今年16岁,职业是学生。
// 我还是个未成年人~

2. 函数的返回值

函数可以使用return语句返回一个值,这个值可以被其他代码使用。返回值可以是任何JavaScript数据类型。

简单返回值

// 声明一个求两数之和的函数
function sum(a, b) {// 返回a和b的和// return语句会立即结束函数执行return a + b;// 这行代码永远不会执行console.log("This won't be printed");
}// 调用函数并将返回值赋给result变量
let result = sum(3, 5);
console.log(result); // 输出8// 可以直接在表达式中使用函数调用
console.log(sum(10, 20) * 2); // 输出60// 也可以作为其他函数的参数
console.log(sum(sum(2,3), sum(4,5))); // 输出14

复杂返回值

// 返回复杂数据结构的函数
function createUser(name, age) {// 返回一个对象// 可以根据参数动态计算属性值return {username: name,userAge: age,isAdult: age >= 18,registeredAt: new Date(), // 添加注册时间// 方法也可以作为返回值greet: function() {return `Hi, I'm ${this.username}`;}};
}let user = createUser("赵六", 25);
console.log(user); 
/* 输出:
{username: "赵六",userAge: 25,isAdult: true,registeredAt: [当前日期时间],greet: [Function: greet]
}
*/
console.log(user.greet()); // 输出: Hi, I'm 赵六let teen = createUser("小红", 16);
console.log(teen.isAdult); // false

3. 函数表达式

函数也可以作为表达式赋值给变量,这种形式更加灵活。

匿名函数表达式

// 将匿名函数赋值给multiply变量
// 函数表达式不会被提升,必须先定义后使用
let multiply = function(a, b) {return a * b;
};// 调用函数表达式
let product = multiply(4, 5);
console.log(product); // 输出20// 立即调用的函数表达式(IIFE)
// 常用于创建独立作用域
let result = (function(x, y) {return x / y;
})(10, 2);
console.log(result); // 输出5// 带参数的IIFE
(function(config) {console.log(`App starting with ${config.env} mode`);
})({ env: 'development', debug: true });

箭头函数(ES6)

// 使用箭头函数简化语法
// 当只有一个参数和一条语句时最简洁
let square = x => x * x;
console.log(square(5)); // 输出25// 多参数箭头函数
// 需要括号包裹参数
let greet = (name, time) => {return `Good ${time}, ${name}!`;
};
console.log(greet("张三", "morning")); // 输出"Good morning, 张三!"// 箭头函数与this绑定
const counter = {count: 0,increment: function() {setInterval(() => {// 箭头函数不绑定自己的this,继承自外围this.count++;console.log(this.count);}, 1000);}
};
counter.increment();

实际应用场景

数据处理

// 格式化货币金额
function formatCurrency(amount) {// 添加货币符号并保留两位小数return "¥" + amount.toFixed(2);
}
console.log(formatCurrency(29.9)); // 输出"¥29.90"
console.log(formatCurrency(123.456)); // 输出"¥123.46"// 更复杂的格式化函数
function formatPrice(amount, currency = '¥', decimal = 2) {const formatted = amount.toFixed(decimal);if (currency === '¥') {return currency + formatted;} else {return formatted + ' ' + currency;}
}
console.log(formatPrice(29.9)); // "¥29.90"
console.log(formatPrice(99.99, '$')); // "99.99 $"

表单验证

// 验证邮箱格式
function validateEmail(email) {// 使用正则表达式验证基本邮箱格式const re = /\S+@\S+\.\S+/;return re.test(email);
}
console.log(validateEmail("test@example.com")); // true
console.log(validateEmail("invalid.email")); // false// 更全面的验证函数
function validateForm(data) {const errors = {};if (!data.username) {errors.username = '用户名不能为空';}if (!validateEmail(data.email)) {errors.email = '邮箱格式不正确';}if (data.password.length < 6) {errors.password = '密码至少需要6个字符';}return Object.keys(errors).length === 0 ? null : errors;
}const formData = {username: '张三',email: 'test@',password: '123'
};
console.log(validateForm(formData));
/* 输出:
{email: '邮箱格式不正确',password: '密码至少需要6个字符'
}
*/

业务逻辑封装

// 计算订单总金额
function calculateTotal(items, taxRate) {// 计算小计let subtotal = items.reduce((sum, item) => sum + item.price, 0);// 计算税费const tax = subtotal * taxRate;// 返回包含明细的对象return {subtotal: subtotal,tax: tax,total: subtotal + tax,itemsCount: items.length};
}const cartItems = [{ id: 1, name: '商品A', price: 100 },{ id: 2, name: '商品B', price: 200 },{ id: 3, name: '商品C', price: 150 }
];const orderTotal = calculateTotal(cartItems, 0.1);
console.log(orderTotal);
/* 输出:
{subtotal: 450,tax: 45,total: 495,itemsCount: 3
}
*/// 更复杂的业务逻辑函数
function processOrder(order, paymentMethod) {// 验证订单if (!order.items || order.items.length === 0) {throw new Error('订单中没有商品');}// 计算总金额const total = calculateTotal(order.items, order.taxRate || 0.1);// 处理支付const paymentResult = processPayment(total.total, paymentMethod);// 记录订单const orderRecord = createOrderRecord(order, total, paymentResult);// 发送确认邮件sendConfirmationEmail(order.customerEmail, orderRecord);return orderRecord;
}

通过合理使用函数,可以使代码更加模块化、易于维护和测试。

八、数组

数组基础概念

数组是编程中最常用的数据结构之一,它是一种用于存储多个值的有序集合。数组中的每个元素都有一个对应的索引(从0开始的整数),通过这个索引可以快速访问或修改特定位置的元素。数组在内存中是连续存储的,这使得它的访问效率非常高。

数组的特点

  1. 有序集合:数组中的元素按照插入顺序排列
  2. 索引访问:每个元素都有对应的从0开始的整数索引
  3. 连续内存:数组元素在内存中是连续存储的
  4. 动态大小:在JavaScript中数组长度可以动态变化
  5. 混合类型:可以存储不同类型的数据

数组的创建方式

1. 字面量方式(推荐)

// 创建数字数组
let numbers = [1, 2, 3, 4, 5]; // 创建字符串数组
let fruits = ['apple', 'banana', 'orange'];// 创建混合类型数组
let mixed = [1, 'text', true, null, {name: 'John'}];// 创建空数组
let empty = [];

2. 构造函数方式

// 创建包含元素的数组
let arr = new Array(6, 7, 8, 9, 10);// 创建指定长度的空数组
let emptyArr = new Array(5); // 长度为5,元素都是undefined// 创建单元素数组时要特别注意
let single = new Array(5); // 创建的是长度为5的空数组
let singleCorrect = [5]; // 这才是包含数字5的数组

数组的访问和修改

let products = ['手机', '电脑', '平板', '耳机', '鼠标'];// 访问元素
console.log(products[0]); // 输出:"手机"
console.log(products[2]); // 输出:"平板"// 访问不存在的索引
console.log(products[10]); // 输出:undefined// 修改元素
products[1] = '笔记本电脑'; // 修改第二个元素
products[3] = '蓝牙耳机'; // 修改第四个元素// 添加新元素
products[5] = '键盘'; // 添加新元素
products[10] = '显示器'; // 这会创建空位(empty items)console.log(products); 
// 输出:['手机', '笔记本电脑', '平板', '蓝牙耳机', '鼠标', '键盘', 空 × 4, '显示器']

数组的常用方法和属性

1. 添加/删除元素

// 初始化数组
let tasks = ['学习', '运动'];// push() - 末尾添加
tasks.push('阅读'); // 添加单个
tasks.push('购物', '做饭'); // 添加多个// pop() - 末尾删除
let lastTask = tasks.pop(); // 删除并返回'做饭'// unshift() - 开头添加
tasks.unshift('起床'); // 添加单个
tasks.unshift('刷牙', '洗脸'); // 添加多个// shift() - 开头删除
let firstTask = tasks.shift(); // 删除并返回'刷牙'console.log(tasks); // 输出:['洗脸', '起床', '学习', '运动', '阅读']

2. 数组长度

let colors = ['red', 'green', 'blue'];// 获取长度
console.log(colors.length); // 输出:3// 修改长度
colors.length = 5; // 扩展数组
console.log(colors); // 输出:['red', 'green', 'blue', empty × 2]colors.length = 2; // 截断数组
console.log(colors); // 输出:['red', 'green']// 清空数组
colors.length = 0;
console.log(colors); // 输出:[]

3. 其他常用方法

// 初始化数组
let numbers = [1, 2, 3, 4, 5];// slice() - 提取子数组
let subArr = numbers.slice(1, 4); // [2, 3, 4]
let lastTwo = numbers.slice(-2); // [4, 5]// splice() - 修改数组
// 删除
numbers.splice(2, 1); // 从索引2开始删除1个 → [1, 2, 4, 5]
// 插入
numbers.splice(2, 0, 3); // 在索引2插入3 → [1, 2, 3, 4, 5]
// 替换
numbers.splice(1, 2, 'a', 'b'); // [1, 'a', 'b', 4, 5]// concat() - 合并数组
let arr1 = [1, 2];
let arr2 = [3, 4];
let combined = arr1.concat(arr2, [5, 6]); // [1, 2, 3, 4, 5, 6]

实际应用示例

示例1:购物车商品管理

// 初始化购物车
let cart = [];// 添加商品
function addProduct(id, name, price) {cart.push({id, name, price});console.log(`已添加: ${name}`);
}// 移除商品
function removeProduct(index) {if (index >= 0 && index < cart.length) {let removed = cart.splice(index, 1);console.log(`已移除: ${removed[0].name}`);} else {console.log('无效的索引');}
}// 计算总价
function calculateTotal() {return cart.reduce((total, item) => total + item.price, 0);
}// 使用示例
addProduct(1, 'iPhone 13', 5999);
addProduct(2, 'AirPods Pro', 1499);
addProduct(3, 'MacBook Pro', 12999);console.log('当前购物车:');
cart.forEach((item, index) => {console.log(`${index + 1}. ${item.name} - ¥${item.price}`);
});removeProduct(1); // 移除AirPods Proconsole.log(`总价: ¥${calculateTotal()}`);

示例2:成绩处理系统

// 初始化成绩数组
let scores = [85, 90, 78, 92, 88];// 计算统计信息
function calculateStats(scores) {if (scores.length === 0) return null;// 计算总分和平均分let sum = scores.reduce((a, b) => a + b, 0);let average = sum / scores.length;// 计算最高分和最低分let max = Math.max(...scores);let min = Math.min(...scores);// 找出不及格的成绩let failed = scores.filter(score => score < 60);return {count: scores.length,sum,average: average.toFixed(2),max,min,failedCount: failed.length,failedScores: failed};
}// 添加新成绩
function addScore(newScore) {scores.push(newScore);console.log(`已添加成绩: ${newScore}`);
}// 删除最低分
function removeLowest() {let minIndex = scores.indexOf(Math.min(...scores));if (minIndex !== -1) {let removed = scores.splice(minIndex, 1);console.log(`已移除最低分: ${removed[0]}`);}
}// 使用示例
console.log('初始成绩:', scores.join(', '));
addScore(95);
removeLowest();let stats = calculateStats(scores);
console.log('统计信息:');
console.log(`数量: ${stats.count}`);
console.log(`总分: ${stats.sum}`);
console.log(`平均分: ${stats.average}`);
console.log(`最高分: ${stats.max}`);
console.log(`最低分: ${stats.min}`);
console.log(`不及格数量: ${stats.failedCount}`);

九、对象

对象的基本概念

对象是JavaScript中最重要的数据类型之一,它是一个无序的键值对集合,用于存储和表示复杂的数据结构。在对象中:

  1. 键(key):称为属性(property),必须是字符串或Symbol类型。属性名遵循标识符命名规则,但也可以使用引号包裹特殊字符作为属性名。

  2. 值(value):称为属性值,可以是任意JavaScript数据类型,包括:

    • 基本类型:字符串、数字、布尔值、null、undefined
    • 复杂类型:数组、函数、其他对象
    • 特殊类型:Symbol、BigInt
  3. 属性描述符:每个属性还有一组描述其特性的属性描述符,包括:

    • value:属性的值
    • writable:是否可修改(默认true)
    • enumerable:是否可枚举(默认true)
    • configurable:是否可配置(默认true)
    • get/set:访问器函数

例如,在浏览器环境中,document对象就是一个典型的JavaScript对象,它包含了大量属性和方法来操作DOM。

对象的创建方式

1. 对象字面量方式

这是最常用的创建对象方式,使用大括号{}语法,适合创建简单的、一次性的对象:

let person = {// 基本类型属性name: "张三",      // 字符串属性age: 20,          // 数字属性isStudent: true,  // 布尔属性// 复杂类型属性courses: ["数学", "语文", "英语"],  // 数组属性address: {        // 嵌套对象city: "北京",street: "中关村大街",getFullAddress() {return `${this.city} ${this.street}`}},// 方法属性sayHello: function() {console.log("Hello, I'm " + this.name);},// ES6简写方法introduce() {console.log(`我叫${this.name},今年${this.age}岁`);},// 计算属性名["id_" + Math.random().toString(36).substr(2)]: "随机ID"
};// 使用对象
person.sayHello();  // 输出: Hello, I'm 张三
console.log(person.address.getFullAddress());  // 输出: 北京 中关村大街

2. 使用Object构造函数

通过new Object()创建空对象,再动态添加属性,适合需要动态构建对象的场景:

let student = new Object();  // 创建一个空对象// 添加属性
student.name = "李四";
student.age = 18;// 添加方法
student.study = function(subject) {console.log(`${this.name}正在学习${subject}`);
};// 添加嵌套对象
student.scores = new Object();
student.scores.math = 90;
student.scores.english = 85;// 使用对象
student.study("数学");  // 输出: 李四正在学习数学
console.log(student.scores.math);  // 输出: 90

3. 使用Object.create()方法

可以指定原型对象创建新对象,适合需要继承的场景:

let animal = {type: "动物",makeSound() {console.log("发出声音");}
};let dog = Object.create(animal);
dog.type = "狗";
dog.breed = "金毛";
dog.bark = function() {console.log("汪汪!");
};dog.makeSound();  // 继承自animal: 发出声音
dog.bark();       // 输出: 汪汪!

4. 使用构造函数和new操作符

适合需要创建多个相似对象的场景:

function Car(make, model, year) {this.make = make;this.model = model;this.year = year;this.displayInfo = function() {console.log(`${this.year} ${this.make} ${this.model}`);};
}let myCar = new Car("Toyota", "Camry", 2020);
myCar.displayInfo();  // 输出: 2020 Toyota Camry

对象属性的访问和操作

1. 点表示法访问

最常用的属性访问方式,简洁直观:

let person = {name: "张三",age: 20,"first-name": "张"  // 包含特殊字符的属性名
};// 访问属性
console.log(person.name);  // 输出"张三"// 修改属性
person.age = 21;  // 修改age属性
console.log(person.age);  // 输出21// 添加新属性
person.gender = "男";
console.log(person.gender);  // 输出"男"// 无法访问特殊字符属性
// console.log(person.first-name);  // 报错

2. 方括号表示法访问

当属性名包含特殊字符或需要动态计算时使用:

let person = {"first-name": "张","last-name": "三",1: "数字作为属性名",[Symbol("id")]: "symbol作为属性名"
};// 访问特殊字符属性
console.log(person["first-name"]);  // 输出"张"// 动态访问属性
let propName = "last-name";
console.log(person[propName]);  // 输出"三"// 数字属性名
console.log(person[1]);  // 输出"数字作为属性名"
console.log(person["1"]); // 同上// Symbol属性名
let sym = Symbol("id");
console.log(person[sym]);  // 输出"symbol作为属性名"// 添加计算属性
let dynamicProp = "score_" + Math.floor(Math.random() * 10);
person[dynamicProp] = 95;
console.log(person[dynamicProp]);

3. 属性操作

删除属性

使用delete操作符删除对象属性:

let person = {name: "张三",age: 20,gender: "男"
};console.log("age" in person);  // 输出true
delete person.age;
console.log(person.age);       // 输出undefined
console.log("age" in person);  // 输出false

检查属性存在
let person = {name: "张三"};// in操作符检查属性是否存在(包括原型链)
console.log("name" in person);      // true
console.log("toString" in person);  // true (继承自Object.prototype)// hasOwnProperty检查自有属性
console.log(person.hasOwnProperty("name"));      // true
console.log(person.hasOwnProperty("toString"));  // false

遍历属性
let person = {name: "张三",age: 20,gender: "男"
};// for...in循环(包含继承的可枚举属性)
for (let key in person) {console.log(key + ": " + person[key]);
}// Object.keys()获取自有可枚举属性
let keys = Object.keys(person);
console.log(keys);  // ["name", "age", "gender"]// Object.getOwnPropertyNames()获取所有自有属性
let allProps = Object.getOwnPropertyNames(person);
console.log(allProps);// Object.getOwnPropertySymbols()获取Symbol属性
let symbols = Object.getOwnPropertySymbols(person);
console.log(symbols);

对象方法的定义和调用

1. 定义方法

方法本质上是一个函数类型的属性,有多种定义方式:

let calculator = {// 传统函数表达式add: function(a, b) {return a + b;},// ES6方法简写subtract(a, b) {return a - b;},// 箭头函数(注意this的指向问题)multiply: (a, b) => a * b,// 生成器方法*generateSequence(start, end) {for (let i = start; i <= end; i++) {yield i;}},// 异步方法async fetchData(url) {let response = await fetch(url);return await response.json();}
};

2. 调用方法

使用点表示法或方括号表示法调用对象方法:

let person = {name: "张三",age: 20,// 方法定义sayHello() {console.log(`你好,我是${this.name},今年${this.age}岁`);},// 另一个方法celebrateBirthday() {this.age++;console.log(`庆祝生日!现在${this.age}岁了`);}
};// 直接调用
person.sayHello();              // 输出: 你好,我是张三,今年20岁// 动态调用
let methodName = "sayHello";
person[methodName]();           // 同上// 链式调用
person.celebrateBirthday().sayHello();  // 先增加年龄,再打招呼

3. 方法中的this

在对象方法中,this指向调用该方法的对象,但需要注意一些特殊情况:

let person = {name: "Alice",greet: function() {console.log("Hi, I'm " + this.name);},greetArrow: () => {console.log("Hi, I'm " + this.name);  // 箭头函数没有自己的this}
};// 直接调用
person.greet();        // 输出: Hi, I'm Alice
person.greetArrow();   // 输出: Hi, I'm undefined (或全局name)// 方法赋值给变量
let greetFunc = person.greet;
greetFunc();           // 输出: Hi, I'm undefined (this丢失)// 使用bind绑定this
let boundGreet = person.greet.bind(person);
boundGreet();          // 输出: Hi, I'm Alice// 作为回调函数
setTimeout(person.greet, 1000);             // this丢失
setTimeout(person.greet.bind(person), 1000); // 正确绑定

4. Getter和Setter

可以使用getter和setter定义访问器属性:

let user = {firstName: "张",lastName: "三",// getterget fullName() {return `${this.firstName} ${this.lastName}`;},// setterset fullName(value) {[this.firstName, this.lastName] = value.split(" ");}
};console.log(user.fullName);  // 输出: 张 三
user.fullName = "李 四";
console.log(user.firstName); // 输出: 李
console.log(user.lastName);  // 输出: 四

对象的高级特性

1. 属性描述符

可以使用Object.defineProperty定义或修改属性特性:

let obj = {};Object.defineProperty(obj, "readOnlyProp", {value: 42,writable: false,enumerable: true,configurable: false
});console.log(obj.readOnlyProp);  // 42
obj.readOnlyProp = 100;        // 静默失败(严格模式下报错)
console.log(obj.readOnlyProp); // 仍然是42// 获取属性描述符
let descriptor = Object.getOwnPropertyDescriptor(obj, "readOnlyProp");
console.log(descriptor);

2. 对象冻结

可以限制对象的修改:

let person = {name: "张三",age: 20
};// 1. Object.preventExtensions: 禁止添加新属性
Object.preventExtensions(person);
person.gender = "男";  // 静默失败(严格模式下报错)// 2. Object.seal: 禁止添加/删除属性
Object.seal(person);
delete person.name;    // 静默失败// 3. Object.freeze: 完全冻结对象
Object.freeze(person);
person.age = 21;      // 静默失败// 检查对象状态
console.log(Object.isExtensible(person));  // false
console.log(Object.isSealed(person));      // true
console.log(Object.isFrozen(person));       // true

3. 原型和继承

JavaScript使用原型链实现继承:

// 父类
function Animal(name) {this.name = name;
}
Animal.prototype.speak = function() {console.log(`${this.name} makes a noise.`);
};// 子类
function Dog(name) {Animal.call(this, name);  // 调用父类构造函数
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() {console.log(`${this.name} barks.`);
};let d = new Dog("Rex");
d.speak();  // 输出: Rex barks.

4. ES6类语法

ES6引入了更简洁的类语法:

class Person {constructor(name, age) {this.name = name;this.age = age;}greet() {console.log(`Hello, I'm ${this.name}`);}static createAnonymous() {return new Person("Anonymous", 0);}
}class Student extends Person {constructor(name, age, grade) {super(name, age);  // 调用父类构造函数this.grade = grade;}study() {console.log(`${this.name} is studying`);}
}let student = new Student("张三", 20, "A");
student.greet();  // 输出: Hello, I'm 张三
student.study();  // 输出: 张三 is studying

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93513.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93513.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytest中使用loguru的问题及解决

引语 上一篇文章,我们向大家推荐了python语言的一个第三方日志库loguru,使用非常简单且功能完备。 但对于我们做自动化测试,经常使用 pytest 框架的小伙伴来说,却有点小问题。就是 Pytest 内建的日志捕获机制是在标准库 logging 的基础上进行优化过的。 这样我们在使用 p…

Qt异步编程:QFuture与QPromise深度解析

在现代GUI应用中&#xff0c;异步操作是保证界面流畅性的关键。本文将深入探讨Qt框架中强大的异步工具——QFuture和QPromise&#xff0c;揭示它们如何简化多线程编程并提升应用性能。 为什么需要QFuture/QPromise&#xff1f; 在Qt开发中&#xff0c;我们经常面临这样的挑战&a…

基于Python的电影评论数据分析系统 Python+Django+Vue.js

本文项目编号 25008 &#xff0c;文末自助获取源码 \color{red}{25008&#xff0c;文末自助获取源码} 25008&#xff0c;文末自助获取源码 目录 一、系统介绍1.1 用户功能1.2 管理员功能 二、系统录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状 六、…

数据结构:在二叉搜索树中插入元素(Insert in a BST)

目录 插入的本质是什么&#xff1f; 如何寻找“合法”的位置&#xff1f;—— 模拟查找过程 递归插入&#xff08;Recursive Insert&#xff09;—— 优雅的实现 代码逐步完善 总结 上一节我们从第一性原理搞清楚了二叉搜索树&#xff08;BST&#xff09;是什么&#xff0…

【论文阅读】美 MBSE 方法发展分析及启示(2024)

文章目录 论文摘要 论文框架 1. MBSE 方法概述 2. 美国防部的 MBSE 方法政策要求 在这里插入图片描述 3. 美军兵种的 MBSE 方法政策要求 4. 启示 5.总结 参考文献 论文摘要 本文梳理了美国防部基于模型的系统工程(MBSE)方法的发展历程,并剖析 其技术原理;跟踪《数字工程战略…

人工智能训练师复习题目实操题1.1.1 - 1.1.5

列出所有的python 库和 apiimport pandas as pd import numpy as np就这两个库pandas 库 - apinumpy 库 - apimatplotlib.pyplot - apipd.read_csv()np.where(condition,x,y)fillna(methodffill,inplaceTrue)methodbfill,pd.read_excel()np返回结果 series 对象 data[A列].valu…

旅游管理实训室:旅游教育实践育人的关键支撑

在中等职业教育旅游服务与管理专业教学中&#xff0c;旅游管理实训室并非简单的教学场所&#xff0c;而是落实专业教学标准、实现 “理实一体化” 育人的核心阵地。它通过模拟真实职业场景、配置专业实训设备、设计实践教学活动&#xff0c;将抽象的专业知识转化为具体的操作技…

http工作流程

HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;是互联网中客户端与服务器之间传输超文本&#xff08;如HTML、图片、JSON等&#xff09;的核心协议&#xff0c;基于请求-响应模型和TCP/IP协议族工作。其完整工作流程可拆解为以下9个核心步…

正则表达式实用面试题与代码解析专栏

正则表达式是前端表单验证、字符串匹配的核心工具,简洁高效的正则能大幅提升代码性能。本专栏整理了7道高频面试题,包含核心正则表达式、代码实现及关键知识点解析,帮你快速掌握正则实用技巧。 一、正则基础:核心概念与语法 在学习面试题前,先明确几个高频基础语法,这是…

【数据可视化-89】基孔肯雅热病例数据分析与可视化:Python + pyecharts洞察疫情动态

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

云智智慧停充一体云-allnew全新体验-路内停车源码+路外停车源码+充电桩源码解决方案

采用Java主流的微服务技术栈&#xff0c;基于 Spring Cloud Alibaba 的微服务解决方案进行封装的快速开发平台&#xff0c;包含多种常用开箱即用功能的模块&#xff0c;通用技术组件与服务、微服务治理&#xff0c;具备RBAC功能、网关统一鉴权、Xss防跨站攻击、自动生成前后端代…

利用pypy加速pyxlsbwriter生成xlsb文件

上文介绍了python通过DuckDB和pyxlsbwriter模块生成xlsb文件&#xff0c;因为python是解释执行&#xff0c;它的速度有点慢&#xff0c;pypy是另一种python解释器&#xff0c;它使用即时编译&#xff08;JIT&#xff09;技术来提高执行速度。 因为DuckDB与pypy不兼容&#xff0…

【Java后端】Spring Boot 集成 MyBatis-Plus 全攻略

Spring Boot 集成 MyBatis-Plus 全攻略 1. 为什么选择 MyBatis-Plus 零侵入&#xff1a;在 MyBatis 基础上增强&#xff0c;不影响现有功能。内置 CRUD&#xff1a;无需写 XML/SQL&#xff0c;直接调用 BaseMapper 方法。强大插件&#xff1a;分页插件、性能分析、乐观锁、多租…

LangChain 多任务应用开发

Q: LangChain dify coze是竞品关系 都是AI Agent搭建平台&#xff0c;dify和coze 属于低代码&#xff0c;langChain属于高代码&#xff0c;coze优于dify Q&#xff1a;向量数据库是存储向量&#xff0c;做相似度检索的&#xff0c;可以用faiss milvus chromdb Q&#xff1a;使用…

实用技巧:Oracle中精准查看表占用空间大小

目录实用技巧&#xff1a;Oracle中精准查看表占用空间大小一、为什么需要精准统计表空间占用&#xff1f;二、完整查询SQL&#xff1a;覆盖表、LOB、索引三、SQL语句关键逻辑解析1. 基础表&#xff1a;dba_tables 与 dba_tablespaces2. 子查询1&#xff1a;统计表段空间&#x…

openEuler等Linux系统中如何复制移动硬盘的数据

在 openEuler 系统中,提示 “You should mount volume first” ,意思是需要先挂载移动硬盘的分区才能访问: 安装必要软件(针对特殊文件系统) 如果移动硬盘是 NTFS 等非 Linux 原生支持的文件系统格式,需要安装对应的支持软件,以挂载 NTFS 格式移动硬盘为例,需要安装 …

java如何把字符串数字转换成数字类型

在Java中将字符串数字转换为数字类型有多种方法&#xff0c;以下是详细说明和示例代码&#xff1a; 一、基础转换方法 Integer.parseInt() String str "123"; int num Integer.parseInt(str); // 转换为intDouble.parseDouble() String str "3.14"; dou…

WPFC#超市管理系统(6)订单详情、顾客注册、商品销售排行查询和库存提示、LiveChat报表

WPF&C#超市管理系统10. 订单详情10.1 页面布局10.2 功能实现11. 顾客注册12. 商品销售排行查询与库存提示14. LiveChart报表总结10. 订单详情 10.1 页面布局 页面分三行布置&#xff0c;第一行复用OutstorageView界面的第一行&#xff0c;将属性和命令修改为顾客相关第二…

【Linux】文件基础IO

1.关于文件的共识原理 1.文件内容属性 2.文件分为打开的文件和没打开的文件 3.打开的文件&#xff1a; 文件被打开必须先被加载到内存&#xff0c;所以本质是研究进程和文件的关系&#xff0c;一个进程可以打开多个文件。操作系统内部一定存在大量被打开的文件&#xff0c;要进…

基于微信小程序的生态农产销售管理的设计与实现/基于C#的生态农产销售系统的设计与实现、基于asp.net的农产销售系统的设计与实现

基于微信小程序的生态农产销售管理的设计与实现/基于C#的生态农产销售系统的设计与实现、基于asp.net的农产销售系统的设计与实现