前端 面试题

本文介绍了JavaScript中的开包(函数柯里化)、闭包的概念及其优缺点,探讨了原型链、防抖与节流的区别,以及递归的原理和应用场景,还涉及了去重方法(Set和扩展运算符)和数组操作(indexOf)。

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

什么是开包和闭包

开包:开包也可以叫函数柯里化,是将接收多个参数的函数转换成一系列使用单个参数的函数

 function add(x, y) {
        return x + y
    }
    function addToX(x) {
        return function (y) {
            return add(x, y)
        }
    }
    const addFive = addToX(5);
    addFive(2); // 7

闭包

  • 函数嵌套函数
  • 函数内部可以引用外部的参数和变量
  • 参数和变量不会被垃圾回收机制回收,会永远留驻在内存中

闭包优点:长时间储存变量在内存中,减少全局变量的污染,加强封装性
闭包缺点:占用更多的内存导致内存泄漏,或性能下降

闭包不是回调,回调也不是闭包,回调是函数内执行另一个函数闭包是函数内返回另一个函数且返回了父级函数的作用域变量

垃圾回收机制:简单的说,当一个函数被执行完后,其作用域会被收回

 function counter() {
        let count = 0
        return () => {
            return ++count
        }
    }
    const c = counter()
    console.log(c())	//1
    console.log(c())	//2
    console.log(c())	//3

原型链

  • 原型:portoType属性就是函数的原型
  • 原型链:所有对象都有原型,而原型本身就是对象,所以原型也有自己的原型对象,就形成了原型链
  • 如果对象本身没有属性,就会去原型链上找
  • object原型对象的原型值为null

防抖和节流

  • 防抖:触发事件后在N秒内只执行一次,如果再次触发则重新计算函数执行时间(每多少秒内只能执行一次,再次点击重新算时间
  • 节流:每次触发事件后的时间间隔至少要大于等于N秒,不会重置计时(每多少秒可以触发一次

递归

什么是递归
  • 自身调用自身
  • 至少应该有一个结束条件

使用场景

  • 多层级结构,并且每个层级大致相同,而且前后还有关联性
    递归比普通函数效率低,日常还是少用吧
function walk(step){
	if(step == 0){
		console.log('结束了')
	}else{
		step--
		walk(step)
	}
}
walk(100)  //默认传了100

去重

  • new Set() 和扩展运算符结合
	 	let arr = [1,2,3,4,5,1,2,3,4,5,6]
	 	let setArr = new Set(arr)
       	console.log(setArr)   //返回set数据结构   Set(3) {1,2,3,4,5,6,7}
      	//es6的 ... 运算符
       	console.log([...setArr])  //输出  [1, 2, 3, 4, 5, 6]
       	console.log(...setArr)  //输出  1, 2, 3, 4, 5, 6
  • indexOf
  let arr1 = [1,2,3,4,5,1,2,3,4,5,6]
       let arr2 = []
       for(let i in arr1){
           if(arr2.indexOf(arr1[i]) === -1){   //如果数组中没有当前数值,indexOf 则返回-1, 
               arr2.push(arr1[i])
           }
       }
       console.log(arr2)
  • 双层循环,外层循环数组1,内层循环数组2,数组2中有则跳过,没有则push

封装过的组件

  • 图片上传组件
  • 轮播图组件
  • 日期选择器
  • 头部,侧边栏,底部,导航栏组件等

封装的方法有那些

vue组件之间通讯

V2

  • 父子组件通讯:通过 props 将数据从父组件传到子组件,子组件修改参数后通过$emit方法触发事件告诉父组件
  • 子父组件通讯:通过在子组件中使用 $emit 方法触发一个事件,在父组件中使用 $on 方法监听该事件,从而实现子组件向父组件通信。
  • 兄弟组件通讯:可以通过一个父组件作为中介,在父组件定义变量,通过props分别传给两个子组件,其中一个子组件修改了变量后,通过$emit传回父组件,在逐级传递给另一个子组件
  • 无关组件通讯:可以使用事件总线(Event Bus)实现无关组件间的通讯,也就是一个空的vue实例(事件总线)上定义一个事件,然后任意组件通过$emit 和 $on方法分别触发和监听该事件来实现通讯
  • Vuex :Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,通过共享一个全局状态对象,实现组件之间的数据共享和通信。Vuex 将所有的状态都保存在 state 中,然后通过 mutations 修改 state,最后在 actions 中触发 mutations 从而修改 state 中的数据,最终通过 getters 获取 state 中的数据。

es6 新增的特性

1. let和const

都有作用域,不能同一个作用域重复声明,const 声明变量必须有默认值

2. 字符串模板 “${}

3. 箭头函数 “()=>{}”

4. 扩展运算符 “…”

5.结构赋值

方便数据提取和赋值方式,他可以从数组或者对象中提取值,然后单独赋值给变量

数组的结构赋值

let [a, b, c] = [1, 2, 3];
console.log(a); // 1 
console.log(b); // 2 
console.log(c); // 3 
// 可以跳过某些位置 
let [x, , z] = [4, 5, 6]; 
console.log(x); // 4 
console.log(z); // 6  
// 可以使用剩余操作符 `...` 收集剩余的元素 
let [m, n, ...rest] = [7, 8, 9, 10, 11]; 
console.log(m); // 7 
console.log(n); // 8 
console.log(rest); // [9, 10, 11]

对象的解构赋值

let { name, age } = { name: "John", age: 30 }; 
console.log(name); // John 
console.log(age); // 30
// 可以给变量起不同的名字
let { name: myName, age: myAge } = { name: "Jane", age: 25 };
console.log(myName); // Jane
console.log(myAge); // 25
// 可以设置默认值
 
let { city = "New York" } = {}; 
console.log(city); // New York

6.map/set

Map:Map 是键值对的集合,其中键可以是任何类型的值(包括对象),而不仅仅是字符串。

// 创建
let myMap = new Map();
myMap.set("key1", "value1");
myMap.set(2, "value2");
myMap.set({ name: "John" }, "value3");
// 获取
console.log(myMap.get("key1"));
console.log(myMap.get(2));
console.log(myMap.get({ name: "John" }));
// 检查键是否存在
console.log(myMap.has("key1"));
// 删除键值对
myMap.delete("key1");
// 获取 Map 的大小
console.log(myMap.size)
// 遍历 Map
for (let [key, value] of myMap) {
  console.log(key + ': ' value);
}

Set:Set 是一种不允许重复值的数据结构。

// 创建
let mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add(2); // 重复添加不会有效果
mySet.add("Hello");
 
// 检查元素是否存在
console.log(mySet.has(1));
// 删除元素
mySet.delete(1);
// 获取 Set 的大小
console.log(mySet.size);
// 遍历 Set
for (let item of mySet) {
  console.log(item);
}

7.symbol

在 ES6 中,Symbol 是一种新的基本数据类型,它的主要目的是创建独一无二的值,通常用于对象的属性名,以避免属性名冲突。

let sym1 = Symbol();
let sym2 = Symbol("description"); // 可以提供一个可选的描述字符串

8.promise

9.类 class

10.剩余参数

ES6 中的剩余参数语法允许将不定数量的参数表示为一个数组。

其语法形式为:在函数的最后一个命名参数前加上三个点(…),后面跟着参数名,例如:function(a, b,…theArgs){ // 函数体 } ,在这个例子中,theArgs 将收集该函数的第三个参数及以后的所有剩余参数。

function fun1(...theArgs) {
  alert(theArgs.length);
}
 
fun1(); // 弹出"0", 因为 theArgs 没有元素
fun1(5); // 弹出"1", 因为 theArgs 只有一个元素
fun1(5, 6, 7); // 弹出"3", 因为 theArgs 有三个元素
 
function multiply(multiplier,...theArgs) {
  return theArgs.map(function(element) {
    return multiplier * element;
  })
}
 
var arr = multiply(2, 1, 2, 3);
console.log(arr); // (2, 4, 6)

function sortRestArgs(...theArgs) {
  var sortedArgs = theArgs.sort();
  return sortedArgs;
}
alert(sortRestArgs(5, 3, 7, 1)); // 弹出 1, 3, 5, 7

// 剩余参数可以被解构
function f(...(a, b, c)) {
  return a + b + c;
}
f(1) // NaN (b 和 c 是 undefined)
f(1, 2, 3) // 6
f(1, 2, 3, 4) // 6 (第四个参数没有被解构)

11.模块化

ES6 引入了模块化的概念,这使得 JavaScript 代码的组织和管理更加清晰和高效。

一个模块就是一个独立的 JavaScript 文件。模块内的变量、函数、类等默认是私有的,只有通过 export 关键字导出的部分才能被其他模块使用。

// 导出单个变量或函数
export const num = 42;
export function add(a, b) {
  return a + b
}
 
 
// 也可以将多个导出写在一处
const str = "Hello";
function subtract(a, b) {
  return a - b;
}
export { str, subtract };

//对应页面导入
import { num, add } from "./module1";

常见的数据类型

字符串

String

数字

Number

数组

Array

布尔值

true和false。

null

null类型的默认值是null,从逻辑角度讲,是表示一个空对象指针

对象

Object

函数

function

未定义(Undefined)

声明了变量,但是没有初始化

日期

new Data()

Symbol

Symbol 类型本质上是一种唯一标识符,可用作对象的唯一属性名。

页面布局的几种方式

静态布局

浮动布局

定位布局

栅格布局

table布局

弹性(flex)布局

圣杯布局

自适应布局

流式布局

响应式布局

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值