2024前端面试笔记

本文详细解释了JavaScript中的原型链机制、函数的this指向、闭包原理,以及Vuex和vue-router在状态管理和路由控制中的应用,包括编程式导航和导航守卫。
摘要由CSDN通过智能技术生成

js原型链

原型链就是实例对象和原型对象之间的链接。每个函数都有一个prototype属性,这个prototype属性就是我们的原型对象,我们拿这个函数通过new构造函数创建出来的实例对象,这个实例对象自己会有一个指针(proto)指向他的构造函数的原型对象!这样构造函数和实例对象之间就通过( proto )连接在一起形成了链条。
JS的每个函数在创建的时候,都会生成一个属性prototype,这个属性指向一个对象,这个对象就是此函数的原型对象。该原型对象中有个属性为constructor,指向该函数。这样原型对象和它的函数之间就产生了联系。

// 构造函数
function Person(name,age){
    this.name = name;
    this.age = age;
}
 
// 原型对象上的公共方法
Person.prototype.say =  function (word)  {
    // 模板字符串
    console.log(`${this.name}说:${word}`)
}
 
// 创建实例
const lili = new Person('lili',18);
// 返回布尔值,指对象自身属性中是否有指定属性
console.log("hasOwnProperty",lili.hasOwnProperty('say')) // false 说明不是定义再本身上的
 
lili.say('hello world') // 可以调用公共方法

递归

什么是递归
一个方法或函数内部调用了自己,这就叫递归。如下
递归必须要有终止条件否则会超出最大调用堆栈大小

<script>
//求和
  const handel = (n: number) => {
    // 基本情况:当 n 等于 0 或 1 时,直接返回 1
    if (n === 0 || n === 1) {
        return 1;
    }
    // 递归调用:将问题分解为更小的子问题
    return n + handel(n - 1);
    
}
console.log(handel(5))//15

//最大公约数
const handel1 = (m,n)=> {
    if (n == 0) return m
    return fn(n,m % n)
}
console.log(fn(10,8));//2
</script>

闭包

如果一个函数访问了此函数的父级及父级以上的作用域变量,那么这个函数就是一个闭包。
从广义的角度来说:JavaScript中的函数都是闭包;
从狭义的角度来说:JavaScript中一个函数,如果访问了外层作用于的变量,那么它是一个闭包;

//例如
    var a = 1;
	// 匿名的立即执行函数,因访问了全局变量a,所以也是一个闭包
    (function test (){
		alert(a);
	})()
//本质上,JS中的每个函数都是一个闭包,因为每个函数都可以访问全局变量。

闭包的作用
延伸了函数的作用范围,读取函数内部的变量
让变量的值始终保持在内存中。不会在调用后被自动清除。
方便调用上下文的局部变量。利于代码封装。
闭包的优缺点
1.优点
避免全局变量的污染
能够读取函数内部的变量
可以在内存中维护一个变量
2.缺点
闭包会常驻内存,会增大内存使用量,导致一定程度上的内存泄露。
在游览器中因为回收机制无法回收闭包的函数以及闭包函数中储存的数据,会使游览器占用更多的性能开销
内存的泄漏
当一个对象有一个引用指向它时,那么这个对象的引用就+1,当一个对象的引用为0时,这个对象就可以被销毁掉;
这个算法有一个很大的弊端就是会产生循环引用;这样就会造成内存泄漏

this指向问题

1.普通函数:关于this,谁调用就指向谁,没有调用者,就指向全局对象window。
2.箭头函数没有自己的this指向,它会捕获自己定义所处的外层执行环境,并且继承这个this值,指向当前定义时所在的对象。箭头函数的this指向在被定义的时候就确定了,之后永远都不会改变。即使使用call()、apply()、bind()等方法改变this指向也不可以
3.有时候我们需要改变this的指向,也就是说使函数可以被其他对象来调用,那么我们可以用下面的方法
改变普通函数的this指向
在JavaScript中,call()、apply()和bind()是Function对象自带的三个方法,这三个方法的主要作用是改变函数中的this指向
相同点

  1. apply 、 call 、bind 三者都是用来改变函数的this对象的指向;
  2. apply 、 call 、bind 三者都可以利用后续参数传参;
    不同点
    1.接受参数上call、bind接收多个参数,apply接收一个数组;
    2.区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
call

//.函数.call() 参数不传,或者传递null,undefined, 函数中的this指向window对象
//
var n = 123;
var obj = { n: 456 };
function a() {
  console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456

apply

//pply()方法作用与call()方法类似,也是改变this指向,然后再调用该函数,唯一的区别在于:appl接收一个数组做为函数执行时的函数。
//格式: func.apply(thisValue,[ arg1 , arg2… ])
//如果参数不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
function class1(args1,args2){       
  this.name=function(){      
   console.log(args,args);      
  }     
}     
function class2(){    
  var args1="1";
  var args2="2";
  class1.call(this,args1,args2);  
  /*或*/
  class1.apply(this,[args1,args2]);
}
var c=new class2();   
c.name();//1,2


bind

//bind() 方法与 apply 和 call 很相似,也是可以改变函数体内 this 的指向。然后返回一个新的函数。
//注意:bind方法的返回值是函数
var bar=function(){   
  console.log(this.x);   
}
var foo={ 
     x:3   
}   
bar();  			//undefined
bar.bind(foo)();	//3
 /*或*/
var func=bar.bind(foo);   
func();				//3

应用

//数组之间追加
var array1 = [12 , “foo” , {name “Joe”} , -2458];
var array2 = [“Doe” , 555 , 100];
Array.prototype.push.apply(array1, array2);
///* array1 值为 [12 , “foo” , {name “Joe”} , -2458 , “Doe” , 555 , 100] */
//获取数组中的最大值和最小值
var numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers), //458
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
//number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法。

vuex

import Vue from 'vue'
import Vuex from 'vuex'
 
Vue.use(Vuex)
 
export default new Vuex.Store({
  //数据,相当于data
  state: {
    
  },
  getters: {
    
  },
  //里面定义方法,操作state方发
  mutations: {
    
  },
  // 操作异步操作mutation
  actions: {
    
  },
  modules: {
    
  },
})

State(状态):Vuex 使用一个单一的状态树来管理应用的所有状态,即一个对象包含了全部的应用层级状态。可以通过 this.$store.state 来访问状态。

Getters(获取器):Getters 可以理解为 store 的计算属性。可以通过定义一些 getter 函数来获取 state 中的值,类似于 Vue 中的计算属性。

Mutations(变更):Mutations 是唯一允许修改状态的地方。每个 mutation 都有一个字符串的事件类型和一个回调函数,通过调用 store.commit 方法来触发 mutation。

Actions(动作):Actions 类似于 mutations,但是可以包含任意异步操作。通过调用 store.dispatch 方法来触发 action。Action 可以包含多个 mutation,通过提交 mutation 来改变状态。

Mutations(变更): 是 Vuex 中用于修改状态的方法。它是唯一允许修改状态的地方,类似于事件的处理器。每个 mutation 都有一个字符串的事件类型和一个回调函数,通过调用 store.commit 方法来触发 mutation。

Modules(模块):Vuex 允许将 store 分割成模块。每个模块拥有自己的 state、getters、mutations 和 actions,可以通过模块化的方式组织和管理复杂的应用。

       通过使用 Vuex,我们可以更好地组织和管理应用的状态,使得状态的变更更加可追踪和可维护。同时,也可以方便地在组件中获取和修改状态,简化了组件之间的通信。

vue-router

1 vue-router 中的编程式导航 API
vue-router 提供了许多编程式导航的 API,其中最常用的导航 API 分别是:

  1. this.$router.push(‘hash 地址’)

跳转到指定 hash 地址,并增加一条历史记录

  1. this.$router.replace(‘hash 地址’)

跳转到指定的 hash 地址,并替换掉当前的历史记录

③3this.$router.go(数值 n)

实现导航历史前进、后退

4.$router.back()

在历史记录中,后退到上一个页面

  1. $router.forward()

在历史记录中,前进到下一个页面
导航守卫
1 全局前置守卫
每次发生路由的导航跳转时,都会触发全局前置守卫。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制:

const router = new VueRouter({ ...})
router.before.Each((to, from, next) => {
    //to将要访问的页面
    //from将要离开的页面
    //next是一个函数,调用next()表示方形,允许跳转
    //例如
    if (to.path === './main') {
        const token = localStorage.getItem("token")
        if(token){
            next()
        }
    }
})

还有一种写法就是给每一个路由添加 meta 配置项,通过meta里的真假值来判断是否需要进行判断

     { 
        path: 'users',
        component: Users,
        meta: { isAuth: true },
      },
      ...
      
// 全局前置守卫
router.beforeEach((to, from, next) => {
    if (to.meta.isAuth) { // 判断是否需要进行导航守卫
        const token = localStorage.getItem('token')
        if (token) {
            next()
        } else {
            next('/login')
        }
    } else {
        next()
    }
})

全局后置钩子
每次发生路由的跳转之后,都会触发全局后置钩子

	...
     { 
        path: 'users',
        component: Users,
        meta: { isAuth: true, title: '用户管理'  },
      },
     ...
// 全局后置守卫
router.afterEach(function (to, from) {
  document.title = to.meta.title || '管理系统'
})

路由独享守卫

	...
     { 
        path: 'users',
        component: Users,
        meta: { isAuth: true, title: '用户管理'  },
        beforeEnter: (to, from, next)=>{
		   // ...
        }
      },
     ...

组件内路由守卫

<template>
  <h4 class="text-center">订单管理</h4>
</template>

<script>
export default {
  name: 'MyOrders',
  // 通过路由规则,进入该组件时被调用
  beforeRouteEnter(to, from, next){
    // ...
  },
  // 通过路由规则,离开该组件时被调用
  beforeRouteLeave(to, from, next){
    // ...
  }
}
</script>

路由的两种工作模式

路由有两种工作模式,分别是:hash 和 history
hash模式
1.默认开启的就是 hash 的工作模式
2.网页路径端口号后的#就是代表hash,后面跟着的是hash值
3.注意:# 后面的值都是不发给服务器的
history 模式
开启 history 模式要添加一个 mode配置项 ,默认是 hash,history 是没有 # 号的

import { createRouter, createWebHashHistory } from 'vue-router'
import { constantRoute } from './routes'
// 创建路由器
const router = createRouter({

  mode:'history',
  routes: constantRoute,
})
export default router

hash 和 history 的区别
对于一个url来说,什么是hash值?——#及其后面的内容就是hash值
hash值不会包含在HTTP请求中,即:hash值不会带给服务器
hsah模式
1.地址中永远带有#号,不美观
2.若以后将地址通过第三方手机app分享,若app效验严格,则3.地址会被标记为不合法
3.兼容性较好
history模式
1.地址干净美观
2.兼容性和hash模式相比略差
3.应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题
总结
① 能够知道如何在 vue 中配置路由

createRouter、app.use(router)
② 能够知道如何使用嵌套路由

通过 children 属性进行路由嵌套
③ 能够知道如何实现动态路由匹配

使用冒号声明参数项、this.$route.params、props: true
④ 能够知道如何使用编程式导航

this.router.push 、this.router.go
⑤ 能够知道如何使用导航守卫

路由实例.beforeEach((to, from, next) => { /* 必须调 next 函数 */ })
⑥ 能知道路由守卫有多少种

全局前置路由守卫、全局后置钩子、独享路由守卫、组件内路由守卫
⑦能够知道路由的两种方式
hash 模式和 history 模式

watch与computed区别总结

功能上:computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。

是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。

是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。

computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)

使用场景:computed----当一个属性受多个属性影响的时候,使用computed-----购物车商品结算。watch–当一条数据影响多条数据的时候,使用watch-----搜索框.

  • 17
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值