一、Variables变量
(1)变量的声明方式。
在 JavaScript 中,let
、const
和 var
是用于声明变量的关键字,但它们在作用域、可变性、以及提升(Hoisting)行为上有所不同。下面是对这三者的详细解释:
1. var
:
-
作用域:
var
声明的变量有函数作用域,意味着如果var
在函数内声明,变量只在函数内有效。如果在函数外部声明,变量会成为全局变量。 -
提升(Hoisting):
var
声明的变量会在作用域内“提升”到顶部,这意味着你可以在声明之前访问该变量,但它的值为undefined
。 -
可重复声明:在同一个作用域中,可以多次使用
var
来声明同一个变量,不会抛出错误。例子:
2. let
:
-
作用域:
let
声明的变量有块级作用域,即它仅在最近的代码块(如{}
)内有效。 -
提升(Hoisting):
let
变量也会被提升,但不会被初始化,即你不能在声明之前使用它,若使用会报错。其作用域从声明处开始。 -
可重复声明:在同一作用域内不能重复声明同一个变量,使用
let
会抛出错误。例子:
let与var声明的变量可以被重新赋值:
三者均具备有块级作用域:
3. const
:
-
作用域:
const
与let
一样,也有块级作用域。 -
提升(Hoisting):
const
变量也会被提升,但和let
一样,不能在声明之前访问。 -
不可变性:
const
用于声明常量,意味着声明后其值不能再改变(对于原始数据类型如number
、string
等)。但如果const
声明的是一个对象或数组,虽然引用不能变,但对象或数组的内容仍然可以修改。 -
可重复声明:与
let
相同,不能在同一作用域内重复声明同一个变量。例子:
总结:
var
:函数作用域、会提升、可重复声明、不推荐使用(因为有些行为可能造成问题)。let
:块级作用域、会提升但不会初始化、不可重复声明,通常用于可变值。const
:块级作用域、会提升但不会初始化、不可重复声明、声明常量,通常用于不可变值或引用不变的对象。
通常,建议在 JavaScript 中优先使用 let
和 const
,而尽量避免使用 var
,因为 var
在作用域和提升方面的行为较为复杂,容易导致意外错误。
(2)变量的类型
JavaScript 中的基本数据类型包括以下几种:
1. 原始数据类型 (Primitive Types)
原始数据类型是不可变的,也就是说它们的值一旦被创建,就不能被改变。原始数据类型包括:
- String:表示文本数据,例如
'hello'
或"world"
。 - Number:表示数字,包括整数和浮点数,例如
123
或3.14
。 - BigInt:用于表示任意大小的整数,常用于处理大数,例如
123n
。 - Boolean:表示布尔值,只有两个值:
true
或false
。 - undefined:表示变量未赋值时的初始状态,例如:
let x; console.log(x); // 输出:undefined
- null:表示“无”或“空”的值,通常用于表示一个空对象引用:
let y = null;
- Symbol:表示唯一的、不可变的值,通常用于创建对象的唯一标识符:
let sym = Symbol('description');
2. 引用数据类型 (Reference Types)
引用数据类型是由多个值组成的数据结构,它们是可变的。引用数据类型包括:
- Object:表示一组键值对的数据结构。对象可以包含多个属性和方法。例如:
let person = {name: "John",age: 30 };
- Array:数组是一种特殊的对象,表示一系列按顺序排列的值。例如:
let fruits = ['apple', 'banana', 'cherry'];
- Function:函数也是一种对象,代表一段可以执行的代码。例如:
function greet() {console.log('Hello, world!'); }
- Date:用于表示日期和时间的对象。例如:
let now = new Date();
3. 类型转换
在 JavaScript 中,原始数据类型和引用数据类型之间是可以进行转换的。例如,字符串和数字之间可以转换,或者将 null
和 undefined
作为特殊值来处理。
总结
JavaScript 的数据类型分为两类:
- 原始数据类型:
String
、Number
、BigInt
、Boolean
、undefined
、null
和Symbol
。 - 引用数据类型:
Object
、Array
、Function
和Date
。
这些数据类型是构建 JavaScript 程序的基础。了解它们之间的区别和使用方法对于高效编程非常重要!
二、Functions 函数
(1)基本概念
在 JavaScript 中,函数是非常重要的一部分,它帮助你封装代码,实现可复用性。下面我会从几个方面详细解释 JavaScript 中的函数。
(2)函数的声明方式
JavaScript 中有几种声明函数的方式:
1.这种方式是最常见的函数声明方式,它通过 function
关键字来声明一个函数。
function FunctionName(){console.log("hello world");
}
2.函数也可以作为一个表达式被赋值给变量。这个方式常用于匿名函数。
const FunctionName = function(){console.log("hello world");
}
3.箭头函数是 ES6 引入的一种简化的函数写法,语法更简洁,尤其适合用作回调函数。
const FunctionName = () => {console.log("hello world");
}
(3) 函数参数
函数可以接受参数,这些参数可以是任何类型的数据,包括基本类型、对象、数组等。
const FunctionName = (name) => {console.log(`hello ${name}`);
}
如果函数未传递足够的参数,JavaScript 会将未传入的参数设为 undefined
。
(4) 返回值(Return)
函数可以通过 return
语句返回一个值。如果没有显式的 return
,默认返回 undefined
。
const FunctionName = (a,b) => {return a+b;}
(5)函数作用域(Scope)
JavaScript 函数有自己的作用域,意味着函数内部定义的变量不能在函数外部访问,反之亦然。
5. 闭包(Closure)
闭包是指函数可以“记住”并访问它定义时的作用域,即使该函数在外部作用域执行时,仍然可以访问原作用域中的变量。
javascript
复制编辑
function outer() { let count = 0; return function inner() { count++; console.log(count); }; } const counter = outer(); counter(); // 输出 1 counter(); // 输出 2
6. 函数的 this
关键字
this
关键字指向函数调用时的上下文对象。在普通函数中,this
通常指向全局对象(在浏览器中是 window
),在对象方法中,this
指向调用该方法的对象。
javascript
复制编辑
function show() { console.log(this); } show(); // 在浏览器中输出 window 对象 const obj = { name: "Alice", greet: function() { console.log(this.name); } }; obj.greet(); // 输出 "Alice"
7. 函数重载
JavaScript 不支持传统意义上的函数重载。即不能根据参数的数量或类型来区分多个同名函数。你可以在函数体内根据参数的不同情况来手动处理不同的功能。
javascript
复制编辑
function greet(name, age) { if (arguments.length === 1) { console.log(`Hello, ${name}!`); } else if (arguments.length === 2) { console.log(`Hello, ${name}, you are ${age} years old!`); } } greet("Alice"); // 输出 "Hello, Alice!" greet("Alice", 30); // 输出 "Hello, Alice, you are 30 years old!"
8. 高阶函数
在 JavaScript 中,函数可以作为参数传递给其他函数,或者返回一个函数。这种函数被称为高阶函数。
javascript
复制编辑
function greet(name, callback) { console.log(`Hello, ${name}!`); callback(); } greet("Alice", function() { console.log("Goodbye!"); });
9. 立即调用函数表达式(IIFE)
立即调用函数表达式(IIFE)是指声明并立即执行的函数。它常用于创建一个独立的作用域,避免污染全局命名空间。
javascript
复制编辑
(function() { console.log("This function is invoked immediately!"); })();
10. 函数的默认参数
在 ES6 中,函数的参数可以设定默认值,若调用时没有传递参数,则会使用默认值。
javascript
复制编辑
function greet(name = "Guest") { console.log(`Hello, ${name}!`); } greet(); // 输出 "Hello, Guest!" greet("Alice"); // 输出 "Hello, Alice!"
总结
JavaScript 中的函数非常灵活,具有多种特性,比如匿名函数、箭头函数、闭包、作用域、this
关键字等。通过函数,你可以实现代码的封装、复用和更好的结构化。
三、object面向对象编程
在 JavaScript 中,Object
是一种数据类型,它用于存储键值对。对象可以包含多种类型的属性,包括数字、字符串、函数等。JavaScript 中的对象非常灵活,可以用来表示现实世界的各种事物,比如人、车、学生等。接下来我会详细介绍 JavaScript 中对象的相关知识。
定义object类型的变量
判断变量是否是对象
1. 创建对象
对象可以通过多种方式来创建:
1.1 对象字面量(Object Literal)
最常用的方式是通过对象字面量创建对象,即使用 {}
来创建一个对象。
const person = {name: "Alice",age: 25,greet: function() {console.log(`Hello, my name is ${this.name}.`);}
};
1.2 new Object()
语法
你也可以使用 new Object()
来创建对象,不过这种方式较为少见。
const person = new Object();
person.name = "Alice";
person.age = 25;
person.greet = function() {console.log(`Hello, my name is ${this.name}.`);
};
2. 访问对象的属性
可以通过两种方式来访问对象的属性:
2.1 点操作符(Dot Notation)
console.log(person.name); // 输出 "Alice"
console.log(person.age); // 输出 25
2.2 方括号操作符(Bracket Notation)
这种方式适合当属性名是动态的或者包含特殊字符时。
console.log(person["name"]); // 输出 "Alice"
console.log(person["age"]); // 输出 25
3. 修改对象的属性
你可以直接修改对象的属性:
person.name = "Bob"; // 修改 name 属性
console.log(person.name); // 输出 "Bob"
或者使用方括号语法:
person["age"] = 30;
console.log(person.age); // 输出 30
4. 添加新的属性
你可以随时为对象添加新的属性:
person.address = "123 Main St";
console.log(person.address); // 输出 "123 Main St"
5. 删除对象的属性
使用 delete
操作符可以删除对象的属性:
delete person.age;
console.log(person.age); // 输出 undefined
6. 对象的遍历
6.1 for...in
循环
for...in
循环用于遍历对象的所有可枚举属性。
for (let key in person) {console.log(key, person[key]);
}
// 输出:
// name Bob
// greet [Function: greet]
// address 123 Main St
6.2 Object.keys()
和 forEach
Object.keys()
返回对象的所有属性名组成的数组,你可以使用 forEach
来遍历:
Object.keys(person).forEach(function(key) {console.log(key, person[key]);
});
// 输出:
// name Bob
// greet [Function: greet]
// address 123 Main St
7. 对象的this
关键字
在对象的方法中,this
关键字通常指向调用该方法的对象。
const person = {name: "Alice",greet: function() {console.log(`Hello, my name is ${this.name}.`);}
};
person.greet(); // 输出 "Hello, my name is Alice."
8. 对象的方法
对象不仅可以包含数据,还可以包含方法。方法是对象的属性,它的值是一个函数。
const person = {name: "Alice",greet: function() {console.log(`Hello, my name is ${this.name}.`);}
};
person.greet(); // 输出 "Hello, my name is Alice."
9. 对象的constructor
属性
每个对象都有一个 constructor
属性,它指向创建该对象的构造函数。例如,普通对象的构造函数是 Object
。
const person = {name: "Alice"
};
console.log(person.constructor); // 输出 [Function: Object]
10. 对象的 Object
方法
10.1 Object.keys()
Object.keys()
返回一个包含对象所有属性名称的数组。
const person = { name: "Alice", age: 25 };
console.log(Object.keys(person)); // 输出 ["name", "age"]
10.2 Object.values()
Object.values()
返回一个包含对象所有属性值的数组。
console.log(Object.values(person)); // 输出 ["Alice", 25]
10.3 Object.entries()
Object.entries()
返回一个包含对象所有键值对的二维数组。
console.log(Object.entries(person));
// 输出 [["name", "Alice"], ["age", 25]]
10.4 Object.assign()
Object.assign()
用于将一个或多个源对象的所有可枚举属性复制到目标对象。
const person = { name: "Alice" };
const details = { age: 25, gender: "female" };
const newPerson = Object.assign({}, person, details);
console.log(newPerson); // 输出 { name: "Alice", age: 25, gender: "female" }
11. 对象的原型
每个 JavaScript 对象都有一个原型(prototype),通过原型,子对象可以继承父对象的属性和方法。
const person = {name: "Alice",greet: function() {console.log(`Hello, my name is ${this.name}.`);}
};const student = Object.create(person);
student.grade = "A";
student.greet(); // 输出 "Hello, my name is Alice."(继承自person对象的方法)
console.log(student.grade); // 输出 "A"
12. 类(Class)与对象
在 JavaScript 中,你可以使用类(ES6 引入)来定义对象的模板。类本质上是一个构造函数。
class Person {constructor(name, age) {this.name = name;this.age = age;}greet() {console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);}
}const person = new Person("Alice", 25);
person.greet(); // 输出 "Hello, my name is Alice and I am 25 years old."
Document Object Model (DOM) in JavaScript
DOM(文档对象模型)是浏览器提供的一种 API(应用程序接口),允许开发者通过编程的方式访问和操作 HTML 或 XML 文档的结构。DOM 把网页的结构表示为一个树形结构,网页中的每个元素都被表示为树的一个节点。
1. DOM的基本概念
-
文档对象模型(DOM)是网页的表示形式。它把整个网页结构转化为树形结构,其中每个节点代表网页中的一个部分,例如元素、属性、文本等。
-
DOM 树:DOM 将网页中的每个元素都看作是一个对象,形成了一个类似树形的结构,这个树形结构可以通过 JavaScript 操控。
比如,网页内容:
<html><body><div id="container"><p>Hello, World!</p></div></body> </html>
它对应的 DOM 树是:
HTML├── HEAD└── BODY└── DIV (id="container")└── P└── "Hello, World!"
2. DOM 树的节点类型
DOM 树包含多种类型的节点,主要有:
- 元素节点(Element Nodes):代表 HTML 标签,如
<div>
、<p>
等。 - 文本节点(Text Nodes):代表 HTML 元素中的文本内容。
- 属性节点(Attribute Nodes):表示 HTML 元素的属性,例如
class
、id
等。 - 文档节点(Document Node):代表整个文档。
3. DOM 操作
JavaScript 可以通过 DOM 来访问和修改网页内容,DOM 提供了大量的方法来操作这些节点。
3.1 获取元素
DOM 提供了几种方法来获取元素或节点:
-
document.getElementById(id)
:通过元素的id
获取一个元素。const element = document.getElementById("container");
-
document.getElementsByClassName(className)
:通过元素的class
获取一组元素。const elements = document.getElementsByClassName("class-name");
-
document.getElementsByTagName(tagName)
:通过元素的标签名获取一组元素。const paragraphs = document.getElementsByTagName("p");
-
document.querySelector(selector)
:通过 CSS 选择器获取一个元素。const element = document.querySelector(".class-name");
-
document.querySelectorAll(selector)
:通过 CSS 选择器获取所有匹配的元素。const elements = document.querySelectorAll("p.class-name");
3.2 修改元素
一旦获取了元素,你就可以通过 JavaScript 修改它们的内容、样式、属性等。
-
修改文本内容:使用
textContent
或innerText
修改文本。const paragraph = document.querySelector("p"); paragraph.textContent = "New text!";
-
修改 HTML 内容:使用
innerHTML
修改元素的 HTML 内容。const div = document.querySelector("#container"); div.innerHTML = "<p>New HTML content</p>";
-
修改属性:使用
setAttribute()
方法修改元素的属性。const img = document.querySelector("img"); img.setAttribute("src", "new-image.jpg");
-
修改样式:使用
style
属性修改元素的样式。const div = document.querySelector("#container"); div.style.backgroundColor = "blue";
3.3 添加和删除元素
-
创建元素:使用
createElement()
创建一个新的元素。const newDiv = document.createElement("div");
-
添加元素到页面:使用
appendChild()
或insertBefore()
把新的元素添加到页面中。const parent = document.querySelector("#container"); parent.appendChild(newDiv);
-
删除元素:使用
removeChild()
删除一个子元素。const parent = document.querySelector("#container"); const child = document.querySelector("p"); parent.removeChild(child);
3.4 事件处理
DOM 允许你为页面上的元素添加事件监听器,以便在用户交互时执行代码。
-
添加事件监听器:使用
addEventListener()
为元素添加事件监听器。const button = document.querySelector("button"); button.addEventListener("click", function() {alert("Button clicked!"); });
-
移除事件监听器:使用
removeEventListener()
移除事件监听器。button.removeEventListener("click", function() {alert("Button clicked!"); });
4. DOM 中的导航
-
父节点(parentNode):获取元素的父节点。
const child = document.querySelector("p"); const parent = child.parentNode;
-
子节点(childNodes):获取元素的所有子节点。
const parent = document.querySelector("#container"); const children = parent.childNodes;
-
第一个子节点(firstChild):获取元素的第一个子节点。
const parent = document.querySelector("#container"); const firstChild = parent.firstChild;
-
最后一个子节点(lastChild):获取元素的最后一个子节点。
const parent = document.querySelector("#container"); const lastChild = parent.lastChild;
-
兄弟节点(nextSibling, previousSibling):获取元素的兄弟节点。
const element = document.querySelector("p"); const next = element.nextSibling; const previous = element.previousSibling;
5. DOM 的作用与应用
-
动态网页交互:DOM 使得网页能够响应用户的输入、点击等交互,动态地改变页面内容。
-
表单验证:通过 DOM 操控表单,可以验证用户输入的有效性,给用户提示信息。
-
AJAX 和 API 请求:DOM 可以与 JavaScript 中的异步请求(例如
fetch
或XMLHttpRequest
)结合,动态更新页面内容而无需刷新整个页面。
6. DOM 与性能
-
DOM 操作可能会比较慢,特别是在进行大量节点操作时。为了提高性能,尽量减少 DOM 的访问次数,使用一些优化技术(例如:批量操作,事件委托等)。
-
虚拟 DOM:一些现代框架(如 React)引入了虚拟 DOM 技术,它通过先在内存中更新虚拟 DOM,再与实际 DOM 进行比较,最后进行最小化的更新,从而提高页面性能。
7. 总结
- DOM 是浏览器提供的一种 API,用于表示和操作 HTML 或 XML 文档。通过 JavaScript,开发者可以访问和修改页面的结构、内容和样式。
- DOM 的操作是基于树形结构的,开发者可以使用 JavaScript 动态创建、删除、修改、访问网页元素。
- DOM 提供了事件处理机制,使得网页能够响应用户交互。
总结
JavaScript 中的对象是一个非常灵活的数据类型,它可以包含多个不同类型的数据和方法。对象通过键值对来存储数据,支持动态的属性修改和删除。对象的特性,如继承、原型链等,都是面向对象编程的重要概念。通过熟悉对象的使用,你可以更好地组织和管理你的代码。
flex和grid
在 CSS 中,flex
和 grid
是两种用于布局的现代技术,它们可以帮助你更灵活地创建响应式、复杂的网页布局。它们都提供了比传统的布局方式(如浮动和定位)更加简便和强大的工具。接下来,我将详细解释它们各自的概念和使用方法。
1. Flexbox(弹性盒子布局)
Flexbox 是一种一维布局模型,主要用于在 水平 或 垂直 方向上排列和分配空间,适用于需要沿某一方向(行或列)对元素进行对齐和分布的情况。
1.1 基础概念
Flexbox 布局的核心是通过设置容器的 display: flex
属性,将容器内的子元素变为弹性项(flex items),然后通过一些属性来控制这些子元素的排列方式。
1.2 主要属性
-
容器的属性(作用于父元素):
-
display: flex;
:定义一个 flex 容器。 -
flex-direction
:设置主轴的方向,决定了弹性项的排列方向。row
(默认值):水平排列,主轴从左到右。row-reverse
:水平排列,主轴从右到左。column
:垂直排列,主轴从上到下。column-reverse
:垂直排列,主轴从下到上。
-
justify-content
:控制弹性项在主轴方向上的对齐方式。flex-start
(默认值):将项目靠近主轴的起点对齐。flex-end
:将项目靠近主轴的终点对齐。center
:将项目居中对齐。space-between
:项目之间的间距相等,首尾项目靠近容器的两端。space-around
:项目之间的间距相等,项目两侧的间距也相等。
-
align-items
:控制弹性项在交叉轴(与主轴垂直的方向)上的对齐方式。stretch
(默认值):将项目拉伸以填满容器。flex-start
:项目在交叉轴的起点对齐。flex-end
:项目在交叉轴的终点对齐。center
:项目在交叉轴上居中对齐。baseline
:项目的基线对齐。
-
align-content
:控制多行之间的对齐方式。与align-items
类似,但它影响的是多行之间的对齐,而不是单行。
-
-
弹性项的属性(作用于子元素):
-
flex-grow
:定义弹性项如何伸展以填充额外空间。默认值是0
,表示不伸展。如果一个项的flex-grow
为1
,它就会占据剩余的空间。 -
flex-shrink
:定义弹性项如何缩小以适应容器。如果容器空间不足,子元素会根据该属性进行缩小。默认值是1
,表示可以缩小。 -
flex-basis
:定义弹性项的初始大小。可以使用像素、百分比等单位。默认值是auto
,表示元素的初始大小根据其内容决定。 -
flex
:一个简写属性,flex-grow
,flex-shrink
,flex-basis
的缩写,通常用来控制弹性项的扩展和缩小。 -
align-self
:允许单个子元素覆盖align-items
属性的对齐方式,可以为某一项设置不同的对齐方式。
-
1.3 Flexbox 示例
<div style="display: flex; justify-content: center; align-items: center; height: 200px;"><div style="width: 50px; height: 50px; background-color: red;"></div><div style="width: 50px; height: 50px; background-color: blue;"></div><div style="width: 50px; height: 50px; background-color: green;"></div>
</div>
这个例子中,flex
容器内的子元素被水平和垂直居中排列。
2. Grid Layout(网格布局)
Grid 是一种二维布局模型,允许你在 水平 和 垂直 方向上同时控制元素的排列和分布。它适用于更复杂的布局,比如分为多个区域的页面布局。
2.1 基础概念
Grid 布局通过设置容器的 display: grid
来启用,并通过定义 行(rows)和 列(columns)来规划元素的位置。
2.2 主要属性
-
容器的属性(作用于父元素):
-
display: grid;
:定义一个网格容器。 -
grid-template-columns
:定义网格的列。可以设置具体的列宽度,例如200px
,1fr
(占可用空间的1份),或auto
(根据内容宽度自动调整)。 -
grid-template-rows
:定义网格的行。类似于grid-template-columns
,用于设置行高。 -
grid-template-areas
:通过命名的区域来定义网格。每个子元素可以分配一个区域。 -
grid-gap
(或gap
):定义行和列之间的间距。 -
grid-auto-rows
和grid-auto-columns
:定义自动生成的行和列的大小(当元素超出预设的网格时)。
-
-
网格项的属性(作用于子元素):
-
grid-column
:定义元素跨越的列数。可以设置一个起始列和结束列,或者使用span
来指定跨越多少列。 -
grid-row
:定义元素跨越的行数,使用方式与grid-column
类似。 -
grid-area
:定义元素所占的区域,可以使用命名的区域来定位。 -
justify-items
:控制元素在水平(行)方向上的对齐方式。 -
align-items
:控制元素在垂直(列)方向上的对齐方式。 -
justify-self
和align-self
:分别控制单个元素在网格容器内的水平和垂直对齐方式。
-
2.3 Grid 示例
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; grid-gap: 10px;"><div style="background-color: red;">Item 1</div><div style="background-color: blue;">Item 2</div><div style="background-color: green;">Item 3</div>
</div>
在这个例子中,我们创建了一个有三列的网格布局,每列占据相等的空间,元素之间有 10px 的间距。
2.4 Grid 布局的优势
- 灵活性:Grid 可以轻松处理二维布局,适合设计复杂的页面结构。
- 简洁性:通过定义列和行,开发者可以轻松管理元素的对齐和分布。
3. Flexbox 和 Grid 的对比
特性 | Flexbox | Grid |
---|---|---|
布局方向 | 仅限于一维布局(行或列) | 支持二维布局(行和列) |
适用场景 | 简单的线性布局,适合小范围的排列 | 复杂的页面布局,适合大范围的区域布局 |
灵活性 | 灵活且适用于简单的布局 | 更加灵活,适用于复杂的布局 |
空间分配 | 支持在主轴方向上的空间分配 | 支持同时在水平和垂直方向上的空间分配 |
总结
- Flexbox:适用于一维布局,简单的对齐和空间分配,通常用于需要在行或列中对齐元素的情况。
- Grid:适用于二维布局,能够在行和列上同时控制布局,适合复杂的网页布局。
这两种布局方式可以单独使用,也可以结合起来使用,帮助开发者在现代网页设计中实现灵活且高效的布局。
CSS中的单位详解
CSS中的单位可分为多个类别,每种单位适用于不同的场景。以下是对各类单位的详细解释及示例:
一、绝对长度单位
基于物理测量,适合固定尺寸,但在不同设备上可能显示不一致。
-
px(像素):屏幕显示的基本单位(1px = 1/96英寸)。
width: 20px; /* 固定宽度为20像素 */
-
pt(点):印刷常用单位(1pt = 1/72英寸)。
font-size: 12pt; /* 字体大小为12点 */
-
in(英寸)、cm(厘米)、mm(毫米):
width: 2in; /* 2英寸 */ padding: 0.5cm; /* 0.5厘米 */
-
pc(派卡):1pc = 12pt。
line-height: 1.5pc; /* 18pt */
二、相对长度单位
相对于其他元素或视口的尺寸,灵活适应不同环境。
-
字体相关单位:
-
em:相对于父元素的字体大小。
.child { font-size: 1.5em; } /* 父元素字体为16px → 24px */
-
rem:相对于根元素(
<html>
)的字体大小。html { font-size: 16px; } .element { width: 2rem; } /* 32px */
-
ex:当前字体的x高度(小写字母x的高度)。
-
ch:字符“0”的宽度(等宽字体中更准确)。
-
-
百分比(%):
- 相对于父元素的对应属性。
.child { width: 50%; } /* 父元素宽度的50% */ .box { padding-top: 10%; } /* 相对于父元素宽度计算 */
- 相对于父元素的对应属性。
-
视口单位:
- vw(视口宽度):1vw = 视口宽度的1%。
- vh(视口高度):1vh = 视口高度的1%。
- vmin:取vw和vh中较小值的1%。
- vmax:取vw和vh中较大值的1%。
.full-screen { width: 100vw; height: 100vh; }
-
动态视口单位(较新):
- svw/svh:小视口尺寸(设备UI可见时)。
- lvw/lvh:大视口尺寸(设备UI隐藏时)。
- dvw/dvh:动态调整视口尺寸。
三、容器查询单位
相对于容器尺寸(需父元素声明为容器)。
- cqw:容器宽度的1%。
- cqh:容器高度的1%。
- cqi:容器内联方向(水平)的1%。
- cqb:容器块方向(垂直)的1%。
@container (width > 300px) {.item { width: 50cqw; } /* 容器宽度的一半 */ }
四、网格单位(CSS Grid)
- fr:按比例分配剩余空间。
grid-template-columns: 1fr 2fr; /* 两列宽度比为1:2 */
五、角度单位
用于旋转、渐变等。
- deg(度)、rad(弧度)、grad(百分度)、turn(圈数)。
transform: rotate(45deg); background: linear-gradient(90grad, red, blue);
六、时间单位
用于动画和过渡。
- s(秒)、ms(毫秒)。
animation: slide 2s ease-in; transition: opacity 300ms;
七、分辨率单位
用于高分辨率屏幕检测(媒体查询)。
- dpi(每英寸点数)、dpcm(每厘米点数)、dppx(每像素点数)。
@media (min-resolution: 2dppx) { ... } /* 视网膜屏 */
八、其他单位
- lh:元素的行高(如
height: 2lh;
)。 - % 的特殊行为:
margin/padding
的百分比始终相对于父元素宽度。line-height
的百分比相对于当前字体大小。
最佳实践
- 响应式布局:优先使用
rem
、%
、vw/vh
或容器查询单位。 - 字体大小:用
rem
避免层级问题。 - 精确控制:
px
适合边框或小元素。 - 动态视口:使用
dvh
替代vh
解决移动端工具栏问题。
/* 示例:综合使用 */
.container {width: min(90%, 1200px); /* 结合百分比和固定值 */padding: 2rem;margin: 0 auto;
}
通过合理选择单位,可实现灵活且自适应的布局。
CallBack Function 回调函数
function Run(CallBack){CallBack();
}function CallBack(){console.log("This is callBack Functions")
}Run(CallBack);
回调函数(Callback Function)是编程中一种常用的技术,它指的是将一个函数作为参数传递给另一个函数,并在特定事件发生或操作完成后调用这个被传入的函数。下面将从多个角度详细解释回调函数的概念、工作原理、使用场景及注意事项。
1. 回调函数的概念
简单来说,回调函数就是“把函数当作参数传进去”,在合适的时候由另一个函数来调用。这样做的主要目的是使程序具有更高的灵活性和可扩展性,例如处理异步操作、事件响应或定制化逻辑。
2. 回调函数的工作原理
回调函数的执行流程大致如下:
-
定义回调函数
编写一个函数,它将用于在某个操作完成后执行特定的逻辑。 -
传递回调函数
将这个回调函数作为参数传递给另一个函数。被调用的函数内部会保存这个回调函数的引用。 -
触发调用
当某个事件发生或者特定操作完成时,被调用的函数会“回调”传入的函数,通常还会传入操作的结果或者状态信息。
例如,在异步编程中,常见的模式是启动一个耗时操作(比如网络请求或文件读写),操作完成后调用回调函数来处理结果,而不会阻塞程序的其他部分。
3. 常见的使用场景
3.1 异步编程
在处理耗时操作时(如网络请求、数据库查询、文件读写等),使用回调函数可以避免程序阻塞。例如,在 JavaScript 中,很多异步 API 都使用回调函数来通知操作完成后的结果:
// 模拟异步操作:读取数据
function fetchData(callback) {setTimeout(function() {let data = "数据加载完成";callback(data); // 操作完成后调用回调函数}, 1000);
}// 使用回调函数处理结果
fetchData(function(result) {console.log(result); // 输出:数据加载完成
});
3.2 事件处理
在用户界面编程中,经常需要对用户的操作(如点击、悬停等)做出响应。回调函数常常被注册为事件处理器:
// 在浏览器中注册点击事件的回调函数
document.getElementById("myButton").addEventListener("click", function() {alert("按钮被点击了!");
});
3.3 函数扩展
有时候,我们希望在某个函数执行完毕后能够插入一些自定义逻辑,而不修改原函数的实现。回调函数使这种扩展变得简单:
// 定义一个可以接受回调函数的函数
function processData(data, callback) {// 对数据进行处理let processedData = data.toUpperCase();// 调用回调函数,并传入处理后的数据callback(processedData);
}processData("hello", function(result) {console.log(result); // 输出:HELLO
});
4. 回调函数的注意事项
4.1 回调地狱(Callback Hell)
当多个回调函数嵌套使用时,会导致代码层层嵌套,难以阅读和维护。这种情况常被称为“回调地狱”。为了解决这个问题,现代编程中常使用 Promise、async/await 等方式来管理异步流程,从而提高代码的可读性和可维护性。
4.2 错误处理
在使用回调函数时,需要设计良好的错误处理机制。很多异步 API 采用“错误优先回调”(Error-First Callback)的模式,即回调函数的第一个参数用于传递错误信息。例如:
function fetchData(callback) {setTimeout(function() {// 模拟出错的情况let error = null; // 如果没有错误,则为 nulllet data = "数据加载完成";// 第一个参数为错误信息,第二个参数为数据callback(error, data);}, 1000);
}fetchData(function(err, result) {if (err) {console.error("发生错误:", err);} else {console.log(result); // 输出:数据加载完成}
});
5. 其他语言中的回调函数
回调函数不仅存在于 JavaScript 中,在许多其他编程语言中也有类似的概念。例如:
- C/C++:常用于库函数或事件驱动编程中,通过函数指针实现回调。
- Python:函数可以作为参数传递,许多框架(如 Flask、Django)也使用回调机制来处理请求或事件。
总结
回调函数是一种将函数作为参数传递并在特定时机执行的编程模式,它为处理异步操作、事件响应以及扩展程序逻辑提供了灵活且强大的机制。虽然回调函数非常实用,但在设计和实现时需要注意代码的可读性、错误处理以及避免过度嵌套(即回调地狱)等问题。
希望这篇详细解释能帮助你更好地理解和应用回调函数!
setTimeout 设置超时函数:
function CallBack(){console.log("This is callBack Functions0")
}Run(CallBack);//setTimeout(CallBackFunctionName,times(/ms)); //设置超时函数 setTimeout(function(){console.log("This is setTimeout Function0")
}, 3000);
//3s后打印 : "This is setTimeout Function0"setTimeout(() => {console.log("This is setTimeout Function2")
}, 2000);
//2s后打印 :"This is setTimeout Function2"setTimeout(CallBack,1000);
//1s后打印 : "This is setTimeout Function0"
定时器
setInterval(()=>{console.log("This is a Interval after 3 seconds");
},3000) //每3s打印一次
利用超时计数器来停止定时器
const intervalId = setInterval(()=>{console.log("This is a Interval after 3 seconds");
},3000) //每3s打印一次const timeoutId = setTimeout(() => {console.log("This is a timeout after 2 seconds");
} , 2000);const timeoutOfStopIntervalId = setTimeout(() =>{clearInterval(intervalId);console.log("Clear interval after 10 seconds");
},10000); //10s后停止定时器
运行结果