高级前端题库
前端题库
JS篇
如何理解作用域和作用域链
- 作用域
作用域就是变量或函数在其内能够被访问的“可见区域”- 全局作用域
- 局部作用域
- 作用域链
当在某个作用域中尝试访问一个变量时,JS引擎会从当前作用域开始,沿着作用域链向上逐级开始查找,直到找到该变量为止,如果在全局作用域仍然找不到,则抛出未定义错误。
闭包是什么,有哪些缺点,哪些使用场景
闭包是值一个函数与其词法环境的组合。这个词法环境包含了闭包创建时在作用域的所有局部变量。闭包允许函数访问并操作外部函数的变量,即时外部函数已经执行完成。
-
优点
- 封装性:闭包可以创建私有变量,限制外部对某些变量的访问。这有助于实现信息隐藏和模块化编程。
- 状态持久性:闭包能够持久化某些状态,允许在不同的调用之间保持变量的值。
- 回调机制:在异步编程中,闭包可以捕获和保持对外部变量的引用,使得在异步操作完成后仍能访问这些变量。
- 函数工厂:闭包可以用于生成具有特定行为的函数,例如创建配置化的函数或生成器。
-
缺点
- 内存管理:闭包会保持对外部作用域变量的引用,可能导致内存泄漏,特别是不再需要时未能及时释放。
- 性能开销:每次创建闭包都会增加内存占用,频繁创建闭包可能会影响性能,尤其是高频调用的场景中。
- 调试复杂:闭包的作用域链可能导致调试变得复杂,尤其是在深层嵌套或多层回调的情况下,可能难以追踪变量的来源。
-
使用场景
- 模块模式:使用闭包来创建模块,隐藏内部实现细节,暴露公共接口。
const Module = (function(){let privateVar = "private value";return {getPrivateVar:function(){return privateVar}}
})()
console.log(Module.getPrivateVar()) // private value
- 事件处理:在事件处理函数中使用闭包来保持对外部变量的引用,避免被意外修改。
function setupButton(buttonId){let button = document.getElementById(buttonId)let count = 0;button.addEventListener('click',function(){count ++;console.log(`Button clicked ${count} times`)})
}
setupButton("myButton")
- 计时器和状态管理:通过闭包实现简单的计时器,保存状态。
function createCounter(){let count = 0;return {increment:function(){count++;return count;},decrement:function(){count--;return count;},getCount:function(){return count;}}
}
- 延迟执行:在需要延迟执行的场景中,闭包可以捕获外部变量的状态
function delay(message,seconds){setTimeout(function(){console.log(message)},seconds * 1000)
}
delay("hello",2)
防抖节流区别是什么,如何实现防抖和节流
限制函数执行频率的两种策略
- 防抖 (Debouncing)
防抖是一种控制函数延时执行的技术,目的是确保在事件触发后,只有在指定的延迟时间内没有再次触发事件时,才执行回调函数。防抖主要用于处理高频率的事件。
function debounce(func,delay){let timer;return functon(...args){clearTimeout(timer);timer = setTimeout(() => {func.apply(this,args)},delay)}
}
const handleInput = debounce(() => {console.log("input event handled")
},2000)
document.getElementById("inputId").addEventListener("input",handleInput)
- 节流(Throttling)
节流是一种控制函数执行频率的技术,确保在指定时间间隔内,回调函数只会执行一次。
function throttle(func,limit){let lastFunc;let lastRan;return function(...args){const context = this;if(!lastRan){func.apply(context,args);lastRan = Date.now()}else{clearTimeout(lastFunc)lastFunc = setTimeout(() => {if (Date.now() - lastRan >= limit) {func.apply(context, args); // 在限制时间后执行lastRan = Date.now(); // 更新上次执行时间}}, limit - (Date.now() - lastRan));}}
}
const handleScroll = throttle(() => {console.log('Scroll event handled');
}, 1000);window.addEventListener('scroll', handleScroll);
- 防抖使用场景
- 输入框实时搜索
- 窗口大小调整
- 表单校验
- 节流使用场景
- 滚动事件
- 窗口大小调整
- 鼠标移动
JS闭包会导致内存泄漏,内存泄漏是什么,怎么解决
内存泄漏是指程序在运行工程中,未能释放已分配的内存,导致可用内存逐渐减少,最终可能导致程序性能下降或崩溃。
- 引用未释放
- 全局变量
- 事件监听器未移除
- 闭包
function createClosure(){let largeArray = new Array(1000).fill("*")return function(){console.log(largeArray)}
}
const closureFunc = createClosure()
// largeArray被闭包引用,即使函数执行完毕,但还是存在于内存中,导致内存无法被回收。
- 解决内存泄漏
- 避免不必要的全局变量
- 及时清理引用
- 移除事件监听器
- 使用WeakMap和WeakSet
- 监控内存使用
什么是原型和原型链
- 原型(prototype)
原型是一个对象,作为其他对象的模板。每个JavaScript对象都有一个内部属性[[prototype]]
,指向其原型对象。
通过原型,子对象可以访问父对象的属性和方法。
function Person(name){this.name = name;
}Person.prototype.greet = function(){console.log(`name:${this.name}`)
}
const alice = new Person('Alex')
alice.greet()
- 原型链
- 原型链:有多个对象通过其原型相互连接而形成的链式结构,当访问一个对象的属性时,JavaScript会首先查找该对象的属性,如果找不到则会沿着原型链向上查找。
- 查找顺序:如果对象A的属性在其自身中不存在,JavaScript会查找其原型对象B的属性,如果B中也没有,再查找B的原型 ,依次类推,直到找到属性或达到原型链的顶端
const animal = {eats: true
};const rabbit = Object.create(animal);
rabbit.hops = true;console.log(rabbit.eats); // 输出: true
console.log(rabbit.hops); // 输出: true
console.log(rabbit.__proto__ === animal); // 输出: true
JS实现继承的方式
- 原型继承
通过将一个对象的原型设置为另外一个对象来实现继承。
function Parent() {this.name = 'Parent';
}Parent.prototype.sayHello = function() {console.log(`Hello from ${this.name}`);
};function Child() {this.name = 'Child';
}// 设置Child的原型为Parent的实例
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;const child = new Child();
child.sayHello(); // 输出: Hello from Child
- 构造函数继承
在子类的构造函数中调用父类构造函数,以继承父类的属性
function Parent() {this.name = 'Parent';
}function Child() {Parent.call(this); // 调用父类构造函数this.name = 'Child';
}const child = new Child();
console.log(child.name); // 输出: Child
- 组合继承
结合原型继承和构造函数继承的优点,既能继承父类的属性,也能继承父类的方法。
function Parent() {this.name = 'Parent';
}Parent.prototype.sayHello = function() {console.log(`Hello from ${this.name}`);
};function Child() {Parent.call(this); // 调用父类构造函数
}// 设置Child的原型为Parent的实例
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;const child = new Child();
child.sayHello(); // 输出: Hello from Child
- 类继承(ES6)
使用ES6的类语法实现继承,语法更简介和直观
class Parent {constructor() {this.name = 'Parent';}sayHello() {console.log(`Hello from ${this.name}`);}
}class Child extends Parent {constructor() {super(); // 调用父类构造函数this.name = 'Child';}
}const child = new Child();
child.sayHello(); // 输出: Hello from Child
- 寄生式继承
在原型继承的基础上,创建一个新的对象,并在其上添加新的方法
function Parent() {this.name = 'Parent';
}Parent.prototype.sayHello = function() {console.log(`Hello from ${this.name}`);
};function createChild(parent) {const child = Object.create(parent);child.sayGoodbye = function() {console.log(`Goodbye from ${this.name}`);};return child;
}const child = createChild(new Parent());
child.sayGoodbye(); // 输出: Goodbye from Parent
- 总结
- 原型继承:简单,但可能导致属性共享的问题。
- 构造函数继承:只继承属性,无法继承方法。
- 组合继承:结合两者优点,是常用的继承方式。
- 类继承(ES6):语法简单,易于理解。
- 寄生式继承:适合创建具有特定功能的对象。
new 操作符做了什么
- 创建一个空对象
- 将对象的原型指向构造函数的原型
- 将空对象作为构造函数的上下文(改变this指向)
- 对构造函数有返回值的处理判断
function Fun(age,name){this.age = age;this.name = name;
}
function create(fn,...args){// 1、创建一个空对象const obj = {};// 2、将空对象的原型指向构造函数的原型Object.setPrototypeOf(obj,fn.prototype)// 3、将空对象作为构造函数的上下文(改变this指向)const res = fn.apply(obj,args) // 4、对构造函数有返回值的处理判断return res instanceof Object ? res : obj;
}
console.log(create(Fun,12,"alex"))
JS中this指向
- 全局上下文中
在全局上下文中,this
指向全局对象。在浏览器中,这个对象是window
- 函数调用
- 严格模式下:在严格模式下,
this
是undefined
- 非严格模式下:在普通函数中,
this
指向全局对象
- 严格模式下:在严格模式下,
function show(){console.log(this)
}
// 在非严格模式下输出:window,在严格模式下输出:undefined
show()
- 对象方法
当this
在对象的方法中使用时,指向调用该方法的对象。
const obj = {name:'Alex',greet:function(){console.log(`${this.name}`)}
}
- 构造函数
在构造函数中,this
指向新创建的实例对象。
function Person(name){this.name = name;
}
const p = new Person("Alex")
console.log(p.name)
- 箭头函数
箭头函数不会创建自己的this
,而是从外部作用域继承this
的值。这使得箭头函数在处理回调时非常有用。
const obj = {name:"Alex",greet:function(){const inner = () =>{console.log(`${this.name}`)}inner();}
}
obj.greet();
- 事件处理
在事件处理程序中,this
通常执行触发事件的元素。
const button = document.querySelector("button")
button.addEventListener('click',function(){console.log(this)
})
call apply bind区别
在javaScript中,call、apply和bind是用来改变函数执行时的上下文(即this的指向)的方法,它们主要区别在于传入参数的方式和返回值。
- call方法
call 方法允许你调用一个函数,同时也可以指定函数内部的this
指向,并且可以传入单个或者多个参数。
语法:function(thisArg,arg1,arg2,...)
thisArg 为函数执行时this
的值,后面的参数是传给函数的参数列表。
call方法会立即执行
function introduce(greeting, age, location) {console.log(`${greeting}, my name is ${this.name}. I am ${age} years old and I live in ${location}.`);
}const person = { name: 'Alice' };// 使用 call() 传入多个参数
introduce.call(person, 'Hello', 30, 'New York');
// 输出: Hello, my name is Alice. I am 30 years old and I live in New York.
- apply方法
apply和call作用相同,不同之处在于传入参数的方式。
语法:function.apply(thisArg,[argsArray]
thisArg为函数执行时this
的值,argsArray是一个数组,包含传给函数的参数。
apply 方法会立即执行函数。
function introduce(greeting, age, location) {console.log(`${greeting}, my name is ${this.name}. I am ${age} years old and I live in ${location}.`);
}const person = { name: 'Bob' };// 使用 apply() 传入多个参数
introduce.apply(person, ['Hi', 25, 'Los Angeles']);
// 输出: Hi, my name is Bob. I am 25 years old and I live in Los Angeles.
- bind方法
bind方法会创建一个新的函数,其中this
的值被绑定在bind的第一个参数上。
语法:function.bind(thisArg,arg1,arg2,...)
thisArg 为函数执行时this的值,后面的参数是被绑定的参数。
bind方法不会立即执行函数,而是返回一个新的函数。
function introduce(greeting, age, location) {console.log(`${greeting}, my name is ${this.name}. I am ${age} years old and I live in ${location}.`);
}const person = { name: 'Charlie' };// 使用 bind() 预设多个参数
const boundIntroduce = introduce.bind(person, 'Hello', 28);// 调用新的函数
boundIntroduce('New York');
// 输出: Hello, my name is Charlie. I am 28 years old and I live in New York.
深拷贝和浅拷贝的区别,常见的浅拷贝,实现一个深拷贝
浅拷贝
浅拷贝复制引用类型时,只复制引用的值
- Object.assign()
const o1 = {a:1,b:"alex",c:{d:2}
}
const shallowCopy = Object.assign({},o1)
- 展开运算符
const obj2 = { a: 1, b: { c: 2 } };
const shallowCopy2 = { ...obj2 };
shallowCopy2.b.c = 3; // 修改深层属性
console.log(obj2.b.c); // 输出: 3 (原对象也被影响)
深拷贝
复制对象引用类想需要复制其本身。
function deepClone(obj) {// 处理基本数据类型和 nullif (obj === null || typeof obj !== 'object') {return obj;}// 创建一个新对象或数组const copy = Array.isArray(obj) ? [] : {};// 递归复制每个属性for (const key in obj) {if (obj.hasOwnProperty(key)) {copy[key] = deepClone(obj[key]);}}return copy;
}// 示例
const original = { a: 1, b: { c: 2 } };
const deepCopied = deepClone(original);
deepCopied.b.c = 3;console.log(original.b.c); // 输出: 2 (原对象未被影响)
console.log(deepCopied.b.c); // 输出: 3
事件委托是什么
事件委托:是一种基于事件冒泡机制的JavaScript事件处理技术,允许将事件处理程序绑定到一个父元素上,而不是直接绑定到每个子元素上,这种技术可以提高性能,简化代码并支持动态内容。
- 工作原理
- 事件冒泡
当一个事件在某个元素上被触发时,该事件会从目标元素向上冒泡到其父元素上,直到达到文档根元素。这使得父元素可以捕获子元素的事件。 - 绑定到父元素
通过将事件处理程序绑定到父元素,可以在该父元素的任意子元素上触发事件,而不需要为每个子元素单独绑定事件处理程序。
- 事件冒泡
<ul id="item-1"><li>项目-1</li><li>项目-2</li><li>项目-3</li><li>项目-4</li>
<ul>
<script>const listItem = document.getElementById("item-1")listItem.addEventListener("click",function(event){if(event.tagName === "LI"){console.log("点击了 ===>",event.target.textContent)}})
</script>
事件循环
事件循环:Event Loop 是JavaScript的核心概念之一,它使得JavaScript能够在单线程环境中有效地处理异步操作。
- JavaScript的执行模型
JavaScript是单线程的,这意味着它在任何时刻只能执行一个操作,为了处理异步操作(如网络请求、定时器等),JavaScript采用了事件循环机制。 - 执行栈(call Stack)
- 执行栈是一个后进先出(LIFO)的数据结构,负责管理函数的执行。
- 当一个函数被调用时,它会被推入执行栈;当函数执行完成时,它会从栈中弹出。
- 任务队列(Task Queue)
- 任务队列用于存储待处理的异步任务,如事件处理程序、网络请求的回调等。
- 当主线程空闲时,事件循环会从任务队列中取出任务并将其推入执行栈。
- 微任务与宏任务
- 宏任务(Macro Tasks):包含
setTimeout
、setInterval
、I/O操作等。 - 微任务(Micro Tasks):包括
promise
中then
、catch
、finally
等回调。
微任务的优先级高于宏任务,事件循环每次都需先执行微任务队列。
- 宏任务(Macro Tasks):包含
- 工作流程
- 检查执行栈:事件循环首先检查执行栈是否为空。
- 处理微任务:如果执行栈为空,事件循环会从微任务队列中取出所有微任务并执行,直到微任务队列为空。
- 处理宏任务:完成微任务后,事件循环会从宏任务对列中取出第一个宏任务并将其推出执行栈。
- 重复执行以上操作。
Promise实现原理
- 设计模式:观察者模式
- 调用流程
- Promise的构造方法接受一个
executor()
,在new Promise()就会立即执行这个executor回调; executor()
内部的异步任务被放入宏/微任务队列,等待执行;then()
被执行,收集成功/失败回调,放入成功/失败队列;executor()
的异步任务被执行,触发resolve/reject
,从成功或者失败的对列中取出回调依次执行。- 宏任务是由宿主机(浏览器、Node)发起的,而微任务由JS自身发起
- Promise的构造方法接受一个
- Promise A+规范
- Promise本质是一个状态机,且状态只能有以下三种:
Pending(等待态)
、Fulfilled(执行态)
、Rejected(拒绝态)
,状态变更是单向的,只能从Pending -> Fulfilled 或 Pending -> Rejected,状态变更不可逆;
- Promise本质是一个状态机,且状态只能有以下三种:
Promise和async await 的区别
- Promise
- 是一个代表异步操作最终完成(或失败)及其结果值的对象。
- 可以通过
.then()
和.catch()
方法来处理成功和失败的结果。
- async和await
- 是基于Promise的语法糖,使得异步代码看起来像同步代码;
- 使用
async
声明一个异步函数,在该函数内部可以使用await
来等待Promise的结果; async
函数总是返回一个Promise,即时函数内部没有显式返回Promise;
await
只能在async
函数内部使用- 当JavaScript引擎遇到
await
时,它会暂停当前async
函数的执行,直到await
后面的Promise被解决(fulfilled)或拒绝(rejected) - 在等待期间,JavaScript事件循环会继续执行其他宏任务和微任务,这意味着其他代码仍然可以运行,而不会阻塞主线程;
- 当JavaScript引擎遇到
页面渲染流程
-
解析HTML
解析HTML,生成DOM树结构, 首先会拿到html整体的字符串,进行标记化- 为什么要标记化?
因为浏览器是不能识别这些字符串需要进行标记化处理,本质上就是把这段字符串的html标签类型的拆分,因为是一长串的字符串需要进行解析成node节点,所以会进行标记化,方便浏览器根据标记的标签进行DOM树渲染。
- 为什么要标记化?
-
处理CSS 和 JavaScript标签
- 浏览器在解析的时候会启动一个预解析线程,这个线程主要做的就是扫描外部的style和JS文件,进行异步下载解析。
- 这个线程主要做的就是扫描外部的style和js文件进行异步下载解析,解析完成后如果渲染主线程没有完成会直接把解析的结果CSSOM添加到主线程中style和link标签的解析和下载都是在预解析线程中进行的。
- CSS下载失败的情况下也不会影响主线程的进度,css标记化也会形成一颗CSSOM树。
- JS文件为什么会阻塞HTML解析
当主线程解析HTML遇到<script>
标签(无async/defer属性)时,会停止HTML解析,下载并执行该脚本。因为JavaScript可能通过document.write等方式修改DOM结构,浏览器必须确保脚本执行时后续DOM尚未构建,从而避免竞态条件。执行完成后,主线程继续解析HTML。- async 异步下载,下载完成后立即执行(仍然可能存在阻塞解析)
- defer 异步下载,延迟DOM解析完成后执行
-
样式计算
- CSSOM构建阶段
- 浏览器解析所有CSS规则(内联/外联/继承),生成CSSOM树状结构
- 继承机制:如
font-size
会从父元素继承; - 层叠规则:通过优先级算法,确定最终样式;
- 默认值填充
- 渲染树合成
- 将DOM树与CSSOM树合并生成Render Tree
- 过滤机制
- 移除
display:none
的节点 - 保留
visibility:hidden
等影响布局但不可见的节点
- 移除
- 样式重计算触发条件
- DOM结构变化(增删节点)
- CSSOM(动态样式操作)
- 窗口缩放或设备方向变化
- CSSOM构建阶段
-
布局
- 当浏览器解析HTML和样式计算后已经知道每个DOM节点所附带的样式了,但是还不足以呈现在页面上,因为我们还缺少每个元素在页面上的位置布局
- 主线程会递归遍历完刚刚构建好的DOM树,由于DOM树上挂载了计算样式,可以计算布局树
- 布局树上的每个节点都挂载了它在页面上的位置也就是X、Y的坐标以及盒子模型的大小等集合信息
-
分层
- 主线程会遍历整个布局树生成一个**层次树(Layer Tree)**确定元素需要放在那一层;
- 滚动条,堆叠上下文,transform,opacity等样式都会影响分层的结果,也可以通过z-index,will-Change属性对其进行分层。
-
生成绘制指令
- 分层结束之后,就开始绘制指令的生成了 主线程会给每一层单独生成一个绘制指令集,用于生成该层的图像生成
- 只生成绘制的指令,还没有执行只是生成了指令,渲染主线程基本已经完结了,接下来的工作交给合成线程
-
分块
- 合成线程会对每个图层进行一些分块,划分为更小的区域
- 当完成分块之后,合成线程就不会和主线程单独进行了,而是会申请更多的线程同时去完成分块内的工作
-
光珊化
- 简单来说,确认每个像素点的rbg颜色信息,光珊化的操作不是由合成线程来做的,而是合成线程交给GPU进程,GPU进程会以极高的速度完成光珊化的操作,GPU是专门做图形化处理工作,会开启多个线程进行绘制。
-
绘制
- 所有的图形被光珊化之后,合成线程就拿到了每个图层以及每个块的位置信息,从而生成一个个的**【指引】**信息,指引会标识出每个图块应该渲染到屏幕的位置信息,标签考虑到旋转、缩放等变形效果都发生在合成线程中。
重排和重绘
- 重排(回流)
触发重排:当我们的渲染树发生元素的尺寸,结构或者属性发生变化时,浏览器会重新解析dom树和css树。 - 重绘
触发重绘:当页面中某些元素的样式发生变化,当不会影响其在文档流中的位置时,浏览器就会对元素进行绘制。
sort原理
JavaScript 中的 sort() 方法是用于对数组元素进行排序的内置函数。
- 默认情况下,sort() 会将数组元素转换为字符串,然后按照 Unicode 码点顺序进行排序。
- 对于小型数组,可能使用插入排序(Insertion Sort)等简单算法。
- 对于大型数组,通常使用快速排序(QuickSort)或归并排序(MergeSort)等更高效的算法。
- sort() 会直接修改原数组,而不是返回一个新数组。
- 如果数组包含 undefined 元素,它们会被排到数组末尾。
localStorage
、sessionStorage
和 cookie
区别
localStorage
、sessionStorage
和 cookie
是前端开发中常用的三种客户端存储方式,它们各有特点和适用场景。以下是它们的详细区别:
-
- 存储位置
localStorage
:存储在浏览器中,数据持久化,即使关闭浏览器也不会丢失。sessionStorage
:存储在浏览器中,但数据仅在当前会话期间有效,关闭浏览器或标签页后数据会被清除。cookie
:存储在浏览器中,数据可以设置过期时间,过期后会被清除。
-
- 数据有效期
localStorage
:永久有效,除非手动清除或通过代码删除。sessionStorage
:仅在当前会话期间有效,关闭浏览器或标签页后数据丢失。cookie
:可以设置过期时间,过期后自动删除;如果没有设置过期时间,则默认为会话级别(关闭浏览器后删除)。
-
- 存储大小
localStorage
:通常为 5MB 左右(不同浏览器可能略有差异)。sessionStorage
:通常为 5MB 左右(与localStorage
相同)。cookie
:每个域名下最多存储 4KB 数据,且每个域名下的 cookie 总数有限制(通常为 20 个左右)。
-
- 数据共享范围
localStorage
:在同一浏览器的同一域名下,所有页面共享数据。sessionStorage
:仅在同一个标签页或窗口内共享数据,不同标签页之间不共享。cookie
:在同一浏览器的同一域名下,所有页面共享数据,且可以通过设置domain
和path
控制共享范围。
-
- 与服务器的交互
localStorage
:数据不会自动发送到服务器,仅用于客户端存储。sessionStorage
:数据不会自动发送到服务器,仅用于客户端存储。cookie
:每次 HTTP 请求时,浏览器会自动将 cookie 数据发送到服务器(除非设置为HttpOnly
或Secure
)。
-
- 适用场景
localStorage
:适合存储需要长期保存的数据,如用户偏好设置、离线数据等。sessionStorage
:适合存储临时数据,如表单数据、页面状态等,仅在当前会话期间有效。cookie
:适合存储与服务器交互的数据,如用户身份验证信息、会话 ID 等。
-
- 安全性
localStorage
和sessionStorage
:数据仅存储在客户端,容易受到 XSS(跨站脚本攻击)的影响。cookie
:可以通过设置HttpOnly
、Secure
和SameSite
等属性增强安全性,防止 XSS 和 CSRF(跨站请求伪造)攻击。
- 总结
特性 | localStorage | sessionStorage | cookie |
---|---|---|---|
存储位置 | 浏览器 | 浏览器 | 浏览器 |
数据有效期 | 永久 | 会话级别 | 可设置过期时间 |
存储大小 | 5MB 左右 | 5MB 左右 | 4KB 左右 |
数据共享范围 | 同域名下所有页面 | 同标签页内 | 同域名下所有页面 |
与服务器交互 | 不自动发送 | 不自动发送 | 自动发送 |
适用场景 | 长期存储 | 临时存储 | 服务器交互 |
安全性 | 较低 | 较低 | 较高(可增强) |
null和undefined的区别
- 作者设计js的时候先设计出
null
最初设计js的时候借鉴了java语言。 null
会被隐式转换为0,很不容易发现错误。- 先有
null
后有undefined
, - 具体区别:null是表示一个“无”的对象(空指针),转换数值时为0,undefined转换数值时为NaN。
==
和===
的区别
==
:比较的是值
比较时会隐式转换,通过valueOf
转换
Object.prototype.valueOf = function(){}
===
:除了比较值,还比较类型
js的数据类型
基本数据类型:
- Number
- String
- Boolean
- Undefined
- Null:
- Symbol:表示唯一标识符,通常用于对象属性的键值。
- BigInt:表示任意精度的整数,常用于处理大范围的数值。
引用数据类型:Object
延迟加载JS有哪些方式?
- 在
<script>
标签中添加defer属性,可以让脚本在文档解析完成后再执行。
<script src="a.js" defer></script>
async
属性让脚本异步加载,并在加载完成后立即执行,不会阻塞文档的解析。
<script src="b.js" async></script>
- 动态插入脚本
可以使用JavaScript动态创建<scrip>
标签插入文档中,从而实现延迟加载。
const script = document.createElement('script')
script.src = 'a.js'
document.body.appendChild(script)
- 使用window.onload
在window.onload
事件中加载脚本,确保所有内容都加载完成后再执行。
CSS 篇
相关文章:
高级前端题库
前端题库 JS篇 如何理解作用域和作用域链 作用域 作用域就是变量或函数在其内能够被访问的“可见区域” 全局作用域局部作用域 作用域链 当在某个作用域中尝试访问一个变量时,JS引擎会从当前作用域开始,沿着作用域链向上逐级开始查找,直到…...
博途 TIA Portal之1200做主站与汇川EASY的TCP通讯
前言,虽然已经做了几篇关于TCP通讯的文章,但是不同的PLC之间的配合可能不同,下面将演示这种差异。 关于汇川EASY做从站的配置请参见下方链接文章:汇川EASY系列之以太网通讯(套接字socket做从站)_汇川以太网tcp套接字fb块-CSDN博客 1、硬件准备: 1200PLC,汇川EASY320…...
在conda虚拟环境安装GIT并且克隆github上项目指南(解决443问题)
此次笔记记录自己在conda虚拟环境安装git,同时克隆github项目,并且解决了git的443问题。 如有不妥欢迎各位大佬批评指正。 首先默认你已经安装了anaconda。 代开命令提示行 配置环境 #首先创建虚拟环境 conda create -n git_env python3.8 #激活虚拟环…...
JavaWeb遇到的问题汇总
问题一:(键值对最后一项没有逗号) 在JSON字符串转自定义对象和自定义对象转JSON字符串时: 如图所示:若忘记删除键值对的最后一项没有逗号时,则下一句转换不会生效,应该删除最后一项的逗号。 解…...
Stable Diffusion + Contronet,调参实现LPIPS最优(带生成效果+指标对比)——项目学习记录
目录 前言 一、数据集:图像文本,部分选取于DeepFashion 二、优化一,img2img 三、优化二,微调sd参数 四、优化三,dreamshaper优化 五、优化四,sdv1.5contronet 六、问题探索历程 1. 从 SDXL 到轻量化模…...
【“星睿O6”AI PC开发套件评测】在O6开发板使用gemma-2b测试CPU性能
前提条件: x64 Linux 主机:安装CMake 和 arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-linux-gnu radxa O6主机 1.从 Kaggle 获取模型权重和分词器 Gemma 3 2B 模型文件:访问 Kaggle 上的 Gemma 模型页面 https://www.kaggle.com/mode…...
数学知识——矩阵乘法
使用矩阵快速幂优化递推问题 对于一个递推问题,如递推式的每一项系数都为常数,我们可以使用矩阵快速幂来对算法进行优化。 一般形式为: F n F 1 A n − 1 F_nF_1A^{n-1} FnF1An−1 由于递推式的每一项系数都为常数,因此对…...
3DMax中模型解组
1、从网上下载下来的模型是一个整体,需要解开查看每个样式 2、解开组...
链路聚合+vrrp
1.链路聚合 作用注意事项将多个物理接口(线路)逻辑上绑定在一起形成一条逻辑链路,起到叠加带宽的作用1.聚合接口必须转发速率一致。2.聚合设备两端必须一致 配置命令 方法一 [Huawei]interface Eth-Trunk 0----先创建聚合接口,…...
0 std::process::Command 介绍
std::process::Command 是 Rust 标准库中用于创建和配置子进程的主要类型。它允许你启动新的进程、设置其参数和环境变量、重定向输入/输出等。 基本用法 use std::process::Command;let output Command::new("echo").arg("Hello, world!").output().ex…...
Android 中Intent 相关问题
在回答 Intent 问题时,清晰区分其 定义、类型 和 应用场景。以下是的回答策略: 一、Intent 的核心定义 Intent 是 Android 系统中的 消息传递对象,主要用于三大场景: 2. 隐式 Intent(Implicit Intent) 三、…...
【Docker】Docker Desktop镜像存储路径设置方法
在 Docker Desktop 中设置镜像存储路径(即下载的镜像文件存放位置)取决于你的操作系统。以下是不同系统下的设置方法: Windows 系统 完全卸载后重新安装指定路径(Docker Desktop for Windows 默认使用 C:\ProgramData\Docker&…...
Spring Boot 3.x 中 WebClient 全面详解及示例
Spring Boot 3.x 中 WebClient 全面详解及示例 1. WebClient 简介 定义:Spring 5 引入的响应式 HTTP 客户端,用于替代 RestTemplate(已弃用),支持异步非阻塞的 HTTP 请求。核心特性: 支持所有 HTTP 方法&a…...
将图片按照指定大小批量进行裁剪(可设置步长_python)
将图片按照指定大小批量进行裁剪(可设置步长_python) import os from PIL import Image# 设置更高的图像大小限制,禁用解压炸弹检查 Image.MAX_IMAGE_PIXELS None # 禁用解压炸弹检查def crop_image(image_path, block_size(640, 640), step_size(340, 340)):# 打…...
设计模式 --- 原型模式
原型模式是创建型模式的一种,是在一个原型的基础上,建立一致的复制对象的方式。这个原型通常是我们在应用程序生命周期中需要创建多次的一个典型对象。为了避免初始化新对象潜在的性能开销,我们可以使用原型模式来建立一个非常类似于复印机的…...
工作经验记录
坑 部门例会上:跨级暴露问题.部门例会上:说话没有条理,周报写得好,但是表达效果不同.领导直接要求的任务没有当时推进:需考虑GTD清单.不要马后炮领导签字要按顺序 会议上 发言有条理问题不要越级暴露不要强调过程 对同事 对领导 领导同意的文件最好当日通过. 对供应商 不…...
Unity中基于2.5D的碰撞系统
在2.5D游戏中实现精确的碰撞检测是一个关键挑战,因为我们需要在视觉上有深度感的同时保持游戏逻辑的准确性。下面我将详细解析2.5D碰撞系统的实现方法。 1. 2.5D碰撞的核心问题 1.1 Z轴深度与碰撞的关系 视觉表现:物体通过Y轴位置影响Z轴排序ÿ…...
设计模式-命令模式详解
命令模式详解及真实场景解决方案 模式定义 命令模式是一种行为设计模式,将请求封装为独立对象,包含执行操作所需的所有信息。通过这种方式,可以实现请求的参数化、队列管理、撤销/重做等高级功能,同时解耦请求发送者与接收者。 …...
基于Python(Django)+SQLite 实现(Web) 点菜管理系统
点菜管理系统 课程设计任务与要求 1、任务 题目:点菜管理信息系统 问题描述: 随着网络的迅速发展,越来越多的人开始接受甚至时依赖了网络营业的这种交易形式,传统的点菜模式不仅浪费时间,效率低下,而且…...
泰鸿万立上市:加强产品规划和前瞻性研发 打造优质汽车零部件制造商
4月9日,浙江泰鸿万立科技股份有限公司(股票简称“泰鸿万立”,股票代码“603210”)正式登陆上交所主板。 招股书显示,泰鸿万立主营业务为汽车结构件、功能件的研发、生产与销售。经过十余年发展,公司拥有了…...
Charles的安装和使用教程
Charles抓包工具与Sniff Master在Windows上的安装与使用指南 1. Charles抓包工具安装 1.1 下载Charles 进入Charles官网(https://www.charlesproxy.com/download/)下载最新版本的安装包 1.2 安装与激活 正常安装后,打开会提示试用版30天限制进入授权码生成页面…...
论文阅读笔记:Adaptive Multi-Modal Cross-Entropy Loss for Stereo Matching
论文阅读笔记:Adaptive Multi-Modal Cross-Entropy Loss for Stereo Matching 1 背景2 创新点3 方法4 模块4.1 基础和问题描述4.2 自适应多模态概率模型4.3 主模态视差估计器 5 效果6 结论 1 背景 尽管深度学习在立体匹配方面取得了巨大成功,但恢复准确…...
JavaScript学习教程,从入门到精通,JavaScript 运算符及语法知识点详解(8)
JavaScript 运算符及语法知识点详解 一、JavaScript 运算符 1. 算术运算符 用于执行数学运算: 加法- 减法* 乘法/ 除法% 取模(余数) 递增-- 递减** 幂运算(ES6) let a 10, b 3; console.log(a b); // 13 conso…...
聊聊Spring AI的ETL Pipeline
序 本文主要研究一下Spring AI的ETL Pipeline DocumentReader org/springframework/ai/document/DocumentReader.java public interface DocumentReader extends Supplier<List<Document>> {default List<Document> read() {return get();}}有TextReader…...
spark架构和RDD相关概念
运行架构: Spark采用master - slave结构,Driver作为master负责作业任务调度,Executor作为slave负责实际执行任务。 核心组件 Driver:执行Spark任务的main方法,将用户程序转化为作业,在Executor间调度任务&…...
Cloud Kernel SIG 季度动态:发布ANCK 6.6-003版本,支持一测多证
Cloud Kernel SIG(Special Interest Group):支撑龙蜥内核版本的研发、发布和服务,提供生产可用的高性价比内核产品。 01 SIG 整体进展 发布 ANCK 6.6-003 版本。 一测多证流程建立。 OOT 驱动基线更新。 海光平台适配进展更新…...
【11】数据结构之基于线性表的查找算法
目录标题 平均查找长度ASL(Average Search Length)顺序表查找法折半查找法索引顺序查找法 平均查找长度ASL(Average Search Length) 定义:为确定元素在列表中的位置,需要和给定值进行比较的关键字个数的期望值,称之为查找算法成功时的平均查…...
铼赛智能Edge mini斩获2025法国设计大奖 | 重新定义数字化齿科美学
铼赛智能(RAYSHAPE)革命性新品——椅旁3D打印机Edge mini荣获2025年法国设计奖(FRENCH DESIGN AWARDS,简称FDA)产品设计类大奖。作为全球工业设计领域最具影响力的奖项之一,这一殊荣不仅是对产品极简美学的…...
成为一种国家战略范畴的新基建的智慧园区开源了
智慧园区场景视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界…...
Codeforces Round 1016 (Div. 3)题解
题目地址 https://codeforces.com/contest/2093 锐评 在所有题意都理解正确的情况下,整体难度不算太难。但是偏偏存在F这么恶心的题意,样例都不带解释一下的,根本看不懂题。D题也恶心,在于递归过程的拆分,需要点数学…...
安全理念和安全产品发展史
从安全理念的发展历史来看,技术与产品的演进始终围绕 “威胁对抗” 与 “业务适配” 两大核心展开。以下从七个关键阶段解析安全技术与产品的发展脉络,并结合最新实践与未来趋势提供深度洞察: 一、密码学奠基阶段(1970s 前) 安全理念:以 “信息保密” 为核心,防御手段…...
【深度学习】Downstream Model:预训练模型的下游应用与微调技术
Downstream Model:预训练模型的下游应用与微调技术 文章目录 Downstream Model:预训练模型的下游应用与微调技术1 什么是Downstream Model(下游模型)2 预训练模型与下游任务的关系3 微调技术与迁移学习微调的必要性高效迁移学习参…...
每日算法-250409
这是我今天的算法学习记录。 2187. 完成旅途的最少时间 题目描述 思路 二分查找 解题过程 为什么可以使用二分查找? 问题的关键在于寻找一个最小的时间 t,使得在时间 t 内所有公交车完成的总旅途次数 sum 大于等于 totalTrips。 我们可以观察到时间的单…...
【CSS 选择器组合规则详解】
基础选择器组合 空格:后代选择器 > 直接子元素选择器 . 类选择器 : 伪类选择器 多类选择器 .class1.class2 :多类组合 .class1 .class2 :类的所有后代 .class1 > .class2 :类的子元素特殊选择器 :nth-child() :nth-of-…...
手机静态ip地址怎么获取?方法与解析
而在某些特定情境下,我们可能需要为手机设置一个静态IP地址。本文将详细介绍手机静态IP地址详解及获取方法 一、什么是静态IP地址? 静态IP:由用户手动设置的固定IP地址,不会因网络重启或设备重连而改变。 动态IP:由路…...
NumPy对二维矩阵中的每个元素进行加减乘除和对数运算
使用NumPy对二维矩阵中的每个元素进行加减乘除和对数运算的方法如下: 1. 加减乘除运算 对每个元素进行标量运算,可直接使用算术运算符。 示例代码: import numpy as nparr np.array([[1, 2], [3, 4]])# 加法 result_add arr 5 print(&…...
基于C8051F340单片机的精确定时1S的C程序
一、前言 C8051F340单片的定时器2 是一个 16 位的计数器/定时器,由两个 8 位的 SFR 组成:TMR2L(低字节)和TMR2H(高字节)。定时器 2 可以工作在 16 位自动重装载方式、8 位自动重装载方式(两个 …...
提升Windows安全的一些措施
由简单到复杂,仅供参考 一、杀毒软件: 1、杀毒能力: https://haokan.hao123.com/v?vid3883775443252827335&pdhaokan_share 2、使用注意: 一台主机只安装一个杀毒软件就可以了 杀毒软件会误报,造成正常文件…...
中科岩创基坑自动化监测解决方案
1.行业现状 城市基坑开挖具有施工风险高、施工难度大等特点。由于地下土体性质、荷载条件、施工环境的复杂性,单根据地质勘察资料和室内土工试验参数来确定设计和施工方案,往往含有许多不确定因素,对在施工过程中引发的土体性状、环境、邻近建…...
Elasticsearch 系列专题 - 第二篇:数据建模与索引管理
在掌握了 Elasticsearch 的基本概念和操作后,本篇将重点介绍如何设计和管理索引,以及如何高效地导入和维护数据。这对于构建一个高效、可扩展的搜索系统至关重要。 1. 索引设计 1.1 如何选择合适的索引结构 索引是 Elasticsearch 的核心,设计时需考虑以下因素: 数据用途:…...
解决缓存穿透的布隆过滤器与布谷鸟过滤器:谁更适合你的应用场景?
目录 一、布隆过滤器:高效的空间节省者 1.1 布隆过滤器是什么? 1.2 工作原理 1.3 优点 1.4 缺点 1.5 适用场景 二、布谷鸟过滤器:解决删除难题的创新者 2.1 布谷鸟过滤器是什么? 2.2 工作原理 2.3 优点 2.4 缺点 2.5 适用场景 三、…...
OpenHarmony子系统开发 - 调测工具(一)
OpenHarmony子系统开发 - 调测工具(一) 一、bytrace使用指导 简介 bytrace是开发人员用于追踪进程轨迹、分析性能的一种工具,主要对内核ftrace进行了封装和扩展,来支持用户态的打点。通过该工具可以打开想要查看的用户态和内核l…...
Qt中的鼠标事件
1.鼠标进入事件和鼠标离开事件 1.1添加新文件 1.2ui界面 拖出一个Label控件,修改frameShape为Box,使边框更明显 1.3代码实现 #ifndef MYLABEL_H #define MYLABEL_H#include <QLabel>class myLabel : public QLabel {Q_OBJECT public:explicit m…...
MySQL JOIN详解:INNER JOIN与LEFT JOIN的选择与应用
在数据库查询中,JOIN操作是最常用也最重要的操作之一。不同的JOIN类型会导致完全不同的查询结果,正确选择JOIN类型是编写高效、准确SQL查询的关键。本文将深入探讨INNER JOIN和LEFT JOIN的区别、应用场景以及常见问题。 一、JOIN基础概念 1. 什么是JOI…...
Flink 反压下的 TCP 流控制
1. 什么是 Flink 反压和 TCP 流控制? 反压(Backpressure)是什么? 反压是分布式流处理系统中一种自我调节机制。当下游处理数据的速度跟不上上游发送数据的速度时,反压会让上游放慢发送速度,以避免系统过载…...
山东大学软件学院项目实训开发日志(7)之测试前后端本地部署
基于队长搭建的springbootvue框架,在本地进行测试搭建。 在运行后端过程中,出现下图错误: 查找后发现这个问题出现在 Maven 项目的 pom.xml 文件中,显示找不到一些依赖项。所以在此进行最简单的重新加载项目得以解决,…...
YOLOv11训练中精准率召回率与mAP@0.5的动态变化分析
目标检测模型的训练过程涉及多个关键性能指标和损失函数的变化,这些数据能够直观反映模型的收敛速度、最终精度以及改进效果。本文旨在通过绘制YOLOv11模型在训练过程中的精准率(Precision)、召回率(Recall)、mAP0.5 、…...
Windows下ElasticSearch8.x的安装步骤
下载ElasticSearch:https://www.elastic.co/downloads/elasticsearch (我下载的是目前最新版8.17.4)解压ElasticSearch 进入到ElasticSearch的bin目录下双击elasticsearch.bat 弹出控制台并开始执行,在这一步会输出初始账号和密码…...
Leetcode hot100 (day 8,9)
爬楼梯 做法一:小斐波那契数列,只要注意记忆化递归即可 class Solution { public:int dp[50];int climbStairs(int n) {if(dp[n])return dp[n];if(n2){return dp[2]2;}if(n1){return dp[1]1;}//if(dp[n])return dp[n];return dp[n]climbStairs(n-1)clim…...
LinuxSocket套接字编程
1.介绍函数使用 1.创建套接字 int socket(int domain, int type, int protocol); domain:指定协议族,如AF_INET(IPv4)或AF_INET6(IPv6)。 type:指定套接字类型,如SOCK_DGRAM&#…...