20222年10月日记形式刷面试题笔记

本文回顾了JS基础、数据类型、变量、数值转换、时间戳处理、正则表达式、数组对象操作、原型链、闭包、防抖节流等,旨在帮助产假结束的开发者迅速找回编程状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

21年9月17孕吐开始,10月15号离项,今天是22年10月18,一年没有摸键盘了,产假即将结束,要迅速的回忆和恢复之前的代码状态

JS复习题

js基本数据类型

基本数据类型:number string boolean null undefined es中的symbol bigInt
引用数据类型:array object function
typeof(null) //“object”
undefined 和 null的区别:值相等,类型不等,null用于对象,undefined用于变量

变量 var let const的区别

变量生命周期:局部变量在函数执行完销毁 ,全局变量在页面关闭后销毁
var let const的区别
var 声明全局变量 声明的全局作用域 属于window
let 声明局部变量,只在let所在的代码块{}内有效,在{}以外不能访问,不能用let关键字类重置let关键字声明的变量
const 声明的对象或数组是可变,但是不能重新覆盖,const是块级作用域

数值类型转换

数值转换

Number() 转成数字类型
parseInt()  整数     parseFloat()  浮点数
//隐式子转换
'10'+ 1   //101
'10'- 1   //9
+'10'+1  //11
10+''   // '10'
[1,2,3].toString()   // "1,2,3"
valueOf()
[].valueOf()   //[]
[].toString()   //''

转换时间戳

//时间转成时间戳  四种
new Date().getTime()
Number(new Date())   
Date.parse(new Date())
new Date().valueOf()

正则表达式




运算符

解决0.1+0.1=0.200000000001的问题,用整数的乘法来解决
( 0.1*10 +0.1*10 )  /10  =0.2
连接符的问题
"0.2+0.1"   // 0.20.1
"0.2"-0.1     //0.1

eval(7+8)   //15   eval  对字符串进行解析和计算


Array

map( )没有return时,对数组的遍历。有return时,返回一个新数组,该新数组的元素是经过过滤(逻辑处理)过的函数。
filter( )对数组中的每一运行给定的函数,会返回满足该函数的项组成的数组。
every( ):每一项都返回true才返回true
some( ):只要有一项返回true就返回true    every 和  some  类似&&||的关系
reduce( ):语法 array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
			total	必需。初始值, 或者计算结束后的返回值。
			currentValue	必需。当前元素  
			currentIndex  可选 当前元素索引    
			arr  可选。当前元素所属的数组对象。
			initialValue  可选。传递给函数的初始值
map()  map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
isArray() 判断是否是数组
 Array.of(3, 11, 8)   <==== >  new Array(3, 11, 8)    //[3, 11, 8]   两者区别在于传递一个参数 前者依然唯一的数值参数作为元素,返回一个新数组,长度为1   后者返回  有3个空位empty的数组,长度为3
 Array.from()  将类数组转换成数组    
 Array.from("abcdefg")   //["a", "b", "c", "d", "e", "f", "g"]
 fill()   使用固定值填充数组  
  find() 查找数组符合条件的第一个数  
  findIndex()  同上 返回下标  没有返回 -1
  includes()  判断一个数值是否在数组中
  forEach 循环遍历 无法使用 break continue
  keys()  values()  entries()
  var arr = ["a","b"];
  for(let [index,elem] of arr.values()){
		console.log(index,elem);  
	}    //  a  b

object

Object.is(value1, value2)  //用于确定两个值是否相同     Object.is(0,-0);  false
Object.assign()  //浅拷贝  对象属性的合并,合并多个对象
Object.entries()   //把对象转成键值对数组, [key, value] 对的数组
Object.values()
Object.key()

Object.prototype.hasOwnProperty()
Object.create()  //创建一个新的对象
Object.freeze()   //冻结对象

对象描述符

var obj={key:'123'} 
//获取描述符  
Object.getOwnPropertyDescriptors(obj)  //key: {value: "123", writable: true, enumerable: true, configurable: true}
Object.defineProperty(obj,'key',{
value:  '45',     //设置key的新值
writable:false,   //是否可写
enumerable:false,   //是否可枚举    用 for..in
configurable:false   //是否可配置及删除 
})

instanceofconstructor

console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);    
console.log(([]).constructor === Array);
Object.prototype.toString.call()` 使用 Object 对象的原型方法 toString 来判断数据类型:

深拷贝和浅拷贝 赋值

浅拷贝的实现方式:
   1、object.assign()
   2、lodash 里面的 _.clone 
   3...扩展运算符
   4Array.prototype.concat 
   5Array.prototype.slice
​
    深拷贝的实现方式
    1JSON.parse(JSON.stringify())
    2、递归操作
    3、cloneDeep
    4、Jquery.extend() 

栈和堆
栈先进后出的数据机构 存储基本数据类型
堆 存放引用类型的数据结构 指针存在栈中 ,数据内容存在堆中,赋值给另外一个值变量,只把栈地址赋值过去,地址指向的内容未赋值,形成浅拷贝

this

1. 在普通函数中,this指向window    立即执行函数this 指向window
2. 有事件源指向事件源本身,事件源里的普通函数指向window
3. 在定时器下出Es6  this指向window
4. 在对象下this指向的是自己本身,对象中的函数this也指向该方法所属的对象  a.b.m()  m中的this指向b
5. 构造函数中this 指向实例对象
6. 箭头函数没有自己的this  是继承父执行上下文里的this

call、apply、bind

call 和apply 都是为了改变某个函数运行时的上下文而存在的,就是为了改变函数体内this 的指向,call传值是序列,apply传数组
bind和call相似,bind方法不会立即执行,而只是改变上下文this的函数,而原函数this 并没有改变,依旧指向window
call apply bind 三个函数第第一个参数都是this的指向对象
call的参数是序列,直接用逗号隔开
apply的参数必须放在一个数组中传过去
bind除了返回时函数以外,他的参数传递和call一样
call 经常用来做继承
apply 常用来跟数组取最大最小值
bind改变函数内this的指向

B.apply(A , arr) A 继承B A对象继承B 对象的方法
call 英文翻译 为呼叫, 我呼叫你,来吧 继承我的方法吧





原型 、原型链

原型,在js中,每当定义一个函数数据类型的时候(普通函数,类),都会自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值
原型链:每个对象数据类型都有(普通对象,实例,prototype…)也自带一个__proto__ 属性,指向它的构造函数的prototype(原型对象),该原型对象也有一个自己的__proto__属性,层层向上查找

function a(){}
a.prototype.c=10
function b(){}
b.prototype =new a()   //b继承a
console.log(new  b().c)   //10

闭包

闭包是一种保护私有变量的机制,有函数执行时,形成私有作用域保护里边的私有变量不受外界干扰,**直观说形成一个不销毁的栈环境**
访问另一个函数作用域中的变量,形成闭包
闭包会造成内存泄漏,原因:由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包。
解决方法是,在退出函数之前,将不使用的局部变量全部删除或者置空。

```javascript
var add=(function(){
   var count = 0;
   return function(){
    return count+=1
   }
})()
console.log(add())   //1
console.log(add())   //2
console.log(add() )  //3  


var add=function(){
   var count = 0;
   return function(){
    return count+=1
   }
}
console.log(add()())   //1
console.log(add()())   //1
console.log(add()() )  //1  

事件循环 EventLoop

微队列:  new promise().then(回调)   node中的 process。nextTick     // promise属于同步立即执行  回调属于微任务
宏队列 :script(整体代码)、 setTimeout   setInterval   setImmediate   script....
	先执行同步代码,
	遇到异步宏任务则将异步宏任务放入宏任务队列中,
	遇到异步微任务则将异步微任务放入微任务队列中,
	当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,
	微任务执行完毕后再将异步宏任务从队列中调入主线程执行,
    一直循环直至所有任务执行完毕。
setTimeout(() => {
        console.log("4");
        setTimeout(() => {
          console.log("8");
        }, 0);
        new Promise((r) => {
          console.log("5");//构造函数是同步的
          r();
        }).then(() => {
          console.log("7");//then()是异步的,这里已经入队
        });
        console.log("6");
      }, 0);

      new Promise((r) => {
        console.log("1");//构造函数是同步的
        r();
      }).then(() => {
        console.log("3");//then()是异步的,这里已经入队
      });
      console.log("2");                //123  undefined  45678

防抖和节流

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
节流:所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。两种方式可以实现,分别是时间戳版和定时器版。




mouseenter与mouseover区别 :mouseenter 不支持事件冒泡 mouseover 会冒泡

函数

普通函数

//1.  函数表达式可以存储在变量中
var x= function(a,b){
 return a+b
}
var z=x(4,3)
console.log(z)    //7

//2.  函匿名数可以自我调用
(function (){
  var x ='kkk'

})()    //表达式后面紧跟()则会自动调用

//3. 给参数设置默认值
function A (x,y=10){
return x+y
}
A(2,2)  //4     有入参的按照入参  
A(2)   //12  没有入参的按照默认值算

argument

argument 包含了函数调用的参数数值

A (1,2,3)
function A(){
  console.log(arguments[0])     // 1
}  

cookie

Es6复习

变量解构赋值

交换变量
let x = 1;
let y = 2;
[x, y] = [y, x];

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回
function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

字符串的扩展

  1. 摸板字符串,用反引号(`)标识
  2. 模板字符串中嵌入变量,需要将变量名写在${}之中,{}大括号内部可以放入任意的 JavaScript 表达式,调用函数,运算等
  3. includes()返回布尔值,是否找到了参数字符串
  4. startsWith()返回布尔值,参数字符串是否在原字符串的头部 , endsWith() 同上
  5. repeat() ‘x’.repeat(3) //xxx
  6. trimStart()trimEnd()这两个方法。它们的行为与trim()一致,trimStart()消除字符串头部的空格,trimEnd()消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串
  7. charAt()与at()是什么作用 用法一样,at() 作用更广 可以接受

正则和正则的扩展


数值的扩展

Number.parseIntNumber.parseFloat 和ES5中用法一样,只是把全局的方法逐渐模块化
Number.isInteger()用来判断一个数值是否为整数。
Math.trunc() 去除一个数的小数部分,返回整数部分
BigInt(大整数)只用来表示整数,没有位数的限制

// ES5的写法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45

// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45

Number.isInteger(25)   //true 
Number.isInteger('25')  //false
Number.isInteger(25.0)   //true  

函数的扩展

ES6 允许为函数的参数设置默认值
ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了

function add(...values) {
  let sum = 0;
  for (var val of values) {
    sum += val;
  }
  return sum;
}
add(2, 5, 3) // 10


arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.from先将其转为数组。rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法都可以使用
// arguments变量的写法
function sortNumbers() {
  return Array.from(arguments).sort();
}

// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();

(1)箭头函数没有自己的this对象
(2)不可以当作构造函数,也就是说,不可以对箭头函数使用new命令
(3)不可以使用arguments对象,该对象在函数体内不存在
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数
对于普通函数来说,内部的this指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的this对象,内部的this就是定义时上层作用域中的this。也就是说,箭头函数内部的this指向是固定的,相比之下,普通函数的this指向是可变的。

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}
var id = 21;
foo.call({ id: 42 });    //  42

function foo() {
  setTimeout(function(){
    console.log('id:', this.id);
  }, 100);
}
var id = 21;
foo.call({ id: 42 });    // 21

回调函数分别为箭头函数和普通函数,对比它们内部的this指向

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval(function () {
    this.s2++;
  }, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);    //3  指向foo
setTimeout(() => console.log('s2: ', timer.s2), 3100);   //0   指向全局

箭头函数实际上可以让this指向固定化,绑定this使得它不再可变,这种特性很有利于封装回调函数

尾调用

是指某个函数的最后一步是调用另一个函数

// 情况一
function f(x){
  let y = g(x);
  return y;
}

// 情况二
function f(x){
  return g(x) + 1;
}

// 情况三
function f(x){
  g(x);
}

情况一是调用函数g之后,还有赋值操作,所以不属于尾调用,即使语义完全一样。情况二也属于调用后还有操作,即使写在一行内。情况三等同于下面的代码。

function f(x){
  g(x);
  return undefined;
}

个人理解就是:最后一个返回一个 函数调用

function f(x) {
  if (x > 0) {
    return m(x)
  }
  return n(x);                //函数m和n都属于尾调用,因为它们都是函数f的最后一步操作
}

尾递归

函数调用自身,称为递归。如果尾调用自身,就称为尾递归
递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow)。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。

function factorial(n) {
  if (n === 1) return 1;
  return n * factorial(n - 1);
}
factorial(5) // 120

改成尾递归
function factorial(n, total) {
  if (n === 1) return total;
  return factorial(n - 1, n * total);
}
factorial(5, 1) // 120

数组的扩展

扩展运算符

将一个数组,变为参数序列
console.log(...[1, 2, 3])   //  1 ,2,3 

替代函数的 apply() 方法
// ES5 的写法
Math.max.apply(null, [14, 3, 77])
// ES6 的写法
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);

push()函数,push()方法的参数不能是数组,所以只好通过apply()方法变通使用push()方法。有了扩展运算符,就可以直接将数组传入push()方法
// ES5 的写法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
// ES6 的写法
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);

扩展运算符的应用

1.复制数组
const a1 = [1, 2];
const a2 = a1.concat();  //ES5
const a2 = [...a1];  //ES6    或   const [...a2] = a1;
2.合并数组  
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
arr1.concat(arr2, arr3);// ES5 的合并数组
[...arr1, ...arr2, ...arr3]  // ES6 的合并数组
这两种都是浅拷贝
3.与解构赋值结合
const [first, ...rest] = [1, 2, 3, 4, 5];   //first  1       rest  // [2, 3, 4, 5]
4.
[...'hello']    //  [ "h", "e", "l", "l", "o" ]
5. 实现了 Iterator 接口的对象

Array.from 和array.of

copyWithin()

find(),findIndex(),findLast(),findLastIndex()

find()方法,用于找出第一个符合条件的数组成员
findIndex() ,用法同上,返回第一个符合条件的数组成员的位置
find()findIndex()都是从数组的0号位,依次向后检查。ES2022 新增了两个方法findLast()findLastIndex(),从数组的最后一个成员开始,依次向前检查

[1, 4, -5, 10].find((n) => n < 0)    //-5

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2

flat(),flatMap()

将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响
flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1,如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。

[1, 2, [3, 4]].flat()    //  [1, 2, 3, 4]
[1, 2, [3, [4, 5]]].flat(2)    // [1, 2, 3, 4, 5]
[1, 2, [3, [4, 5]]].flat(Infinity);   // [1, 2, 3, 4, 5]

toReversed(),toSorted(),toSpliced(),with()

上面是这四个新方法对应的原有方法,含义和用法完全一样,唯一不同的是不会改变原数组,而是返回原数组操作后的拷贝

toReversed()对应reverse(),用来颠倒数组成员的位置。
toSorted()对应sort(),用来对数组成员排序。
toSpliced()对应splice(),用来在指定位置,删除指定数量的成员,并插入新成员。
with(index, value)对应splice(index, 1, value),用来将指定位置的成员替换为新的值

group(),groupToMap()

group()的参数是一个分组函数,原数组的每个成员都会依次执行这个函数,确定自己是哪一个组
groupToMap()的作用和用法与group()完全一致,唯一的区别是返回值是一个 Map 结构,而不是对象。Map 结构的键名可以是各种值,所以不管分组函数返回什么值,都会直接作为组名(Map 结构的键名),不会强制转为字符串。这对于分组函数返回值是对象的情况,尤其有用

const array = [1, 2, 3, 4, 5];
array.group((num, index, array) => {
  return num % 2 === 0 ? 'even': 'odd';
});    // { odd: [1, 3, 5], even: [2, 4] }


const array = [1, 2, 3, 4, 5];
const odd  = { odd: true };
const even = { even: true };
array.groupToMap((num, index, array) => {
  return num % 2 === 0 ? even: odd;
});//  Map { {odd: true}: [1, 3, 5], {even: true}: [2, 4] }

对象的扩展

Object.is()它用来比较两个值是否严格相等

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

Object.assign(),用来合并对象,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性

对数组处理会把数组当成对象后面全部替换前面的
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]

Object.fromEntries()方法是Object.entries()的逆操作,该方法的主要目的,是将键值对的数据结构还原为对象

Object.fromEntries([
  ['foo', 'bar'],
  ['baz', 42]
])

const map = new Map().set('foo', true).set('bar', false);
Object.fromEntries(map)
// { foo: true, bar: false }

Object.hasOwn()判断某个属性是否为原生属性

const foo = Object.create({ a: 123 });
foo.b = 456;

Object.hasOwn(foo, 'a') // false
Object.hasOwn(foo, 'b') // true

运算符的扩展

指数运算符

运算符的一个特点是右结合,而不是常见的左结合

2 ** 3    2的三次方

2 ** 3 ** 2  // 相当于 2 ** (3 ** 2)   //512

新的赋值运算符(**=)
b **= 3;    // 等同于 b = b * b * b;

链判断运算符 ?.

// 正确的写法
const firstName = (message
  && message.body
  && message.body.user
  && message.body.user.firstName) || 'default';
ES2020写法
const firstName = message?.body?.user?.firstName || 'default';
//上面代码使用了?.运算符,直接在链式调用的时候判断,左侧的对象是否为null或undefined。如果是的,就不再往下运算,而是返回undefined
a?.b
// 等同于
a == null ? undefined : a.b

(a?.b).c
// 等价于
(a == null ? undefined : a.b).c

Null 判断运算符

ES2020 引入了一个新的 Null 判断运算符??。它的行为类似||,但是只有运算符左侧的值为null或undefined时,才会返回右侧的值,如果是false 或者0 就不会
这个运算符的一个目的,就是跟链判断运算符?.配合使用,为null或undefined的值设置默认值。

const animationDuration = response.settings?.animationDuration ?? 300;
前面是undefinednull的时候才会用默认值300

逻辑赋值运算符

// 或赋值运算符
x ||= y
// 等同于  x || (x = y)

// 与赋值运算符
x &&= y
// 等同于   x && (x = y)

// Null 赋值运算符
x ??= y
// 等同于  x ?? (x = y)

为变量或属性设置默认值
user.id = user.id || 1;  // 老的写法
user.id ||= 1;  // 新的写法

Symbol

set 和 map

set

set去重  后用Array.from转换成数组
Array.from(new Set([1,1,2,3,3]));   //  [1, 2, 3]

扩展运算符去重
let arr = [3, 5, 2, 2, 5, 5];
let unique = [...new Set(arr)];

keys()values(),entries() 遍历,
用for…of循环遍历 Set 也可以用forEach()遍历
mapfilter方法也可以间接用于 Set 了

let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
  console.log(item);
}    // red   green  blue    values()  entries() 同理

用map遍历
let set = new Set([1, 2, 3]);
set = new Set([...set].map(x => x * 2));      // 返回Set结构:{2, 4, 6}

并集  交集   差集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
let union = new Set([...a, ...b]);  // Set {1, 2, 3, 4}   并集
let intersect = new Set([...a].filter(x => b.has(x)));    // set {2, 3}  交集
let difference = new Set([...a].filter(x => !b.has(x)));// Set {1}  (a 相对于 b 的)差集

weaksete

WeakSet 结构与 Set 类似,也是不重复的值的集合。
WeakSet 的成员只能是对象,而不能是其他类型的值
WeakSet 不能遍历,是因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能刚刚遍历结束,成员就取不到了。WeakSet 的一个用处,是储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏

map

传统的js对象 ,键值对的集合,只能用字符串作为键
而map打破这一限制,各种类型的值(包括对象)都可以当作键,
Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应
Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组

const map = new Map([  ['name', '张三'],  ['title', 'Author']  ]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"

Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键

const map = new Map();
const k1 = ['a'];
const k2 = ['a'];

map
.set(k1, 111)
.set(k2, 222);
map.get(k1) // 111
map.get(k2) // 222
const map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

[...map.keys()]
// [1, 2, 3]

[...map.values()]
// ['one', 'two', 'three']

[...map.entries()]
// [[1,'one'], [2, 'two'], [3, 'three']]

[...map]
// [[1,'one'], [2, 'two'], [3, 'three']]

promise




vue复习

watch 和computed的

computed是基于他的依赖缓存 ,只有相关依赖发生改变时才会重新取值,computed可以返回监听的属性值
watch可设置异步中间状态,computed做不到,watch只用来监听,在数据变化时执行异步或开销较大的操作时,这个方法最有用

methods和computed

用methods代替computed ,效果上两个是一样的,但是computed是基于他的依赖缓存 ,只有相关依赖发生改变时才会重新取值,而使用methods在重新渲染的时候,函数总会重新调用执行
computed是属性调用,带有缓存功能
methods是函数调用,不带缓存功能

html css复习

实现垂直居中的方法

1.使用绝对定位+transform: translate(-50%,-50%);
2. 同上 ,或者上左50%,然后margin-top 和margin-left 子div的宽高的负一半
3. 使用flex布局,在父元素中设置justify-content: center;align-items: center;,就完成了子元素的水平和垂直居中
4. 使用table自带的功能实现垂直居中。
5. 把div装成table实现垂直居中。

弹性布局

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值