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;
}

定位 子元素在父元素里面垂直居中

  1. 子绝父相
.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%);
}
  1. 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 常用新特性

  1. let const
  2. 解构赋值
  3. 箭头函数
  4. 模板字符串
  5. promise
  6. 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 方法执行后会返回一个对象,对象中有 valuedone 两个属性

  • 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 的区别

父子组件传值方式

  1. 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>
  1. $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>
  1. 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 区别

编译方式

  1. webpack 在编译过程中,会将所有模块打包为一个 bundle.js 文件,然后再运行这个文件。
  2. vite 在开发模式下,没有打包的步骤,它利用了浏览器的 ES Module Imports 特性,只有在真正需要时才编译文件。在生产模式下,vite 使用 Rollup 进行打包,提供更好的 tree-shaking,代码压缩和性能优化。

热更新

  1. webpack 在开发模式下,使用 webpack-dev-server 进行热更新,它会将所有的文件都编译一遍,然后将编译后的文件放在内存中,当文件发生变化时,会将变化的文件编译一遍,然后再将编译后的文件放在内存中,最后刷新浏览器。
  2. vite 的热更新是增量更新,只更新修改的文件,所以即使在大型应用中也能保持极快的编译速度。

生产环境

  1. webpack 在开发环境和生产环境下都是一样的构建
  2. vite 在生产环境下使用 Rollup 进行打包,提供更好的 tree-shaking,代码压缩和性能优化,在开发环境下使用浏览器原生的 ES Module Imports 特性,不需要打包,所以开发环境下的构建速度非常快。

echart 组件渲染的步骤

  1. 通过 echarts.init 初始化一个实例
  2. 通过 setOption 设置图表的配置项和数据
  3. 通过 resize 方法对图表进行重绘
贡献者: huxiguo