2023-07-25 面试 fd
css 实现三角形
.box {
width: 0;
height: 0;
border: 50px solid red;
border-right: 50px solid transparent;
border-left: 50px solid transparent;
border-bottom: 50px solid transparent;
}
定位 子元素在父元素里面垂直居中
- 子绝父相
.par {
width: 300px;
height: 300px;
background-color: red;
position: relative;
}
.son {
width: 100px;
height: 100px;
background-color: blue;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
- flex
.par {
width: 300px;
height: 300px;
background-color: red;
display: flex;
justify-content: center;
align-items: center;
}
.son {
width: 100px;
height: 100px;
background-color: blue;
}
css 预处理
支持 变量、嵌套、继承、导入
sass
// 变量
$color: red;
.box {
width: 100px
height: 100px
background-color: $color
}
// 嵌套
.box {
width: 100px
height: 100px
.son {
width: 50px
height: 50px
}
&:hover {
background-color: red
}
}
// 继承
.box {
width: 100px
height: 100px
.son {
@extend .box
}
}
// 导入
@use 'xxx.scss'
less
// 变量
@color: red;
.box {
width: 100px
height: 100px
background-color: @color
}
// 嵌套
.box {
width: 100px
height: 100px
.son {
width: 50px
height: 50px
}
&:hover {
background-color: red
}
}
// 继承
.box {
width: 100px
height: 100px
.son {
.box()
}
}
// 导入
@import 'xxx.less'
在 css 中使用变量
:root {
--color: red;
--width: 100px;
--height: 100px;
}
.box {
width: var(--width);
height: var(--height);
background-color: var(--color);
}
数据类型
string number boolean undefined null symbol object
typeof null
typeof null
返回 object
原型原型链
每个对象的__proto__
都是指向它的构造函数的原型对象prototype
的
构造函数是一个函数对象,是通过 Function
构造器产生的
原型对象本身是一个普通对象,而普通对象的构造函数都是 Object
function Person() {}
const person = new Person();
console.log(person.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
console.log(Person.__proto__ === Function.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain)
闭包
闭包就是能够读取其他函数内部变量的函数
使用场景
函数作为返回值
function fn() { const a = 1; return function () { console.log(a); }; } const fn1 = fn(); fn1(); // 1
函数作为参数传递
function fn2(fn) { const a = 1; fn(); } fn2(function () { console.log(a); }); // 1
react 函数柯里化
class Login extends React.Component { state = { username: "", password: "", }; saveFormData = (dataType) => { console.log(dataType); return (event) => { this.setState({ [dataType]: event.target.value }); }; }; render() { return ( <form action="http://www.atguigu.com" onSubmit={this.handleSubmit}> 用户名: <input onChange={this.saveFormData("username")} type="text" name="username" /> 密码: <input onChange={this.saveFormData("password")} type="password" name="password" /> <button>登录</button> </form> ); } }
优点: 可以读取函数内部的变量
缺点: 会造成内存泄漏,闭包中的变量不会被垃圾回收机制回收
es6 常用新特性
- let const
- 解构赋值
- 箭头函数
- 模板字符串
- promise
- async await
let const
let const 声明的变量不会被提升,而 var 声明的变量会被提升
const 声明的变量不能被修改,但是如果声明的是一个对象,那么对象的属性是可以修改的
promise
异步编程的一种解决方案,比传统的回调函数更加合理和更加强大,为了解决回调地狱的问题
doSomething(function (result) {
doSomethingElse(
result,
function (newResult) {
doThirdThing(
newResult,
function (finalResult) {
console.log("得到最终结果: " + finalResult);
},
failureCallback
);
},
failureCallback
);
}, failureCallback);
- 链式操作减低了编码难度
- 代码可读性明显增强
状态
pending
(进行中)fulfilled
(已成功)rejected
(已失败)
async await 实现原理
Generator
generator
函数跟普通函数在写法上的区别就是,多了一个星号*
,并且只有在 generator
函数中才能使用 yield
, yield
相当于 generator
函数执行的中途暂停点,比如下方有 3 个暂停点。而怎么才能暂停后继续走呢?那就得使用到 next
方法,next
方法执行后会返回一个对象,对象中有 value
和 done
两个属性
value
:暂停点后面接的值,也就是yield
后面接的值done
:是否generator
函数已走完,没走完为false
,走完为true
function* gen() {
yield 1;
yield 2;
yield 3;
}
const g = gen();
console.log(g.next()); // {value: 1, done: false}
console.log(g.next()); // {value: 2, done: false}
console.log(g.next()); // {value: 3, done: false}
console.log(g.next()); // {value: undefined, done: true}
可以看到最后一个是 undefined
,这取决于你 generator
函数有无返回值
function* gen() {
yield 1;
yield 2;
yield 3;
return 4;
}
const g = gen();
console.log(g.next()); // {value: 1, done: false}
console.log(g.next()); // {value: 2, done: false}
console.log(g.next()); // {value: 3, done: false}
console.log(g.next()); // {value: 4, done: true}
yield
后面接函数的话,到了对应暂停点 yield
,会马上执行此函数,并且该函数的执行返回值,会被当做此暂停点对象的 value
实现 sleep()
(async () => {
console.log(1);
await sleep(2000);
console.log(3);
})();
function sleep(times) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, times);
});
}
宏任务 微任务
宏任务: setTimeout setInterval
微任务: promise.then
事件循环机制:执行一个宏任务,如果遇到微任务就将它放到微任务的事件队列中 当前宏任务执行完成后,会查看微任务的事件队列,然后将里面的所有微任务依次执行完
vue3 ref reactive
ref 用来定义基本类型的响应式数据, reactive 用来定义对象类型的响应式数据
向 ref 传入一个对象,会自动调用 reactive 方法,将对象转换成响应式对象
vue2 和 vue3 的区别
父子组件传值方式
- props
父组件
<template>
<div>
<child :msg="msg"></child>
</div>
</template>
<script setup></script>
子组件
<template>
<div>
<p>{{ msg }}</p>
</div>
</template>
<script setup>
import { defineProps } from "vue";
const props = defineProps(["msg"]);
</script>
- $emit
父组件
<template>
<div>
<child @change="change"></child>
</div>
</template>
<script setup>
const change = (msg) => {
console.log(msg);
};
</script>
子组件
<template>
<div>
<button @click="handleClick">点击</button>
</div>
</template>
<script setup>
import { defineEmits } from "vue";
const emits = defineEmits(["change"]);
const handleClick = () => {
emits("change", "hello");
};
</script>
- provide inject
父组件
<template>
<div>
<child></child>
</div>
</template>
<script setup>
import { provide } from "vue";
provide("msg", "hello");
</script>
子组件
<template>
<div>
<p>{{ msg }}</p>
</div>
</template>
<script setup>
import { inject } from "vue";
const msg = inject("msg");
</script>
vuex
四大属性
- state:存放状态
- getters:派生状态,类似于计算属性
- mutations:同步修改状态
- actions:异步修改状态
pinia
选项式写法
import { defineStore } from "pinia";
const useStore = defineStore({
id: "main",
state: () => ({
count: 0,
}),
getters: {
doubleCount() {
return this.count * 2;
},
},
actions: {
increment() {
this.count++;
},
},
});
setup 语法
import { defineStore } from "pinia";
const useStore = defineStore("main", () => {
const count = ref(0);
const doubleCount = computed(() => {
return count.value * 2;
});
const increment = () => {
count.value++;
};
return {
count,
doubleCount,
increment,
};
});
vite webpack 区别
编译方式
webpack
在编译过程中,会将所有模块打包为一个bundle.js
文件,然后再运行这个文件。vite
在开发模式下,没有打包的步骤,它利用了浏览器的ES Module Imports
特性,只有在真正需要时才编译文件。在生产模式下,vite
使用Rollup
进行打包,提供更好的tree-shaking
,代码压缩和性能优化。
热更新
webpack
在开发模式下,使用webpack-dev-server
进行热更新,它会将所有的文件都编译一遍,然后将编译后的文件放在内存中,当文件发生变化时,会将变化的文件编译一遍,然后再将编译后的文件放在内存中,最后刷新浏览器。vite
的热更新是增量更新,只更新修改的文件,所以即使在大型应用中也能保持极快的编译速度。
生产环境
webpack
在开发环境和生产环境下都是一样的构建vite
在生产环境下使用Rollup
进行打包,提供更好的tree-shaking
,代码压缩和性能优化,在开发环境下使用浏览器原生的ES Module Imports
特性,不需要打包,所以开发环境下的构建速度非常快。
echart 组件渲染的步骤
- 通过
echarts.init
初始化一个实例 - 通过
setOption
设置图表的配置项和数据 - 通过
resize
方法对图表进行重绘