前端知识点总结

83 阅读4分钟

1. 箭头函数和function的区别

2. bind、call、apply 区别

  1. call:第一个参数是指定函数运行时的this指向,后面的参数是传递给函数的参数,参数以逗号,隔开。
function greet(c1, c2) {
    // 在这个方法中this因为指向了person,所以this.name = Tom,而C1和c2为传入的参数,也就是call参数有几个就是几个
    console.log(`Hello, I am ${this.name}, I love ${c1} and ${c2}`);
}
let person = { name: 'Tom' };
greet.call(person, 'apple', 'banana');// 这里this指向了person
  1. apply:第一个参数也是指定函数运行时的this指向,与call不同,apply第二个参数是一个数组,数组中的元素被用作函数的参数。
 function greet(c1, c2) {
        // 因为person指向了this,所以this.name 也是Tom,但是c1和c2是传入的数组的值,也就是说第二个参数必须是数组
        console.log(`Hello, I am ${this.name}, I love ${c1} and ${c2}`);
      }
      let person = { name: "Tom" };
      greet.apply(person, ["apple",'orage'], ["banna"]);//  这里this 指向了person,
  1. bindbind方法返回一个新的函数,其this值被绑定到你指定的对象。bind方法并不立即执行函数,而是返回一个改变了this指向的新函数。
      function greet(c1, c2) {
        // 参数和call的参数一样,都是一个一个传入
        console.log(`Hello, I am ${this.name}, I love ${c1} and ${c2}`);
      }
      let person = { name: "Tom" };
      let greetPerson = greet.bind(person, "apple", "banana");// this 指向了person,但是bind返回的是一个新的方法,因此不会立即执行。
      greetPerson(); // Hello, I am Tom, I love apple and banana

3. this的作用域和使用场景

①普通函数的调用,this指向的是window
②对象方法的调用,this指的是该对象,且是最近的对象
③构造函数的调用,this指的是实例化的新对象
④apply和call调用,this指向参数中的对象
⑤匿名函数的调用,this指向的是全局对象window
⑥定时器中的调用,this指向的是全局变量window
⑦.箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则this的值则被设置为全局对象
⑧.onclick和addEventerListener是指向绑定事件的元素(ev.currentTarget)

4. 闭包的作用,和使用场景

5. 防抖和节流

二者区别:

  1. 防抖就是排队阻塞,你是一个强盗,你说10:00吃饭,但是前面排队的人9:59到了,但是你来了,你就要大家一起和你等到10:00才可以吃饭。
  2. 节流就是等待有票,大家去医院挂号,本来是按照顺序挂号,但是你们来早了,7:00才放票,那么7点以前来的都要排队等待一起抢号。
  • 定义防抖, 就是一段时间内只让执行一次操作,如果在这个时间内已经有任务在执行,那么就取消重新计时。
      // 防抖
      const debounce = (fn, delay) => {
        console.log(this, "lxz");
        var timer = null;
        return function (...args) {
            // 如果定时任务执行完毕那么timer就消失了,所以就重新定义timer,如果timer依然存在,那么说明上次执行还没有结束,因此需要重新计时,
          if (timer) {
            clearTimeout(timer);
          }
          timer = setTimeout(() => {
             // 方法1:使用闭包函数中的参数
             fn(...args);
              // 方法2:使用this绑定隐形参数, this 就是当前对象,arguments 就是当前的所有参数
            fn.apply(this, arguments); //this和参数
            timer = null;
          }, delay);
        };
      };
// 调用方法
    //  获取对象
      const app = document.querySelector("#app");
      // 设置输入事件监听/
      // 在500秒内执行一次数据输入
      app.addEventListener(
        "input",
        // 实名调用
        debounce((e) => {
          console.log("数据发送成功", e.target.value);
        }, 500)
        // debounce()
      );
  • 定义节流 如果用户不停的触发某种动作,那么在一段时间内就执行一次,如果用户只执行一次,那就获取当前执行时间点内的结果,也就说我们要延迟用户行为

函数定义

   function throttle(fn, interval) {
        // 1. 记录上一次的开始时间
        let lastTime = 0;
        return function (e) {
          // 2.1.获取当前事件触发时的时间
          const nowTime = new Date().getTime();

          // 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
          const remainTime = interval - (nowTime - lastTime);
          if (remainTime <= 0) {
            // 2.3真正触发函数
            fn(e); //做出响应
            // 2.4保留上次触发的时间
            lastTime = nowTime; //更新最后一次执行的时间
          }
        };
      }

函数调用

// 定义监听事件
      const inputEl = document.querySelector("#app");
      let counter = 0;
      const inputChange = function (event) {
        console.log(`发送了第${++counter}次网络请求`, this, event.target.value);
      };

      // 节流处理
      inputEl.oninput = throttle(inputChange, 2000); //当用户不断触发事件按照2秒的频率执行

6. v-modle 原理设计

其实就是利用Object.defineProperty 进行数据拦截,利用其get,set方法进行数据赋值

  <div id="username"></div>
    <input type="text" id="app">
    <script>
        let obj ={}
        Object.defineProperty(obj,"username",{
            get(){
                return "1"
            },
            set(val){
                document.querySelector("#username").innerHTML = val 
            }
        })
        document.getElementById("app").addEventListener('input',(e)=>{
            obj.username = e.target.value
        })
    </script>

7、订阅发布模式

订阅模型 思路:创建一个dep对象,其中包含多有订阅者,注册方法,通知订阅者的方法

8. vue的插槽

1、具名插槽 传入

      <lxz-header-item :name="i" v-for="i in 10" :key="i"></lxz-header-item>
      <div slot="headername">DTM2112</div>
    </lxz-header>

接收

    <div class="slot">
     // 实名
      <slot name="headername"></slot>
      // 匿名
      <slot></slot>
    </div>
    

9、 计算属性是否可以被修改

  computed: {
     // 普通设置计算属性
    double1() {
      return this.count * 2;
    },
    // 如果计算属性可以被修改,那么需要设置set和get方法。比如被v-modle所引用
    double: {
      set(val) {
        this.count = this.count * val;
      },
      get() {
        return this.count * 3;
      },
    },
  },

10、 watch 进行监听,如果是上引用类型监听,那么需要进行深度监听,另外无法监听到变化前的值

   //  数据改变引用类型内部的数据,执行这个方法会引起下面stu的变化,但是newData和old是同样的数据,都是改变以后的
    updateStu() {
      this.stu.person = {
        name: 5343,
          age: 343,
      };
    },
    // 进行数据的深度监听
   stu: {
      handler(newData, old) {
        this.watchOldStu = old;
        this.watchNewStu = newData;
      },
      deep: true,
    },

11、 什么事自定义v-model

v-modle语法糖,实际上就是两个指令的集合 value 值的传递,自组件接受value就可以获取到对应的值 input 事件回调,实际上就是父组件给自组件传递了一个input事件,只要在值发生变化的时候回调这个方法就可以

12、 proxy的原理

``

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>vue3数据监听</title>
  </head>
  <body>
    <script>
      function isObject(obj) {
        return obj !== null && typeof obj === "object";
      }
      function reactive(obj) {
        if (!isObject(obj)) {
          return obj;
        }
        const proxy = new Proxy(obj, {
          get(target, key) {
            console.log("获取数据", target[key]);
            if (isObject(target[key])) {
              return reactive(target[key]);
            } else {
              return Reflect.get(target, key);
            }
          },
          set(target, key, value) {
            console.log("设置数据", target[key], value);
            target[key] = value;
            Reflect.set(target, key, value);
          },
          deleteProperty(target, key) {
            console.log(target, key);
            return Reflect.deleteProperty(target, key);
          },
        });
        return proxy;
      }
      const data = {
        name: "lxz",
        age: 12,
        info: { a: { b: { c: { d: 1 } } } },
      };
      const proxyData = reactive(data);
      proxyData.name;
      proxyData.name = 121;
      delete proxyData.name;
      console.log(proxyData.name);
      delete proxyData.info.a.b.c;
    </script>
  </body>
</html>

13、 vue3为什么比vue2快

6-19可以参考

14、什么是高级函数,

15、reactDom中的CreateProtal,渲染到对应元素的外部

16、 react context ,公共信息的主题颜色createContext

17、父组件更新以后,子组件是否需要重新渲染

18、scu的使用,为什么需要不变值进行处理

19、hoc组件增加,render props 作为插槽处理

20、纯函数的定义和原理

21 JSX的本质是什么,vue的本质是什么

22、 vue和react如何吧vnode渲染成真实的dom

23、 react性能优化

  • 1、渲染使用key
  • 2、事件销毁,定时任务销毁
  • 3、异步组件的使用
  • 4、合理使用bind this 次数
  • 5、scu的合理使用
  • 6、不可变值的性能处理
  • 7、webpack优化
  • 8、图片懒加载
  • 9、使用ssr
  • 10、

24、vue和react的区别

  • 共同点:
  1. 支持组件化
  2. 数据驱动视图
  3. vdom操作dom
  • 不同
  1. vue模版 react是jsx 爱的不同
  2. vue声明编程,数据都在data中提前声明,react函数编程setState利用方法来更新
  3. vue指令比较全面,react自己来做

25、打包构建发布webpack

优化构建打包

  • 生成环境
  1. 优化babel-loader:缓存,排除不需要的nodemodle,压缩
  2. ignorePlugin 排除代码体积
  3. noParse不引用资源
  4. happyPack 多进程打包
  5. paralleIUglifyPlugin 多进程压缩js
  • 开发环境 自动刷新,热更新,DllPlugin开发环境打包

产出代码

体积减小,合理分包,不重复加载速度更快,内存使用更少

  1. 图片压缩

  2. bunle+hash值

  3. 懒加载

  4. 提取公共代码 cache split chunks

  5. 使用cdn加速

  6. 环境设置prod,dev,代码压缩

  7. tree-shaking 代码