面试题JS篇

目录

  • Js 基本数据类型有哪些
  • Ajax 如何使用
  • 如何判断一个数据是 NaN?
  • Js 中 null 与 undefined 区别
  • 闭包是什么?有什么特性?对页面会有什么影响
  • JS中模块化的方法
  • Js 中常见的内存泄漏
  • 什么是事件冒泡?
  • 如何阻止事件冒泡?
  • 事件委托是什么?如何确定事件源?
  • 对比Cookie、localStorage、sessionStorage的异同
  • ES6 新特性
  • for...of 和 for...in的区别
  • Let 与 var 与 const 的区别
  • 数组方法有哪些请简述
  • Json 如何新增/删除键值对
  • 改变函数内部 this 指针的指向函数(bind,apply,call 的区别)
  • 手写bind
  • window和document的关系?
  • 什么是面向对象请简述
  • 普通函数和构造函数的区别
  • 请简述原型/原型链/(原型)继承
  • JS 的 new 操作符做了哪些事情?
  • 如何实现继承?/ 请写出一个简单的类与继承
  • Promise 的理解
  • 介绍一下async/await
  • 我们用 Promise 来解决什么问题?
  • 一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
  • get 请求传参长度的误区
  • 说说前端中的事件流
  • 解释一下什么是 Event Loop
  • clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop 的区别?
  • 鼠标的位置
  • JS 拖拽功能的实现
  • JS的垃圾回收机制
    • 有哪些垃圾回收策略?
  • DOM VS BOM
  • JS 监听对象属性的改变
  • JS 怎么控制一次加载一张图片,加载完后再加载下一张
  • 深拷贝VS浅拷贝?
  • 实现 JS 中所有对象的深度克隆(包装对象,Date 对象,正则对象)
  • 能来讲讲 JS 的语言特性
  • 为什么会造成跨域/请简述同源策略?
  • 请输出三种减少页面加载时间的方式
  • 什么是 jsonp 工作原理是什么?他为什么不是真正的 ajax
  • 请掌握 2 种以上数组去重的方式
  • 箭头函数与普通函数的区别
  • 常见的 HTTP状态码
  • 预加载和懒加载的使用场景
  • Js 的函数节流和函数防抖的区别
  • 介绍一下js中的计时器

参考资料

Js 基本数据类型有哪些

7:string,number,boolean,null,undefined,object,symbol(ES6引入)

Ajax 如何使用

ajax是什么?
实现在 不刷新整个页面的情况下更新部分内容 的技术
与axios的区别?
ajax是原生的(浏览器提供的 XMLHttpRequest 对象来实现),axios是对原生的一个包装

一个完整的 AJAX 请求包括以下五个步骤:

  1. 创建 XMLHttpRequest 对象,var xhr = new XMLHttpRequest();
  2. 设置请求参数 xhr.open(“GET”, “https://example.com/api/data”, true);
  3. 设置回调函数
xhr.onreadystatechange = function() {if (xhr.readyState == 4 && xhr.status == 200) {// 处理服务器响应的逻辑console.log(xhr.responseText);}
};
  1. 发送请求 xhr.send();
  2. 更新页面

如何判断一个数据是 NaN?

  • isNaN()函数
  • 对字符串,这个函数会把字符串转为数字,产生误判
  • 解决:typeof value === ‘number’ && isNaN(value)

Js 中 null 与 undefined 区别

  • null:空值,主动赋值了一个空指针,可以用于清空对象引用;
  • und:声明了但没有赋值,表示缺少
  • Number(null) 的结果是 0。Number(undefined) 的结果是 NaN

闭包是什么?有什么特性?对页面会有什么影响

是什么
是一种语言特性:在一个函数作用于内部定义的函数,能够访问该作用域内的变量,当这个内部函数在其他地方被调用时,依然可以访问那个作用域的变量。
特点
1.函数嵌套函数。
2.函数内部可以引用外部的参数和变量。
3.内部函数所引用的参数和变量不会被垃圾回收机制回收。
优点
1.用于封装私有变量,隐藏细节,暴露接口
2.防止全局变量的滥用和污染
3.模块化,将一组相关的功能封装在一个单独的闭包中,使其具有独立的作用域,从而提高代码的可维护性和可重用性。
模块化示例
var module = (function() {var privateVariable = "I am private";return {publicMethod: function() {console.log(privateVariable);}};
})();module.publicMethod(); // 输出:I am private
缺点:
内存泄露:程序中已经不再需要使用的内存没有被正确释放或回收,导致系统的可用内存减少,最终可能影响系统的性能

JS中模块化的方法

  1. COMMONJS(node.js上,是一种服务器端的模块化规范)使用的 requiremodule.exports
    // 在模块中导出
    var privateVariable = "I am private";
    module.exports = {publicMethod: function() {console.log(privateVariable);}
    };// 在另一个文件中导入
    var myModule = require('./myModule');
    myModule.publicMethod();
    
  2. ES6模块(浏览器上的模块化规范):importexport
    // 在模块中导出
    const privateVariable = "I am private";
    export const publicMethod = function() {console.log(privateVariable);
    };// 在另一个文件中导入
    import { publicMethod } from './myModule';
    publicMethod();
    

Js 中常见的内存泄漏

  1. 未及时清理定时器:定时器如果没有被清理,将一直保持对回调函数的引用
  2. 未解绑事件监听:如果在DOM元素被移除之前没有解绑事件监听,那么事件处理函数将一直存在于内存中,导致内存泄漏。使用 removeEventListener 解绑事件。
  3. 大对象未及时释放:在不再需要使用大型数据对象时,手动释放或将其设置为 null。
  4. 代码中无意间、不经意间创建的全局变量
  5. 闭包未释放
function createClosure() {var data = new Array(10000); // 大型数据结构return function() {// 使用 dataconsole.log(data.length);};
}var closure = createClosure(); // 创建闭包// 在外部使用 closure,但未解除对 data 的引用
closure();// 假设不再需要使用 closure,但没有解除对闭包的引用
// 这将导致 data 一直存在于内存中,无法被垃圾回收

什么是事件冒泡?

事件会从触发事件的元素一直冒泡到最外层的祖先元素。
例如父子都有点击事件,点儿子,先儿子输出,后父亲输出。

如何阻止事件冒泡?

  1. stopPropagation
  2. preventDefault
e.addEventListener('click',function(event){event.stopPropagation()event.preventDefault()//或
})

事件委托是什么?如何确定事件源?

  • 利用冒泡
  • 将事件监听器添加到父元素上,减少了对每个子元素都添加监听器的工作量。
  • 使用 event.target 确定事件源

对比Cookie、localStorage、sessionStorage的异同

都是用于在客户端存储数据的机制

特性CookielocalStoragesessionStorage
存储容量小(通常4KB)通常 5MB通常 5MB
生命周期可设置过期时间永久存储,除非手动清除页面关闭后自动清除
发送到服务器每次请求都会将 Cookie 数据包含在请求头中,如果 Cookie 中包含大量数据,会导致更多的带宽消耗不会自动发送不会自动发送
作用域可设置作用域全域名共享单个页面共享
安全性非常低,可能被劫持低,但相对较安全低,但相对较安全
主要用途跨页面通信、认证信息本地存储,长期数据本地存储,会话级别数据

ES6 新特性

  1. let 和 const 声明:

    • 引入了 letconst 关键字,用于声明块级作用域的变量和常量。
  2. 箭头函数(Arrow Functions):

    • 提供了更简洁的函数声明语法,同时修复了传统函数中 this 关键字的一些问题。
  3. 模板字符串(Template Strings):

    • 使用反引号 `` 包裹字符串,支持多行字符串和变量插值。
  4. 解构赋值(Destructuring Assignment):

    • 允许通过模式匹配从数组或对象中提取值并赋给变量。
  5. 对象字面量的扩展:

    • 支持简写方法声明、计算属性名、以及 Object.assign 方法用于对象的浅复制。
  6. 类(Classes):

    • 引入了类的概念,提供了更简洁、面向对象的语法。
  7. Promise 对象:

    • 提供了更方便的异步编程模式,解决了回调地狱的问题。
  8. 模块化(Modules):

    • 引入了对模块的官方支持,允许将代码分割为多个文件,使项目更易维护和组织。
  9. 迭代器和生成器(Iterators and Generators):

    • 提供了迭代器协议和生成器函数,使遍历数据结构更加灵活和可控。
  10. Symbol 数据类型:

    • 引入了一种新的基本数据类型 Symbol,用于创建唯一的标识符,通常用于对象属性的键名。const mySymbol = Symbol(‘key’); myObject[mySymbol] = ‘value’;
  11. Set 和 Map 数据结构:

    • 引入了 SetMap,分别用于存储唯一值和键值对,提供了更高效的数据存储和查找。
  12. 默认参数值:

    • 允许在函数声明时为参数提供默认值。
  13. Rest 和 Spread 操作符:

    • ... 用于表示剩余参数(Rest),或将数组或对象展开为参数序列(Spread)。

for…of 和 for…in的区别

  • for…in 循环用于遍历对象的可枚举属性,迭代的是对象的键名(属性名)
  • for…of 循环是用于遍历可迭代对象(如数组、字符串、Set、Map 等),迭代的是对象的,但是for-of不会遍历普通对象!普通对象默认不可迭代。

Let 与 var 与 const 的区别

特性varletconst
声明提升(声明提到作用域顶部)是(只提升声明 赋值undefined)是(但不可访问-死区)是(但不可访问-死区)
块级作用域不是
重复声明允许不允许不允许
初始值可选必须初始化
适用范围函数作用域块级作用域块级作用域
用途旧版 JavaScript 语法,全局作用域变量块级作用域变量,替代 var块级作用域常量
可变性可以重新赋值可以重新赋值不能重新赋值,常量
临时死区(声明之前不让用)

数组方法有哪些请简述

方法描述返回值
arr.push()从数组末尾添加元素,返回添加后数组的长度新数组的长度
arr.pop()从数组末尾删除元素,只能删除一个,返回被删除的元素被删除的元素
arr.shift()从数组头部删除元素,只能删除一个,返回被删除的元素被删除的元素
arr.unshift()从数组头部添加元素,返回添加后数组的长度新数组的长度
arr.splice(i, n)从索引 i 开始删除 n 个元素,返回被删除的元素数组被删除的元素数组
arr.concat()连接两个数组,返回连接后的新数组连接后的新数组
str.split()将字符串转化为数组转化后的数组
arr.sort()将数组进行排序,默认按照字符顺序排序,返回排序后的数组排序后的数组
arr.reverse()将数组反转,返回反转后的数组反转后的数组
arr.slice(start, end)切取索引值 start 到索引值 end 之间的数组,不包含 end切取的数组
arr.forEach(callback)遍历数组,无返回值,可以修改原数组
arr.map(callback)映射数组,返回一个新数组,根据回调函数的返回值生成新元素新数组
arr.filter(callback)过滤数组,返回满足条件的新数组满足条件的新数组

Json 如何新增/删除键值对

直接修改 JSON 字符串是不可行的,首先需要将其解析成 JavaScript 对象,然后对对象进行修改,最后将修改后的对象转换回 JSON 字符串。

JSON ->OBJ
JSON.parse()
OBJ->JSON
JSON.stringify()
  • 增:直接赋值新增键值对,myObject.newKey = ‘newValue’;
  • 删:使用 delete 操作符删除键值对 delete myObject.key1;

改变函数内部 this 指针的指向函数(bind,apply,call 的区别)

  • 都是用于改变this指向
  • bind不会立即执行而是返回一个新的函数
  • apply和call立即执行,apply第二个参数传入参数数组array,call的第二个参数直接传入参数
var obj = { value: 42 };function getValue() {console.log(this.value);
}var boundFunction = getValue.bind(obj,1, 2, 3);
boundFunction(); // 输出:42getValue.apply(obj, args); 
getValue.call(obj, 1, 2, 3);

手写bind

学习视频

  1. 手写apply
    其实本质上就是把函数a放到person里面,执行一下然后删除掉
    function a(gender){console.log(`this ${gender}'s name is ${this.name}`);return {name:this.name,age:this.age}
    }
    const person = {name:'xiaoming',age:'15'
    }
    // a.apply(person,['boy'])
    Function.prototype.newApply = function(obj){let obj=obj||windowlet newArguments = [];for(let i=1;i<arguments.length;i++){newArguments.push(arguments[i])}//最重要的逻辑obj.tempFunc = this;let res=obj.tempFunc(...newArguments);delete obj.tempFunc;return res;
    }
    let b=a.newApply(person,['boy'])
    console.log(b)
    
  2. 手写bind
	function a(gender){console.log(`this ${gender}'s name is ${this.name}`);return {name:this.name,age:this.age}}const person = {name:'xiaoming',age:'15'}
//   b=a.bind(person,'boy')
// b()Function.prototype.newBind=function(obj){console.log(this)let that=this //保存this,也就是调用这个newbind的函数//因为下面在函数里面用,this指向可能会发生变化let newArgus = [...(Array.from(arguments).slice(1))] //注意这里arguments是个对象,要先转化为数组return function(){that.apply(obj,newArgus)//核心代码}}
a.newBind(person,'boy')()

优化后的:
在这里插入图片描述

window和document的关系?

document 表示当前加载的 HTML 文档。
它是 window 对象的属性之一,可以通过 window.document 或简写为 document 来访问

什么是面向对象请简述

  • 是一种编程思想
  • 把程序看做是对象相互作用的过程
  • 每个对象都有自己的属性和方法,并能够与其他对象交互
  • 类:是对象的模板,描述了对象的共同特征和行为。对象是类的实例,具体的实体
  • 三个特点:
  • 1.封装:把属性和方法封装在一个单元内,隐藏了对象的具体实现细节,只暴露必要的接口。提高代码的可维护性和可重用性。
  • 2.继承:允许 子继承父类的属性和方法,便于共享和扩充已有的代码。
  • 3.多态:不同对象的行为可以用相同的方法名调用,但是具体操作不同(其实是废话)

普通函数和构造函数的区别

  1. 普通函数就是用于执行某个特定的任务或操作
  2. 构造函数: 用于创建和初始化对象,它在对象被实例化时被调用,常通过new关键字调用,在JavaScript中,所有的函数实际上都可以被用作构造函数,包括普通函数。当你使用 new 关键字调用一个函数时,该函数就被视为构造函数,用于创建一个新的对象实例
  • 构造函数内部的 this 指向实例,普通函数内部的 this 指向调用函数的
    对象
  • 构造函数习惯上首字母大写

补充-构造函数和类的区别:构造函数和类都用于创建对象和定义对象的属性和方法。都使用 new 关键字可以实例化构造函数或类,得到对象。现代开发中用“类”更多。

请简述原型/原型链/(原型)继承

  • 【先说明原型是什么】原型是对象的一个属性,指向一个父对象。每个对象都有这个属性,都继承父对象的属性和方法
  • 【再形象地解释一下】原型像一个说明书,假设你制造了很多相似的玩具,而它们都有一些共同的特征,比如都能发出声音。你可以把这个共同的特征写在一个“备用说明书”上,然后每个玩具都可以查阅这个说明书,知道怎么发声。原型是对象的属性和方法的集合
  • 【再关联到原型链】每个对象都有一个原型,而该原型又有自己的原型,依此类推,形成一条链。
  • 【补充说明一下作用】当你访问一个对象的属性或方法时,JavaScript 引擎会在原型链上查找,直到找到该属性或方法或者到达原型链的末尾
  • 【一个例外】在原型链的终点,Object.prototype 的原型是 null

操作方法

  • 实例对象本身是没有名为 prototype 的属性的,他们有的是__proto__
  • 只有函数有prototype属性,也可以通过Person.prototype=xxx来改变
  • 查看实例的原型:Object.getPrototypeOf(mydog)或者mydog.prototype
  • 设置实例的原型:Object.setPrototypeOf(myDog, newPrototype); 或者mydog.__proto__

请添加图片描述
构造函数的原型上的方法会被每一个实例方法继承!

function Person(){}
Person.prototype.name='gaga'
let p1=new Person()
let p2=new Person()
console.log(p1.name) //gaga
console.log(p2.name) //gaga

JS 的 new 操作符做了哪些事情?

  1. new 操作符新建了一个空对象,
  2. 这个对象原型(person.__proto__)指向构造函数的prototype(Person.prototype)
  3. 执行构造函数
  4. 返回这个对象

如何实现继承?/ 请写出一个简单的类与继承

暂时只记一种方法:ES6的class继承

class Animal{constructor(name){this.name=name;}sayName(){console.log('name is'+this.name)}
}
class Dog extends Animal {constructor(name.color){super(name);//在子类的构造函数中调用父类的构造函数,并传递 name 参数给父类的构造函数this.breed = breed;}
}let mydog=new Dog('andy','black');
mydog.sayName();

Promise 的理解

  • Promise 是承诺的意思,承诺它过一段时间会给你一个结果
  • Promise 是一种解决异步编程的方案,相比回调函数和事件更合理和更强大
  • 从语法上讲,promise 是一个对象,从它可以获取异步操作的消息

三种状态

  1. pending等待
  2. fulfilled完成,调用Promise的then方法指定的回调函数,传递操作结果。
  3. rejected失败,调用Promise的catch方法指定的回调函数,传递失败原因。
    状态一旦改变,就不会再变

特点

  1. 外界无法直接影响Promise的状态,内部异步操作完成后通过resolve或reject改变状态
  2. 一旦Promise的状态从Pending转变为Fulfilled或Rejected,就不会再发生变化

缺点

无法取消: Promise一旦创建,就无法被取消。

用户输入关键词 “apple”。
开始搜索操作,但用户很快意识到输入错误,想要更改关键词为 “banana”。
由于无法取消前一个搜索操作,系统仍在尝试获取 “apple” 的搜索结果,而用户已经不再关心这个结果。

基本语法

const myPromise = new Promise((resolve,reject)=>{//一些操作if(成功){resolve(成功结果)}else{reject("失败原因")}
)

介绍一下async/await

  • async/await是JavaScript中用于处理异步代码的一种语法糖
  • 一个使用async关键字定义的函数会返回一个Promise对象。在函数体内,你可以使用await关键字等待一个Promise解决,并且在等待期间代码会暂停执行,直到Promise被解决(Fulfilled)或拒绝(Rejected)。
  • 使用try-catch块可以直接捕获异步操作中的错误,而不需要通过回调函数或Promise的catch方法。

我们用 Promise 来解决什么问题?

  1. 回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
  2. 多并发的异步操作: 使用Promise.all()可以并行执行多个异步操作,当所有操作完成时,Promise.all()返回一个包含所有结果的Promise。这种并发执行的方式可以提高异步操作的效率。
  • Promise.all() 接受一个包含多个Promise对象的数组,并返回一个新的Promise。这个新的Promise在传入的所有Promise对象都成功解决时才会成功解决
  • Promise.race() 同样接受一个包含多个Promise对象的可迭代对象,但与Promise.all()不同的是,它在传入的Promise对象中的任何一个解决或拒绝时就会立即解决或拒绝。
Promise.all([promise1, promise2, promise3]).then(values => {console.log(values); // [1, 2, 3]}).catch(error => {console.error(error);});

一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

  1. dns请求。UDP,dns服务器从域名服务开始进行递归搜索,找到ip地址
  2. TCP三次握手
  3. 发送一个http请求,基于tcp
  4. 服务器监听80端口获取请求,发送响应数据。
  5. 浏览器解析
    深度遍历把HTML解析成DOM tree
    遇到script、link、style等会产生阻塞
    css解析渲染dom tree
    js解析

get 请求传参长度的误区

误区:我们经常说 get 请求参数的大小存在限制,而 post 请求的参数大小是无限制的。实际上 HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对 get 请求参数的限制是来源与浏览器或 web服务器,浏览器或 web 服务器限制了 url 的长度

说说前端中的事件流

  • 事件流表示 事件在页面中传播的顺序
  • DOM事件流有两个阶段:捕获阶段和冒泡阶段
捕获阶段
从根节点,沿着DOM树向目标元素传播
应用:在事件到达目标元素之前拦截事件,在用户点击某个区域之前执行一些验证操作
冒泡阶段
从目标元素开始,向根节点传播
应用:事件委托(又叫事件代理)

addEventListener() 方法的第三个参数来控制事件处理程序是在捕获阶段执行还是冒泡阶段执行。如果该参数为true,则事件在捕获阶段执行;如果为false或省略,则事件在冒泡阶段执行

解释一下什么是 Event Loop

  1. 【是什么】Event Loop,简单翻译就是 事件循环,是 JS 语言下实现运行时的一个机制
  2. 【解决什么问题】JS采用这种机制,来解决单线程运行带来的一些问题
  3. JS是一种单线程语言,所有任务都在一个线程上完成
  4. 遇到耗时的任务,就会有很多闲置资源因为等待而浪费
  5. 【怎么解决的】浏览器环境中JS引擎运行在主线程上,同时,浏览器还有其他线程,比如说用户IO线程、HTTP请求线程、定时器线程等等,主线程执行同步任务,当主线程遇到IO操作等异步任务时,就会将异步任务交给其他线程处理,当异步任务完成时,会将结果的回调函数返回给消息队列中,等待主线程执行。这些线程的协作是通过事件循环机制来完成的。
  6. 【具体实现细节】异步任务又分为宏任务和微任务,宏任务的执行时机是在主线程空闲时,事件循环从宏任务队列中取出一个宏任务执行。微任务会在当前任务执行结束后、下一个任务开始前执行,并且优先级比宏任务高

clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop 的区别?

offsetHeight=内容高度+padding+border
偏移高度,即这个元素总共占了多少空间,但注意不包括margin,maigin不算是这个元素里面的,而是元素周围的空白
offset属性是相对于offsetParent元素偏移的数值,offsetParent是距离最近的一个被定位的父元素
在这里插入图片描述
在这里插入图片描述

clientHeight=内容高度+padding
请添加图片描述
scrollHeight=实际内容高度+padding


offsetTop=margin-top
clientTop=border-top
scrollTop提供内容已滚动的距离

鼠标的位置

  • offsetX,offsetY:相对于监听鼠标事件的元素而言的左/上距离
  • clientX/Y:相对于浏览器窗口
  • 原点都在左上角

JS 拖拽功能的实现

使用h5的drop API

<body><div class="draggable" draggable="true" id="draggableElement">拖我</div>
<div class="droppable" id="droppableElement">放在这里</div><script>var draggableElement = document.getElementById('draggableElement');var droppableElement = document.getElementById('droppableElement');// 开始拖动时触发draggableElement.addEventListener('dragstart', function(e) {e.dataTransfer.setData('text/plain', 'Hello, Drag!'); // 设置拖动数据});// 在拖动目标上移动时触发droppableElement.addEventListener('dragover', function(e) {e.preventDefault(); // 阻止默认行为,允许放置});// 放置目标上释放时触发droppableElement.addEventListener('drop', function(e) {e.preventDefault(); // 阻止默认行为,允许放置var data = e.dataTransfer.getData('text/plain'); // 获取拖动数据console.log('拖放的数据:', data);});
</script>

JS的垃圾回收机制

JavaScript 使用自动垃圾回收(Garbage Collection)机制来管理内存。这意味着开发者不需要手动释放不再使用的内存,而是由 JavaScript 引擎自动完成。这有助于避免内存泄漏和提高开发效率

垃圾回收的基本原理是找到不再被引用的对象,然后释放它们占用的内存。下面是 JavaScript 中垃圾回收的一些关键概念:

有哪些垃圾回收策略?

  • 引用计数
    该策略通过在对象上维护一个引用计数器来跟踪对象的引用次数。当引用计数变为零时,对象被认为是不再被引用的,即可被垃圾回收。
    缺点是无法解决循环引用的问题,因为循环引用的对象的引用计数永远不会变为零。
  • 标记清除(Mark and Sweep)
    从根对象(一般是全局对象)开始,标记所有可以从根对象访问到的对象。这通常涉及到遍历变量、函数作用域、闭包、以及全局作用域中的所有引用。
    在标记阶段完成后,所有未被标记的对象被认为是不再被引用的,即不可达的对象。这些对象将被清除(回收),释放其占用的内存。

DOM VS BOM

  • DOM 树是文档对象模型的表示,它反映了 HTML 或 XML 文档的层次结构,将文档的内容表示为一个树形结构。在 DOM
    树中,每个HTML 或 XML元素、属性、文本均被表示为一个节点(Node)。DOM树的根节点是文档节点(Document),它包含整个文档的内容。
  • BOM树表示浏览器窗口和浏览器提供的一些对象(非文档对象)。在 BOM 树中,常见的对象包括window、screen、location、history 等。window 对象是 BOM 树的根节点,它代表了整个浏览器窗口。

JS 监听对象属性的改变

方法1:使用Object.defineProperty修改对象属性的内部特性

// 创建一个对象
let myObj = {};// 在对象上定义属性 'myProperty'
Object.defineProperty(myObj, 'myProperty', {get: function() {return this._myProperty;},set: function(value) {this._myProperty = value;console.log('myProperty 被修改了:', value);},enumerable: true,configurable: true
});// 使用该属性
myObj.myProperty = 42; // 触发 set 方法,并输出 'myProperty 被修改了: 42'
console.log(myObj.myProperty); // 触发 get 方法,并输出 42

方法2:Proxy
//以后再学

JS 怎么控制一次加载一张图片,加载完后再加载下一张

使用promise

//图片的地址数组
const imgsArr = ['img1',....]
//下载图片的函数
function loadImg(src){return new Promise((resolve, reject)=>{const img = new Image();img.src = src;img.onload = ()=>resolve(img)//加载成功的回调函数img.onerror = reject; //加载失败的回调})
}//按顺序下载图片
async function loadImgSeq(){for(const src of imgArr){const img = await loadImg(src);imageDIV.appendChild(img);}
}

深拷贝VS浅拷贝?

  • 浅拷贝只复制对象本身以及对象内的基本数据类型,而对于引用类型的元素仅复制引用而不复制实际数据 (直接newobj=oldObj即可)
  • 深拷贝会复制所有嵌套的引用类型比如对象和数组,新复制的对象上的任何更改都不会影响旧对象,两者完全独立。(需要通过一些库来实现)

实现 JS 中所有对象的深度克隆(包装对象,Date 对象,正则对象)

function deepClone(obj, visited = new WeakMap()) {// 检查是否为基本数据类型,如果是,则直接返回if (obj === null || typeof obj !== 'object' || obj instanceof Date || obj instanceof RegExp) {return obj;}// 检查是否已经访问过该对象,防止循环引用if (visited.has(obj)) {return visited.get(obj);}// 创建一个新的对象或数组let clone;if (obj instanceof Date) {clone = new Date(obj.getTime());} else if (obj instanceof RegExp) {clone = new RegExp(obj);} else if (Array.isArray(obj)) {clone = [];} else {clone = Object.create(Object.getPrototypeOf(obj));}// 记录已经访问过的对象,以便处理循环引用visited.set(obj, clone);// 递归地深度克隆对象的属性for (let key in obj) {if (obj.hasOwnProperty(key)) {clone[key] = deepClone(obj[key], visited);}}return clone;
}

代码解释:

  1. 基本数据类型: 基本数据类型(如字符串、数字、布尔值等)在 JavaScript 中是按值传递的,而不是按引用传递的。因此,对基本数据类型进行赋值或传递时,会直接复制其值而不涉及引用。所以,不需要对基本数据类型进行深拷贝。上述实现中的条件语句 if (obj === null || typeof obj !== 'object' || obj instanceof Date || obj instanceof RegExp) 就是用来检查是否为基本数据类型,如果是,则直接返回原始值。

  2. 循环引用: 循环引用指的是对象包含对自身的引用,形成一个循环链。在深度克隆时,如果不处理循环引用,可能导致无限递归,最终导致堆栈溢出或其他性能问题。使用 WeakMap 来记录已经访问过的对象,可以在发现循环引用时停止递归,避免陷入无限循环。

  3. obj.hasOwnProperty(key) 这是为了确保只复制对象自身的属性,而不包括从原型链继承的属性。在 JavaScript 中,对象的属性可以分为自身属性和继承属性。使用 hasOwnProperty 方法可以判断一个属性是否为对象自身的属性,而不是从原型链上继承的属性。这是为了避免复制不必要的属性,只复制对象自身的属性。

  4. WeakMap 是 JavaScript 中的一种集合类型,它允许将对象作为键存储在映射中。与 Map 不同,WeakMap 中的键只能是对象,而值可以是任意类型。一个 WeakMap 中的键是弱引用的,这意味着如果对象作为键不再被引用,它可以被垃圾回收器回收,从而释放相应的键值对。

能来讲讲 JS 的语言特性

JavaScript 是一门多范式的编程语言,主要用于在网页上实现交互性。它具有一些独特的语言特性,以下是其中一些主要的特点:

  1. 动态类型: JavaScript 是一门动态类型的语言,变量的数据类型可以在运行时动态改变。这意味着你可以在不事先声明变量类型的情况下直接赋值。
  2. 弱类型: JavaScript 是一门弱类型语言,也被称为动态弱类型语言。这意味着在进行一些操作时,JavaScript 会进行隐式类型转换,而不会引发错误。
  3. 原型继承: JavaScript 使用原型继承作为对象之间共享和复用代码的机制。每个对象都有一个原型对象,而对象可以继承原型对象的属性和方法。
  4. 跨平台性: JavaScript 不仅用于浏览器端,还可以通过 Node.js 在服务器端运行。这使得 JavaScript 成为一种具有广泛用途的通用编程语言。
  5. 脚本语言、解释性语言: 脚本语言的一个特点是可以逐行地执行,而不需要事先将整个程序编译成机器码。解释性语言,是因为它的代码在运行时由解释器逐行解释执行。

为什么会造成跨域/请简述同源策略?

同源策略(Same-Origin Policy)是浏览器的一种安全机制,用于防止恶意网站通过脚本等方式进行恶意请求。同源策略规定,两个页面只有在协议、主机和端口均相同的情况下,才属于同一个源(origin)。
举例一种如果没有同源策略,可能会发生的情况: 恶意网站读取了cookie后,可以使用用户的身份信息发起对银行网站的恶意请求

请输出三种减少页面加载时间的方式

  1. 压缩图片/视频音频质量
  2. 懒加载
  3. 异步加载,不阻塞:使用async或defer属性加载JavaScript文件,以确保它们不会阻止页面的渲染。
    <script defer src="example.js"></script>
  4. 使用 CDN 托管资源(使用 CDN Content Delivery Network,内容分发网络 将静态资源放在全球多个服务器上,CDN 会根据用户的地理位置自动选择距离用户最近的服务器提供资源)

什么是 jsonp 工作原理是什么?他为什么不是真正的 ajax

Jsonp 其实就是一个跨域解决方案。
Js 跨域请求数据是不可以的,但是 js 跨域请求 js 脚本是可以的。
jsonp 原理:(动态创建 script 标签,回调函数)
浏览器在 js 请求中,是允许通过 script 标签的 src 跨域请求,可以在请求的结果中添加回调方法名,在请求页面中定义方法,就可获取到跨域请求的数据。

// 客户端定义的回调函数
function handleResponse(data) {// 处理从服务器返回的数据console.log(data);
}// 创建一个 <script> 元素
const script = document.createElement('script');// 设置 <script> 元素的 src 属性,包含 JSONP 请求的 URL,并指定回调函数名
script.src = 'https://example.com/data?callback=handleResponse';// 将 <script> 元素添加到页面中,触发跨域请求
document.body.appendChild(script);

他为什么不是真正的 ajax
ajax 的核心是通过XmlHttpRequest获取本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的 js 脚本。

请掌握 2 种以上数组去重的方式

  1. set
const uniqueArray = [...new Set(originalArray)];
  1. filter
const uniqueArray = originalArray.filter((value, index, self) => {return self.indexOf(value) === index;
});

箭头函数与普通函数的区别

箭头:没有原型属性,不能作为构造函数,不存在arguments,没有自己的this,this指向这个函数的上下文作用域;
普通函数:有arguments对象,可以作为构造函数,this指向调用这个函数的对象,没有被调用时,指向全局对象;

function example() {console.log(arguments.length); // 参数个数=0
}

常见的 HTTP状态码

  1. 信息性状态码(Informational Codes):

    • 100 Continue: 表示服务器已经接收到请求的部分,但仍然等待客户端发送剩余的请求。
  2. 成功状态码(Successful Codes):

    • 200 OK: 表示请求已成功。
    • 201 Created: 表示请求已经被成功处理,并且服务器创建了新的资源。
    • 204 No Content: 表示服务器成功处理了请求,但没有返回任何内容。
  3. 重定向状态码(Redirection Codes):

    • 301 Moved Permanently: 表示被请求的资源已经永久移动到新位置。
    • 302 Found (Moved Temporarily): 表示被请求的资源已经临时移动到新位置。
    • 304 Not Modified: 表示资源未被修改,可以使用缓存的版本。
  4. 客户端错误状态码(Client Error Codes):

    • 400 Bad Request: 表示客户端发送了一个服务器无法理解的请求。
    • 401 Unauthorized: 表示请求需要用户身份验证。
    • 403 Forbidden: 表示服务器理解请求,但拒绝执行。
    • 404 Not Found: 表示服务器无法找到请求的资源。
  5. 服务器错误状态码(Server Error Codes):

    • 500 Internal Server Error: 表示服务器遇到了一个未知的错误。
    • 501 Not Implemented: 表示服务器不支持当前请求所需要的某个功能。
    • 503 Service Unavailable: 表示服务器当前无法处理请求,通常是因为服务器过载或维护。

预加载和懒加载的使用场景

  • 预: 在用户打开商品详情页面前,提前加载商品的相关信息和评论,减少用户等待时间,提高用户体验。
  • 懒:在游戏开始时,只加载当前场景所需的资源,例如地图、角色和音效,以避免一开始就加载整个游戏的资源,提高游戏启动速度。

Js 的函数节流和函数防抖的区别

  • 用于控制函数调用频率的技术,用在一些高频触发的场景中
函数节流
函数节流是指在一定时间内,无论触发事件多少次,只执行一次函数。
场景:微博热搜,热搜词条可能以非常高的频率进行更新,可以使用防抖设置一分钟更新一次,而不是每次有新词条都要触发重新计算。
实现原理
function throttle(func, delay) {let lastTime = 0;return function() {const now = Date.now();if (now - lastTime >= delay) {func.apply(this, arguments);lastTime = now;}};
}
实际开发中使用的是lodash库中的throttle函数
import _ from 'lodash';
const newfunc = _.throttle(func, 500);
函数防抖
等待一定时间,如果在这个时间内没有新的触发事件,则执行函数;如果有新的触发事件,则重新计时。
场景:搜索,每次输入新的文字都会进行搜索内容,但是如果打字太快就会导致过多的搜索请求,就可以使用节流。
实现原理
function debounce(func, delay) {let timer;return function() {clearTimeout(timer);timer = setTimeout(() => {func.apply(this, arguments);}, delay);};
}
实际使用Lodash库中的debounce函数来实现函数防抖
const newfunc = _.debounce(func, 500);

介绍一下js中的计时器

// 在2秒后执行函数
const timeoutId = setTimeout(() => {console.log('Timeout executed!');
}, 2000);// 取消定时执行
clearTimeout(timeoutId);
---------------------------------------------------------
// 每隔1秒执行一次函数
const intervalId = setInterval(() => {console.log('Interval executed!');
}, 1000);// 取消重复执行
clearInterval(intervalId);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2821899.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

windows server mysql 数据库停止 备份 恢复全流程操作方法

一,mysql备份 mysql最好是原工程文件备份.不需要sql查询的方式备份.安全高效. 比如,安装php与mysql组合后,我的mysql文件保存在: D:\phpstudy_pro\Extensions\MySQL5.7.26\data\dux 我只需要复制一份,保存起来就行. 二,mysql恢复 怎么恢复呢.我们一般是只恢复其中一个表,则找…

初学者如何使用QT新建一个包含UI界面的C++项目

文章目录 一、下载并安装QT51、下载安装包2、注册/登录账号3、安装qt6 二、新建QT Widget项目1、新建项目并且运行2、易错点&#xff1a;可能运行成功得到UI界面但是会报错&#xff08;原因是使用了中文路径&#xff09; 一、下载并安装QT5 1、下载安装包 进入下载网址 Windo…

MES系统在离散制造企业中的功能解析

随着信息技术的快速发展和制造业的转型升级&#xff0c;MES在离散制造企业中的作用日益凸显。MES系统不仅提高了生产效率和产品质量&#xff0c;还优化了资源配置&#xff0c;增强了企业的市场竞争力。 一、生产管理功能 MES系统能够实时监控生产现场的各种数据&#xff0c;包…

java小记(2)

IS-A&#xff1a;类的父子继承关系。 default&#xff1a;关键字&#xff0c;与Java中的public&#xff0c;private等关键字一样&#xff0c;都属于修饰符关键字&#xff0c;可以用来修饰属性、方法以及类&#xff0c;但是default一般用来修饰接口中的方法。 接口与抽象类的区…

WSL2部署RV1126 SDK编译环境

1 下载RV1126 SDK 在 Firefly | 让科技更简单&#xff0c;让生活更智能 下载REPO_SDK 这里将SDK下载到了F:\SDK 2 解压SDK到WSL2 tar -xvf /mnt/f/SDK/rv1126_rv1109_linux_release_20211022.tgz 3 编译依赖安装 gcc、g版本依赖安装 sudo apt-get install lib32gcc-7-dev g-7 l…

普通索引和唯一索引详解

前言 面试的时候有时会问面试者&#xff0c;普通索引和唯一索引有什么区别。很多人&#xff0c;甚至工作很多年的工程师回答的千篇一律 “普通索引可以有重复的值&#xff0c;唯一索引不能有重复的值”。于是我又问&#xff0c;这两个索引这两个索引效率哪个高&#xff0c;很少…

ant design pro的react项目build之后页面为空白解决方法

一、问题 执行yarn build之后访问dist文件夹中的index.html文件为空白 二、解决方法 找到config文件夹中的config.ts文件 添加代码 history: {type: hash }, publicPath: ./,修改完重新build一下就好了

BY组态功能清单

演示地址 &#xff1a;http://www.byzt.net:60/sm/ 官网地址&#xff1a;http://www.hcy-soft.com BY组态是一款非常优秀的纯前端的【web组态插件工具】&#xff0c;可无缝嵌入到vue项目&#xff0c;react项目等&#xff0c;由于是原生js开发&#xff0c;对于前端的集成没有框架…

你真的了解C语言中的【柔性数组】吗~

柔性数组 1. 什么是柔性数组2. 柔性数组的特点3. 柔性数组的使用4. 柔性数组的优势 1. 什么是柔性数组 也许你从来没有听说过柔性数组这个概念&#xff0c;但是它确实是存在的。 C99中&#xff0c;结构体中的最后⼀个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员…

Spring Boot整合Kafka

文章目录 1. 介绍2. Kafka基础2.1. 安装KafKakafka集群搭建_kafka交流群-CSDN博客 3. Spring Boot整合Kafka3.1. 引入Kafka依赖3.2.编写配置文件 4. 生产者&#xff08;produced&#xff09;4.1. 生产者基础案例(基础测试) 5. 消费者5.1.消费者基本案例(基础测试) 6.Kafka常用配…

python 公共函数及操作符使用示例合集

python公共操作符以及方法是什么 在Python中&#xff0c;公共操作通常指的是那些可以对不同数据类型&#xff08;如数字、字符串、列表、元组、字典等&#xff09;进行操作的通用函数或方法。这些操作符或函数通常是内置的&#xff0c;并且可以在Python的官方文档中找到。 主要…

数字电路 第五章—第四节(顺序脉冲发生器)

一、计数型顺序脉冲发生器 1、电路组成 计数型顺序脉冲发生器一般都是按自然态序计数的二进制计数器和译码器组成。 2、输出4个脉冲的顺序脉冲发生器 &#xff08;1&#xff09;逻辑电路图&#xff08;采用JK触发器&#xff09;&#xff1a; &#xff08;2&#xff09;时序图…

二叉搜索树的范围和(Lc938)——DFS

给定二叉搜索树的根结点 root&#xff0c;返回值位于范围 [low, high] 之间的所有结点的值的和。 示例 1&#xff1a; 输入&#xff1a;root [10,5,15,3,7,null,18], low 7, high 15 输出&#xff1a;32示例 2&#xff1a; 输入&#xff1a;root [10,5,15,3,7,13,18,1,nul…

家居清洁必备:2024如何挑选高效家用洗地机的实用指南

对于养宠物的家庭来说&#xff0c;宠物的毛发无处不在&#xff0c;尤其在换毛季节&#xff0c;清理工作更加繁琐。此时&#xff0c;洗地机的出现为解决这些问题提供了便利。洗地机可以同时扫地和拖地&#xff0c;实现高效清洁&#xff0c;减轻了清洁负担。而且&#xff0c;洗地…

【爬虫逆向实战 逆向滑块 Python+Node】今天逆向的网站有点嘿嘿,还是仅供学习,别瞎搞

逆向日期&#xff1a;2024.03.01 使用工具&#xff1a;Node.js、Python 加密方法&#xff1a;AES标准算法 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&#xff08;直接解密即可&#xff09;&#xff08;crypto-js.js 标准算…

windows系统安装《植物大战僵尸2009原版》教程

本文演示如何在windows免费安装 植物大战僵尸2009原版。 首先到 点此下载安装包 此页面最末端下载百度网盘分享的安装包。 下载完成后安装如下步骤进行安装&#xff1a; 安装完成即可开心的玩耍啦&#xff01; 我自己的安装过程录屏在这里 https://www.bilibili.com/vid…

新 Logo 正式发布,Tubi 品牌全面升级!

作为新一代观众的首选流媒体平台&#xff0c;Tubi 持续扩大自身影响力&#xff0c;并于近日推出了富有活力的新品牌形象。 根据 Nielsen 的 The Gauge 报告&#xff0c;Tubi 在 2024 年 1 月的电视总观看份额提升至 1.5%&#xff0c;在年轻人和多元化观众群体中的吸引力持续上升…

MYSQL--JDBC优化

一.JDBC优化: 优化前提: 有时候我们并不清楚某些表当中一共有多少列,以及这些列的数据类型,这个时候我们就需要提前通过一些方法提前了解到这些数据,从而更好的进行输出 具体语句: package cn.jdbc;import java.sql.*;public class JDBCDEmo1 {public static void main(String…

11.盛最多水的容器

题目&#xff1a;给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 解题思路&#xff1a;可以…

2023 re:Invent AI 生成产品体验,从 Bedrock 到 Amazon Q

引 如果你也有如下问题&#xff0c;那么接下来的文字会一一为你解答 一套数据集&#xff0c;如何微调不同类型的开源大模型&#xff1f;—— Bedrock 如何只有产品说明书&#xff0c;如何构建一个智能问答机器人&#xff1f;—— Q 哪里还有免费的 GPU 算力——在线 Jupyter…