从同源策略到ES6新特性

同源策略(Same Origin Policy)

核心知识点

  1. 定义与限制

    同源策略要求两个 URL 的 ​协议、域名、端口 必须完全一致才允许交互。例如:
    https://example.comhttps://api.example.com不同源​(域名不同) 主要限制包括:DOM 跨域访问、AJAX 跨域请求、存储隔离(如 Cookie、LocalStorage)

  2. 跨域解决方案

    • CORS :服务器设置 Access-Control-Allow-Origin 头实现跨域资源共享

    • JSONP :利用 <script> 标签无跨域限制的特性,通过回调函数获取数据

    • 代理服务器:前端请求同源代理,由代理转发跨域请求

javascript 复制代码
javascript
// CORS 配置示例(后端)
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  next();
});

LocalStorage、SessionStorage、Cookie 区别

特性 Cookie LocalStorage SessionStorage
存储大小 4KB 5~10MB 5~10MB
生命周期 可设置过期时间或会话级关闭 永久存储,需手动删除 会话结束(标签页关闭)
自动发送到服务端 是(每次请求携带)
作用域 同源共享 同源共享 仅当前标签页

应用场景

  • Cookie:身份验证(如 JWT Token)

  • LocalStorage:持久化用户偏好(如主题设置)

  • SessionStorage:临时表单数据存储

GET vs POST 请求区别

核心区别

  1. 语义与用途

    • GET:获取资源(幂等,可缓存),如搜索请求

    • POST:提交数据(非幂等,不可缓存),如表单提交

  2. 数据传递与安全性

    • GET :参数通过 URL 明文传输(?key=value),长度限制约 2KB,安全性较低

    • POST:数据在请求体中传输,支持二进制数据,安全性较高(配合 HTTPS)

  3. 性能与缓存

    • GET 支持浏览器缓存和书签保存,POST 不缓存且可能触发 TCP 两次握手

    HTTP1.0和HTTP2.0的区别

HTTP/2是HTTP协议的最新版本,它在性能和功能上都有了显著的改进。

  • 性能

    • HTTP/2支持多路复用,可以在一个连接上同时发送多个请求和响应,减少了连接的开销。
    • HTTP/1.0和HTTP/1.1在处理多个请求时需要建立多个连接,这会增加延迟。
  • 连接方式

    • HTTP/2使用二进制分帧层,可以更高效地管理数据传输。
    • HTTP/1.0和HTTP/1.1使用文本协议,相对低效。
  • 头部压缩

    • HTTP/2对请求和响应的头部进行了压缩,减少了数据传输量。
    • HTTP/1.0和HTTP/1.1没有头部压缩功能。

    面试常见问题

  1. HTTP/2 的主要性能改进是什么? HTTP/2 的主要性能改进包括多路复用、服务器推送和头部压缩。

  2. HTTP/2 是否需要使用 HTTPS? 虽然 HTTP/2 不强制要求使用 HTTPS,但大多数浏览器只支持通过 HTTPS 实现的 HTTP/2。

  3. 如何在服务器上启用 HTTP/2? 在服务器上启用 HTTP/2 通常需要配置服务器软件(如 Nginx、Apache)并确保使用 HTTPS。

    垃圾回收机制详解

垃圾回收机制是浏览器自动管理内存的一种方式,它会定期检查并释放不再使用的内存。在前端开发中,了解垃圾回收机制有助于编写高效、稳定的代码,避免内存泄漏等问题。

常见的垃圾回收算法

标记清除

这是最常用的垃圾回收算法。垃圾回收器会标记所有活动的内存块,然后清除未被标记的块。这种方法可以有效回收不再使用的内存,但可能会导致一定的性能开销。

引用计数

这种算法会跟踪每个内存块的引用次数,当引用次数为零时,就认为该块可以被回收。引用计数的优点是简单高效,但存在循环引用的问题,即两个对象相互引用,导致引用计数始终不为零,无法被回收。

代际收集

将内存分为不同的代,新生代对象存活时间短,老生代对象存活时间长,针对不同代采用不同的回收策略。这种方法可以提高垃圾回收的效率,减少对整个内存的扫描。

内存泄漏的常见场景

未释放的DOM引用

在页面中,如果存在对DOM元素的引用,即使该DOM元素已经被移除,只要引用还存在,垃圾回收器就无法回收其占用的内存。

javascript 复制代码
let element = document.createElement('div');
document.body.appendChild(element);

// 移除DOM元素,但未释放引用
document.body.removeChild(element);
// element 引用仍然存在,导致内存泄漏

闭包引起的内存泄漏

闭包会捕获外部函数的变量,如果闭包长时间存在,可能导致这些变量无法被垃圾回收。

javascript 复制代码
function createClosure() {
  let largeData = new Array(1000000).fill('large data');
  return function() {
    console.log(largeData.length);
  };
}

let closure = createClosure();
// closure 仍然存在,导致 largeData 无法被回收

定时器引起的内存泄漏

定时器中的函数可能会捕获外部变量,如果定时器长时间运行,可能导致这些变量无法被回收。

javascript 复制代码
let data = new Array(1000000).fill('large data');
setInterval(function() {
  console.log('定时器运行中');
}, 1000);

// 如果不清理定时器,data 可能无法被回收

如何避免内存泄漏

及时释放引用

在不再需要某个对象时,将其引用设为 null,帮助垃圾回收器回收内存。

ini 复制代码
let largeObject = new Array(1000000).fill('large data');
// 使用完后释放引用
largeObject = null;

合理使用闭包

避免不必要的闭包,或者在闭包中及时释放对外部变量的引用。

ini 复制代码
function createClosure() {
  let largeData = new Array(1000000).fill('large data');
  let closure = function() {
    console.log(largeData.length);
  };
  // 在适当的时候释放引用
  closure.cleanup = function() {
    largeData = null;
  };
  return closure;
}

let closure = createClosure();
// 使用完后调用 cleanup 方法
closure.cleanup();

清理定时器

在组件销毁或不再需要定时器时,及时清理定时器。

javascript 复制代码
let timer = setInterval(function() {
  console.log('定时器运行中');
}, 1000);

// 清理定时器
clearInterval(timer);

面试常见问题

  1. 垃圾回收机制的作用是什么? 垃圾回收机制的主要作用是自动管理内存,释放不再使用的内存,避免内存泄漏,提高程序的性能和稳定性。
  2. 常见的垃圾回收算法有哪些? 常见的垃圾回收算法包括标记清除、引用计数和代际收集。
  3. 如何避免内存泄漏? 避免内存泄漏的方法包括及时释放引用、合理使用闭包、清理定时器等。

JavaScript 数据类型及其区别

JavaScript 数据类型分为 ​基本数据类型 ​(原始类型)和 ​引用数据类型​(对象类型)。它们的核心区别在于存储方式、可变性及比较逻辑

1. ​基本数据类型(7种)​

  • 类型列表UndefinedNullBooleanNumberStringSymbol(ES6)、BigInt(ES10)。

  • 特点

    • 不可变性 :值本身无法被修改(如 let s = 'a'; s = 'b' 实际是创建新值)。

    • 栈存储:直接存储在栈内存中,占用空间小且固定

    • 按值比较1 === 1true

  • 特殊值

    • NaN:表示无效数值,typeof NaN 返回 "number",且 NaN !== NaN

    • Symbol:唯一且不可变,用于解决命名冲突(如对象属性键)

2. ​引用数据类型

  • 类型列表ObjectArrayFunctionDateRegExp 等。

  • 特点

    • 可变性 :对象内容可修改(如 arr.push(1))。

    • 堆存储:值存储在堆中,栈中存储指向堆的指针

    • 按引用比较{} === {}false(比较内存地址)。

3. ​核心区别

特性 基本类型 引用类型
存储位置
赋值行为 复制值 复制指针
添加属性/方法 不支持 支持
内存管理 自动回收 需手动或 GC 回收

数据类型检测方法

1. typeof 运算符

  • 用途 :检测基本类型(undefinedbooleannumberstringsymbolbigint)。

  • 局限性

    • typeof null 返回 "object"(历史遗留问题)

    • 无法区分数组与普通对象(均返回 "object")。

csharp 复制代码
typeof "hello";        // "string"
typeof null;           // "object"(注意误判)

2. instanceof 运算符

  • 用途:检测对象是否为某个构造函数的实例。
  • 局限性:无法检测基本类型,且跨框架对象可能失效。
javascript 复制代码
[] instanceof Array;   // true
{} instanceof Object;   // true

3. Object.prototype.toString.call()

  • 最精准方法 :返回 [object Type] 格式字符串,支持所有类型
javascript 复制代码
Object.prototype.toString.call(null);     // "[object Null]"
Object.prototype.toString.call([]);        // "[object Array]"

4. 其他方法

  • Array.isArray():专用于检测数组。
  • isNaN():检测是否为 NaN(需注意类型转换问题)。

作用域与作用域链

1. ​作用域类型

  • 全局作用域:在函数或代码块外定义的变量,全局可访问。

  • 函数作用域var 声明的变量在函数内有效。

  • 块级作用域let/const 声明的变量在代码块({})内有效(ES6+)

2. ​作用域链

  • 定义:当前作用域 → 外层作用域 → ... → 全局作用域的链式结构。

  • 查找规则:变量不存在时,沿链向上查找,直至全局作用域(未找到则报错)

  • 闭包原理 :内层函数保留对外部作用域的引用(如计数器函数保留 count 变量)。

javascript 复制代码
function outer() {
  const outerVar = "outer";
  return function inner() {
    console.log(outerVar); // 通过作用域链访问外部变量
  };
}

原型与原型链

1. ​原型(Prototype)​

  • 构造函数原型 :每个函数都有 prototype 属性,用于共享方法。

  • 对象隐式原型 :每个对象都有 __proto__,指向其构造函数的 prototype

ini 复制代码
function Person(name) { this.name = name; }
Person.prototype.sayHello = function() { console.log(this.name); };

const john = new Person("John");
john.__proto__ === Person.prototype; // true

2. ​原型链

  • 继承机制 :对象通过 __proto__ 链继承属性和方法,终点为 null
  • 查找规则 :先自身查找 → 沿 __proto__ 链向上查找。
ruby 复制代码
john.hasOwnProperty("name"); // true(来自 Object 原型方法)

JavaScript 中 this 的指向

this 的值由 ​函数调用方式 决定,而非定义位置

1. ​默认绑定

  • 全局上下文this 指向 window(浏览器)或 global(Node.js)。
  • 严格模式thisundefined
scss 复制代码
function showThis() { console.log(this); }
showThis(); // 浏览器中输出 window

2. ​隐式绑定

  • 对象方法this 指向调用该方法的对象。
javascript 复制代码
const obj = {
  value: 42,
  logValue() { console.log(this.value); }
};
obj.logValue(); // 42

3. ​显式绑定

  • call/apply/bind:强制指定 this
javascript 复制代码
function greet() { console.log(this.name); }
const user = { name: "Alice" };
greet.call(user); // "Alice"

4. ​构造函数绑定

  • new 操作符:this 指向新创建的对象实例。
ini 复制代码
function Car(brand) { this.brand = brand; }
const myCar = new Car("Tesla");

5. ​箭头函数

  • 词法绑定this 继承外层作用域的 this,无法通过 call 修改。
javascript 复制代码
const obj = {
  value: "Hello",
  arrowFunc: () => console.log(this.value) // this 指向全局对象
};

事件循环(Event Loop)​

JavaScript 通过 ​事件循环 处理异步任务,核心流程为:

  1. 同步代码 :优先执行调用栈中的同步任务(如 console.log)。

  2. 微任务队列 :清空所有微任务(如 Promise.thenMutationObserver)。

  3. 渲染更新 :执行 requestAnimationFrame 回调,更新页面渲染。

  4. 宏任务队列 :执行一个宏任务(如 setTimeoutDOM 事件),循环往复= 执行优先级

    同步代码 → 微任务 → 渲染 → 宏任务

    示例:

javascript 复制代码
setTimeout(() => console.log('宏任务'), 0);
Promise.resolve().then(() => console.log('微任务'));
console.log('同步代码');
// 输出顺序:同步代码 → 微任务 → 宏任务

对闭包的理解

闭包是函数和其定义时的词法环境的引用的组合。闭包允许函数访问其定义时的作用域中的变量,即使该函数在其他作用域中被调用。

闭包的优缺点

  • 优点

    • 可以访问和修改外部函数的变量,实现数据封装和信息隐藏。
    • 实现函数的持久状态,用于事件处理、回调函数等场景。
  • 缺点

    • 如果不正确使用,可能导致内存泄漏,因为闭包会捕获外部变量,阻止其被垃圾回收。

闭包的应用场景

  • 模块模式:通过闭包实现模块的私有变量和方法。
  • 事件处理:在事件回调函数中使用闭包访问外部变量。
  • 函数节流和防抖:利用闭包保存上次执行的时间或函数调用的状态。
scss 复制代码
// 闭包示例
function outer() {
  let count = 0;
  return function inner() {
    count++;
    console.log(count);
  };
}

const counter = outer();
counter(); // 1
counter(); // 2
counter(); // 3

new 运算符底层原理

1. ​四步核心流程

当执行 new Constructor() 时,发生以下操作:

  1. 创建空对象 :生成一个新对象 obj = {}

  2. 绑定原型链 :设置 obj.__proto__ = Constructor.prototype

  3. 绑定 this :执行构造函数,this 指向 obj

  4. 处理返回值 :若构造函数返回对象,则替代 obj;否则返回 obj

手写模拟 new

javascript 复制代码
javascript
function myNew(Constructor, ...args) {
  const obj = Object.create(Constructor.prototype);
  const result = Constructor.apply(obj, args);
  return result instanceof Object ? result : obj;
}

2. ​易错场景与规避

  • 忘记 new :构造函数直接调用导致 this 指向全局(严格模式报错):
ini 复制代码
function Person(name) {
  this.name = name;
}
const p = Person('Alice'); // 错误!this 指向 window
  • 构造函数返回对象:可能中断原型链:
javascript 复制代码
function Dog() { return { name: '旺财' }; }
const dog = new Dog();
dog instanceof Dog; // false(原型链断裂)

ES6 新特性详解(ECMAScript 2015)

ES6(ECMAScript 2015)是 JavaScript 语言的一次重大升级,引入了诸多现代化特性,显著提升了开发效率和代码可维护性。以下是其核心新特性及实际应用场景:


一、变量声明:块级作用域与常量

  1. ​**letconst**

    • 块级作用域letconst 声明的变量仅在代码块(如 {})内有效,解决了 var 的变量提升问题

    • 不可重复声明:同一作用域内禁止重复声明变量,避免命名冲突

    • 常量 const:声明时必须赋值且不可修改(对象属性或数组元素可修改)

    ini 复制代码
    {
      let x = 10;
      const PI = 3.14;
      // PI = 3.15; // 报错
    }

二、函数增强:箭头函数与默认参数

  1. 箭头函数(Arrow Functions)​

    • 简洁语法 :省略 function 关键字,单行表达式可隐式返回

    • 词法 this :继承外层作用域的 this,适合回调函数和避免 this 绑定问题

    javascript 复制代码
    const add = (a, b) => a + b;
    setTimeout(() => console.log(this.value), 100); // this 指向外层
  2. 默认参数

    函数参数支持默认值,简化条件判断

    ini 复制代码
    const greet = (name = "Guest") => `Hello, ${name}!`;

三、字符串处理:模板字符串与扩展方法

  1. 模板字符串

    使用反引号 ````` 和 ${} 嵌入变量或表达式,支持多行文本

    javascript 复制代码
    const name = "Alice";
    console.log(`Hello, ${name}!
    Today is ${new Date().toDateString()}.`);
  2. 新增字符串方法

    • includes():检查子字符串是否存在
    • padStart() / padEnd():填充字符串至指定长度
    • replaceAll():全局替换(ES12 特性)

四、解构赋值与扩展运算符

  1. 解构赋值

    从数组或对象中提取值并赋值,简化代码

    arduino 复制代码
    // 数组解构
    const [a, b] = [1, 2];
    // 对象解构
    const { name, age } = { name: "Alice", age: 25 };
  2. 扩展运算符(...)​

    展开数组或对象,用于合并、克隆或函数传参

    ini 复制代码
    const mergedArr = [...arr1, ...arr2];
    const clonedObj = { ...original };

五、数据结构:Set、Map 与 Symbol

  1. Set 和 Map

    • Set:存储唯一值,自动去重

    • Map :键值对集合,支持任意类型键(优于 Object

    dart 复制代码
    const unique = new Set([1, 2, 2, 3]); // {1, 2, 3}
    const map = new Map();
    map.set("key", "value");
  2. Symbol

    创建唯一标识符,用于避免对象属性名冲突

    ini 复制代码
    const sym = Symbol("unique");
    const obj = { [sym]: "private" };

六、异步处理:Promise

  1. Promise 对象

    管理异步操作状态(Pending → Fulfilled/Rejected),支持链式调用

    ini 复制代码
    fetchData()
      .then(data => process(data))
      .catch(error => console.error(error));
  2. 静态方法

    • Promise.all:并行执行多个 Promise,全成功时返回结果数组

    • Promise.race:返回首个完成的 Promise 结果


七、面向对象:类与继承

  1. 类(Class)​

    提供更清晰的语法定义构造函数和方法

    javascript 复制代码
    class Animal {
      constructor(name) { this.name = name; }
      speak() { console.log(`${this.name} makes noise.`); }
    }
    class Dog extends Animal {
      speak() { console.log(`${this.name} barks!`); }
    }

八、模块化:importexport

  1. 模块化语法

    支持将代码拆分到不同文件,通过 importexport 管理依赖

    javascript 复制代码
    // math.js
    export const PI = 3.14;
    // app.js
    import { PI } from './math.js';
相关推荐
irving同学462381 小时前
Next.js 组件开发最佳实践文档(TypeScript 版)
前端
刺客-Andy1 小时前
React Vue 项开发中组件封装原则及注意事项
前端·vue.js·react.js
marzdata_lily1 小时前
从零到上线!7天搭建高并发体育比分网站全记录(附Java+Vue开源代码)
前端·后端
小君1 小时前
让 Cursor 更加聪明
前端·人工智能·后端
顾林海1 小时前
Flutter Dart 异常处理全面解析
android·前端·flutter
残轩2 小时前
JavaScript/TypeScript异步任务并发实用指南
前端·javascript·typescript
用户88442839014252 小时前
xterm + socket.io 实现 Web Terminal
前端
helloYaJing2 小时前
代码封装:超时重传方法
前端
literature16882 小时前
隐藏的git文件夹
前端·git
12码力2 小时前
使用 Three.js + Three-Tile 实现地球场景与几何体
前端