【js篇】二常见面试题

【js篇】常见面试问题

函数的柯里化

总结:思路,每次执行,判断参数是否齐全,如果不齐全,递归调用把原来的 arguments一起上去

scss 复制代码
      function curry(fn,...args){
        console.log("...args",args) //就是arguments
        // 判断fn需要的参数是否够了
        if(args.length >= fn.length){ //fn.length 是add函数的形参个数
          return fn(...args) // 收集参数齐所有的参数 即是arguments解构
        }
        // 递归调用
        return (...rest)=>{
          console.log('...rest',...rest)// rest就是当前调用的参数 arguments
          return curry(fn,...args,...rest) //递归调用把原来的 arguments一起上去 和当前的arguments一起 解构
        }
      }

      //案例一:
      const add =(x,y,z)=>x+y+z;
      const curryAdd=curry(add);
      let b=curryAdd(1)(2)(3)
      console.log(b) // 6

数组的扁平

bash 复制代码
      const arr = [
        {id: 1, name: '部门1', pid: 0},
        {id: 2, name: '部门2', pid: 1},
        {id: 3, name: '部门3', pid: 2},
        {id: 4, name: '部门4', pid: 3},
        {id: 5, name: '部门5', pid: 4},
      ]


      function changeFun(aray,id){
        let arr=[];
        for(let item of aray){
          if(item.pid==id){
            arr.push({...item,children:children(aray,item.id)})
          }
        }
        return aray
      }

数组的降维度

javascript 复制代码
    let arr12=[1,3,4,[5,6,7,[8,9]]]
    console.log('flat',arr12.flat(1)) //[1,3,4,5,6,7,[8,9]]
    console.log('flat',arr12.flat(Infinity))// [1,3,4,5,6,7,8,9]

去重

ini 复制代码
 let aray=[2,4,1,2,4,6,8,9,1]
    let setArray=new Set(aray)
    aray=[...setArray]
    console.log(aray) // [2, 4, 1, 6, 8, 9]

乱序

冒泡排序

arduino 复制代码
      // 数组排序(升和降)sort()
      // let aray=[2,4,1,6,8,9,20,21,18]
      // function riseNumber(a,b){ // 升序
      //   return a-b;
      // }
      // function dropNumber(a,b){
      //   return b-a
      // }
      // console.log(aray.

sort(riseNumber))//[1, 2, 4, 6, 8, 9, 18, 20, 21] // console.log(aray.sort(dropNumber)) //[21, 20, 18, 9, 8, 6, 4, 2, 1]

ini 复制代码
      // 冒泡排序
      // let aray=[2,4,1,6,8,9,20,21,18]
      // for(var i=0;i<aray.length-1;i++){
      //   let isSort=true;
      //   for(var j=0;j<aray.length-1-i;j++){
      //     if(aray[j]>aray[j+1]){
      //       isSort=false;
      //       let tmp=aray[j]
      //       aray[j]=aray[j+1]
      //       aray[j+1]=tmp
      //     }
      //   }
      //   if(isSort) break;
      // }

面试题一

const声明对象

虽然const变量不能修改指针,但是可以修改值,比如我们定义一个对象,我们就可以修改对象里的属性值,但是不可以重写整个对象。

["1","2","3"].map(parseInt)

分解

  1. map():里面是个回调函数,三个参数:分别是当前值(v),下标(i),原始数组(arr)

2: 整写法如下['1', '2', '3'].map((v, i, arr) => parseInt(v, i))

从这个简单例子来看,new操作符做了两件事:

  1. 创建了一个全新的对象。
  2. 这个对象会被执行[[Prototype]](也就是__proto__)链接。

promise和async区别

  • promise是个对象Es6语法,async是个函数,es7语法
  • promise 处理异步是另一种地狱回调async是测底拉平,更加优雅
  • async的底层是promise

事件捕捉 与冒 泡模型

如何阻止事件冒泡?

ie:阻止冒泡ev.cancelBubble = true;

非IE ev.stopPropagation();

如何阻止默认事件?

(1)return false;(2) ev.preventDefault();

Javascript的事件流模型都有什么?

"事件捕捉":是从上往下,window,document,document.documentelment(获取的html) document,body 、........目标元素

"事件冒泡":是从下往上:反之

"DOM事件流":三个阶段:事件捕捉、目标阶段、事件冒泡

null和undefined的区别?

nul l是一个表示"无"的对象转为数值时为0undefined 是一个表示"无"的原始值转为数值时为NaN

当声明的变量还未被初始化时,变量的默认值为undefined。 null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。

post 和get 区别

前端性能值有哪些,如何量化

首次内容绘制【 First Contentful Paint, FCP

  • 定义: 浏览器首次渲染DOM内容的时间。
  • 量化 : 通过PerformanceObserverAPI监测first-contentful-paint条目。

最大内容绘制【Largest Contentful Paint, LCP

  • 定义: 页面中最大内容元素渲染完成的时间。
  • 量化 : 使用PerformanceObserver监测largest-contentful-paint条目。

首次输入延迟【First Input Delay, FID

  • 定义: 用户首次与页面交互到浏览器响应的延迟时间。
  • 量化 : 通过PerformanceObserver监测first-input条目。

累计布局偏移【 Cumulative Layout Shift, CLS

  • 定义: 页面生命周期内发生的意外布局偏移总和。
  • 量化 : 使用PerformanceObserver监测layout-shift条目,并计算偏移分数。

交互与时间【Time to Interactive, TTI

  • 定义: 页面完全可交互的时间。
  • 量化: 通过Lighthouse等工具测量。

首字节时间【Time to First Byte, TTFB

  • 定义: 浏览器接收到服务器响应的第一个字节的时间。
  • 量化 : 使用performance.timingPerformanceObserver监测responseStartrequestStart的差值。

Domcontentloaded 事件

  • 定义: HTML文档完全加载和解析完成的时间。
  • 量化 : 通过performance.timing.domContentLoadedEventStart获取。

资源加载时间

  • 定义: 页面中各个资源(如图片、CSS、JS)的加载时间。
  • 量化: 使用浏览器开发者工具的Network面板查看。

页面完全加载时间

  • 定义: 页面所有资源加载完成的时间。
  • 量化 : 通过performance.timing.loadEventEnd获取。

重绘和重排次数

  • 定义: 页面渲染过程中发生的重绘和重排次数。
  • 量化: 使用浏览器开发者工具的Performance面板分析。

js 执行时间

  • 定义: JavaScript代码执行的总时间。
  • 量化: 使用浏览器开发者工具的Performance面板分析。

内存使用

  • 定义: 页面运行时的内存占用。
  • 量化: 使用浏览器开发者工具的Memory面板查看。

总阻塞时间

  • 定义: FCP到TTI之间主线程被阻塞的总时间。
  • 量化: 使用Lighthouse等工具测量。

网络请求数量

  • 定义: 页面加载过程中发起的HTTP请求总数。
  • 量化: 使用浏览器开发者工具的Network面板查看。

速度指数

  • 定义: 页面内容视觉填充的速度。
  • 量化: 通过Lighthouse等工具测量。

伪数组和数组的区别

  • 数组的原型是Array,伪数组的是一个普通对象
  • 伪数组:是arguments(函数参数对象)、nodeList(Dom集合)、或者手动({0:"a",1:"b",length:1})
  • 伪数组不能直接使用、map、push、foreach等方法,需要用Array.from转换或者用call/apply

token 能放到cookies上吗

  1. 需结合 Token 校验和加密机制
  2. 推荐将 Token 置于 HTTP 头(如 Authorization: Bearer <token>

XSS攻击

一种通过向网页注入恶意脚本(如JavaScript、HTML、CSS等)实现攻击的网络安全漏洞

防御XSS攻击的关键措施

  1. 输入过滤与转义

    • 对用户输入内容进行严格过滤,使用htmlspecialchars()htmlentities()等函数转义特殊字符(如<>&12
    • 示例 :PHP中htmlspecialchars($input, ENT_QUOTES)可转义单双引号。
  2. 输出编码

    • 在将数据输出到页面时,根据上下文(HTML、JavaScript、CSS)选择合适的编码方式5
  3. 设置安全HTTP头部

    • 启用X-XSS-Protection头部强制浏览器启用XSS过滤3
    • 使用Content-Security-Policy (CSP)限制脚本来源5
  4. 使用HttpOnly Cookie

    • 为敏感Cookie设置HttpOnly属性,阻止JavaScript访问,降低信息泄露风险16
  5. 避免内联脚本与动态DOM操作

    • 减少使用eval()innerHTML等高风险API,优先通过文本节点操作DOM6

CSRF攻击是什么?

是一种利用用户在已登录状态下对目标网站的信任,通过诱导用户触发恶意请求的攻击方式。攻击者伪造用户的身份,执行非用户本意的敏感操作(如转账、修改密码等

预防

Token 验证SameSite Cookie双重认证请求来源校验

与 XSS 攻击的区别

特性 XSS 攻击 CSRF 攻击
利用对象 利用用户对网站的信任 利用网站对用户浏览器的信任
攻击目标 窃取用户数据或劫持会话 伪造用户身份执行敏感操作
防御重点 过滤用户输入与输出 校验请求来源与身份

三栏布局的实现方案有哪些?

浮动布局、flex布局、绝对定位布局、grid布局grid-template-columns 定义三列,中间自适应、圣杯/双飞翼布局

变量提升

JavaScript 预编译阶段的特性 ,表现为变量和函数的声明 会被隐式提升 到当前作用域(全局或函数作用域)的顶端 ,但赋值操作仍保留在原位置

一个图片 url 访问后直接下载怎样实现?

HTML的download属性

<a>标签中添加download属性,浏览器会直接下载文件:

ini 复制代码
<a href="图片URL" download="自定义文件名.jpg">下载图片</a>

Blob对象下载

通过Fetch API获取文件流并生成Blob对象:

ini 复制代码
fetch(url)
  .then(res => res.blob()) 
  .then(blob => {
    const a = document.createElement('a'); 
    a.href  = URL.createObjectURL(blob); 
    a.download  = 'filename.jpg'; 
    a.click(); 
  });
  • 优点:支持大文件异步下载

服务器端配置方案

设置HTTP响应头

在服务器返回图片时添加Content-Disposition头:

BOM和BOM对象

BOM是浏览器对象模型,提供了与浏览器窗口交互的接口。常见对象包括window、location、history、navigator、screen等。

window对象

窗口控制

markdown 复制代码
-   `window.open(url)` :打开新窗口或标签页[6](https://www.nowcoder.com/questionTerminal/e1c38e4b631f4054a663b6531690df7e?toCommentId=2794725)
-   `window.close()` :关闭当前窗口(仅限通过脚本打开的窗口)[6](https://www.nowcoder.com/questionTerminal/e1c38e4b631f4054a663b6531690df7e?toCommentId=2794725)
-   `window.resizeTo(width, height)`:调整窗口大小[4](https://blog.csdn.net/weixin_33806509/article/details/93203542)

定时器

scss 复制代码
-   `setTimeout(func, delay)`:延迟执行一次函数[5](https://blog.csdn.net/lcwben/article/details/59060158)
-   `setInterval(func, interval)`:周期性执行函数[5](https://blog.csdn.net/lcwben/article/details/59060158)
-   `clearTimeout()`/`clearInterval()`:清除定时器[5](https://blog.csdn.net/lcwben/article/details/59060158)

窗口信息

markdown 复制代码
-   `window.innerWidth`/`window.innerHeight` :获取视口尺寸(包含滚动条)[10](https://blog.csdn.net/qq_34771938/article/details/120353624)
-   `window.scrollY` :获取垂直滚动距离[10](https://blog.csdn.net/qq_34771938/article/details/120353624)`

Location 对象(操作 URL 相关)

URL 控制

scss 复制代码
-   `location.href` :获取或设置完整 URL(可用于跳转页面)[2](https://blog.csdn.net/weixin_50077864/article/details/127268410)[6](https://www.nowcoder.com/questionTerminal/e1c38e4b631f4054a663b6531690df7e?toCommentId=2794725)
-   `location.reload(force)` :刷新页面(参数 `true` 强制从服务器加载)[2](https://blog.csdn.net/weixin_50077864/article/details/127268410)[10](https://blog.csdn.net/qq_34771938/article/details/120353624)
-   `location.replace(url)` :替换当前页面(不可后退)[7](https://blog.csdn.net/azhimei1545/article/details/101508707)[10](https://blog.csdn.net/qq_34771938/article/details/120353624)

URL 解析

markdown 复制代码
-   `location.search` :获取 URL 查询参数(`?` 后的内容)[2](https://blog.csdn.net/weixin_50077864/article/details/127268410)[3](https://blog.csdn.net/weixin_43900284/article/details/113441680)
-   `location.hash` :获取锚点部分(`#` 后的内容)[3](https://blog.csdn.net/weixin_43900284/article/details/113441680)[7](https://blog.csdn.net/azhimei1545/article/details/101508707)

History 对象*(浏览器历史记录)

页面导航

scss 复制代码
-   `history.go(n)` :前进/后退指定页数(`1` 前进,`-1` 后退)[2](https://blog.csdn.net/weixin_50077864/article/details/127268410)[6](https://www.nowcoder.com/questionTerminal/e1c38e4b631f4054a663b6531690df7e?toCommentId=2794725)
-   `history.back()` :后退一页[3](https://blog.csdn.net/weixin_43900284/article/details/113441680)[6](https://www.nowcoder.com/questionTerminal/e1c38e4b631f4054a663b6531690df7e?toCommentId=2794725)
-   `history.forward()` :前进一页[3](https://blog.csdn.net/weixin_43900284/article/details/113441680)[6](https://www.nowcoder.com/questionTerminal/e1c38e4b631f4054a663b6531690df7e?toCommentId=2794725)

历史栈信息

markdown 复制代码
-   `history.length` :获取历史记录中的页面数量[9](https://blog.csdn.net/cainiaoyihao_/article/details/117883001)

浏览器识别

markdown 复制代码
-   `navigator.userAgent` :获取浏览器标识(用于检测浏览器类型)[5](https://blog.csdn.net/lcwben/article/details/59060158)[9](https://blog.csdn.net/cainiaoyihao_/article/details/117883001)
-   `navigator.platform` :获取操作系统信息[7](https://blog.csdn.net/azhimei1545/article/details/101508707)[9](https://blog.csdn.net/cainiaoyihao_/article/details/117883001)

功能检测

markdown 复制代码
-   `navigator.cookieEnabled` :检测是否启用 Cookie[2](https://blog.csdn.net/weixin_50077864/article/details/127268410)[6](https://www.nowcoder.com/questionTerminal/e1c38e4b631f4054a663b6531690df7e?toCommentId=2794725)
-   `navigator.onLine` :检测网络连接状态[9](https://blog.csdn.net/cainiaoyihao_/article/details/117883001)

Screen 对象(屏幕信息)

  • screen.width/screen.height :获取屏幕分辨率49
  • screen.availWidth/screen.availHeight :获取可用屏幕尺寸(排除任务栏)910

html5 drag APi

dragstart:事件主体是被拖放元素,在开始拖放被拖放元素时触发,。

darg:事件主体是被拖放元素,在正在拖放被拖放元素时触发。

dragenter:事件主体是目标元素,在被拖放元素进入某元素时触发。

dragover:事件主体是目标元素,在被拖放在某元素内移动时触发。

dragleave:事件主体是目标元素,在被拖放元素移出目标元素是触发。

drop:事件主体是目标元素,在目标元素完全接受被拖放元素时触发。

dragend:事件主体是被拖放元素,在整个拖放操作结束时触发

iframe 是什么?有什么缺点?

定义:iframe 元素会创建包含另一个文档的内联框架

提示:可以将提示文字放在之间,来提示某些不支持 iframe 的浏览器

缺点:

会阻塞主页面的 onload 事件

搜索引擎无法解读这种页面,不利于 SEO

iframe 和主页面共享连接池,而浏览器对相同区域有限制所以会影响性能。

一句话概括 RESTFUL

就是用 URL 定位资源,用 HTTP 描述操作。

click 在 ios 上有 300ms 延迟,原因及如何解决?

原因:

要是为了区分用户的单击操作和双击缩放操作

解决

1、使用FastClick库

2、 在HTML文档的<head>区域添加以下meta标签来禁用双击缩放功能:

ini 复制代码
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

3、使用CSS属性touch-action: manipulation;。这个属性可以告诉浏览器某些触摸行为(如双击缩放)应该被禁用,从而减少或消除点击延迟。

Math对象

Math.round(x)

arduino 复制代码
返回 `x` 四舍五入后的整数。

```
console.log(Math.round(4.7)); // 5
console.log(Math.round(4.3)); // 4
```

Math.ceil(x)

arduino 复制代码
返回 `x` 向上取整后的整数。


```
console.log(Math.ceil(4.1)); // 5
console.log(Math.ceil(-4.1)); // -4
```

Math.floor(x)

arduino 复制代码
返回 `x` 向下取整后的整数。


```
console.log(Math.floor(4.9)); // 4
console.log(Math.floor(-4.9)); // -5
```
  • Math.trunc(x)

    返回 x 的整数部分(去除小数部分)。

    javascript 复制代码
    console.log(Math.trunc(4.9)); // 4
    console.log(Math.trunc(-4.9)); // -4

Math.random()

go 复制代码
返回一个 0 到 1 之间的随机数(包含 0,不包含 1)。

```
console.log(Math.random()); // 0.1234567890123456
```
如果只需要生成 1 到 10 的随机整数,可以简化代码:
javascript 复制代码
const randomNumber = Math.floor(Math.random() * 10) + 1;
console.log(randomNumber); // 1 到 10 之间的随机整数
  • 原理

    • Math.random() * 10 生成 [0, 10) 之间的随机小数。
    • Math.floor() 向下取整,得到 [0, 9] 的整数。
    • 加上 1,将范围调整为 [1, 10]
生成指定范围的整数

使用 Math.random()Math.floor()

arduino 复制代码
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

const randomNumber = getRandomInt(1, 10);
console.log(randomNumber); // 1 到 10 之间的随机整数
  • 原理

    • Math.random() 生成一个 [0, 1) 之间的随机小数。
    • 乘以 (max - min + 1) 将范围扩展到 [0, max - min + 1)
    • 使用 Math.floor() 向下取整,得到 [0, max - min] 的整数。
    • 加上 min,将范围调整为 [min, max]

Math.abs(x)

go 复制代码
返回 `x` 的绝对值。

```
console.log(Math.abs(-5)); // 5
```

价格精确度

ini 复制代码
//精确度 封装方法 相加  
export function addFun(num1, num2) {
  var len1 = 0;
  var len2 = 0;
  var m = 0;
  num1=Number(num1)
  num2=Number(num2)
  try {
    len1 = num1.toString().split(".")[1].length;
  } catch (e) {
    len1 = 0;
  }
  try {
    len2 = num2.toString().split(".")[1].length;
  } catch (e) {
    len2 = 0;
  }
  m = Math.pow(10, Math.max(len1, len2));
  var m1 = num1 * m;
  m1 = new Number(m1.toFixed(0));
  var m2 = num2 * m;
  m2 = new Number(m2.toFixed(0));
  return (m1 + m2) / m;

}

//精确度 封装方法 减
export function subtractFun(num1, num2) {
  var len1 = 0;
  var len2 = 0;
  var m = 0;
  num1=Number(num1)
  num2=Number(num2)
  try {
    len1 = num1.toString().split(".")[1].length;
  } catch (e) {
    len1 = 0;
  }
  try {
    len2 = num2.toString().split(".")[1].length;
  } catch (e) {
    len2 = 0;
  }
  m = Math.pow(10, Math.max(len1, len2));
  var m1 = num1 * m;
  m1 = new Number(m1.toFixed(0));
  var m2 = num2 * m;
  m2 = new Number(m2.toFixed(0));
  return (m1 - m2) / m;
}

//精确度 封装方法剩

export function multiplyFun(num1, num2) {
  var len1 = 0;
  var len2 = 0;
  var m = 0;
  num1=Number(num1)
  num2=Number(num2)
  try {
    len1 = num1.toString().split(".")[1].length;
  } catch (e) {
    len1 = 0;
  }
  try {
    len2 = num2.toString().split(".")[1].length;
  } catch (e) {
    len2 = 0;
  }
  m = Math.pow(10, Math.max(len1, len2) + 1);
  var m1 = num1 * m;
  m1 = new Number(m1.toFixed(0));
  var m2 = num2 * m;
  m2 = new Number(m2.toFixed(0));
  var m3 = m * m;
  var m4 = m1 * m2 / m3;
  return m4;

}

// //精确度 封装方法 除
export function divideFun(num1, num2) {
  var len1 = 0;
  var len2 = 0;
  var m = 0;
  num1=Number(num1)
  num2=Number(num2)
  try {
    len1 = num1.toString().split(".")[1].length;
  } catch (e) {
    len1 = 0;
  }
  try {
    len2 = num2.toString().split(".")[1].length;
  } catch (e) {
    len2 = 0;
  }
  m = Math.pow(10, Math.max(len1, len2) + 1);
  var m1 = num1 * m;
  m1 = new Number(m1.toFixed(0));
  var m2 = num2 * m;
  m2 = new Number(m2.toFixed(0));
  var m3 = m1 / m2;
  return m3;
}

把价格转千分位

1. 使用 toLocaleString() 方法

最简单且原生支持的方法,直接调用数字的 toLocaleString() 方法:

ini 复制代码
const number = 1234567.89;
const formatted = number.toLocaleString(); // 输出:"1,234,567.89"(根据系统区域设置)

说明

  • 自动适配本地化格式(如小数点符号、千分位分隔符可能因系统区域不同而变化)。
  • 兼容性好,推荐优先使用。

2. 自定义正则表达式

手动处理整数部分,用正则表达式插入逗号:

ini 复制代码
function formatNumber(num) {
  // 处理小数部分(如果有)
  const parts = num.toString().split('.');
  const integerPart = parts[0].replace(/\B(?=(\d{3})+(?!\d)/g, ',');
  const decimalPart = parts[1] ? '.' + parts[1] : '';
  return integerPart + decimalPart;
}

const number = 1234567.89;
const formatted = formatNumber(number); // 输出:"1,234,567.89"

说明

  • \B(?=(\d{3})+(?!\d)) 正则表达式匹配每三位数字的位置并插入逗号。
  • 完全控制格式,不受区域设置影响。

3. 处理字符串逆序插入逗号

手动从右到左遍历字符串,每三位插入逗号:

ini 复制代码
function formatNumber(num) {
  const str = num.toString().split('.');
  let integerPart = str[0];
  let result = '';
  let counter = 0;

  // 逆序遍历整数部分
  for (let i = integerPart.length - 1; i >= 0; i--) {
    counter++;
    result = integerPart[i] + result;
    if (counter % 3 === 0 && i !== 0) {
      result = ',' + result;
    }
  }

  // 处理小数部分
  const decimalPart = str[1] ? '.' + str[1] : '';
  return result + decimalPart;
}

const number = 1234567.89;
const formatted = formatNumber(number); // 输出:"1,234,567.89"

说明

  • 不依赖正则表达式,直接操作字符串。
  • 代码稍长,但逻辑清晰。

4. 使用 Intl.NumberFormat

更灵活的国际化 API,可指定区域和格式:

ini 复制代码
const number = 1234567.89;
const formatter = new Intl.NumberFormat('en-US'); // 指定为美式格式
const formatted = formatter.format(number); // 输出:"1,234,567.89"

说明

  • 支持更多格式选项(如货币符号、小数位数等)。
  • 语法:new Intl.NumberFormat(locales, options)

总结

方法 优点 缺点
toLocaleString() 最简单,原生支持,兼容性好 依赖系统区域设置
正则表达式 完全控制格式,代码简洁 需要理解正则逻辑
手动逆序处理 不依赖正则,逻辑透明 代码较长
Intl.NumberFormat 国际化支持,高度可配置 语法稍复杂

推荐使用场景

  • 快速实现:优先用 toLocaleString()Intl.NumberFormat
  • 固定格式需求:选择正则表达式或手动逆序处理。

js常见时间方法

方法 返回值说明 示例(假设当前时间 2023-09-25 15:30:45
new Date() 创建当前时间的 Date 对象 2023-09-25T07:30:45.000Z
Date.now() 当前时间的时间戳(毫秒,UTC) 1695634245000
new Date().getTime() 当前时间的时间戳(毫秒,UTC) 1695634245000
new Date().valueOf() 或者 +new Date() 当前时间的时间戳(毫秒,UTC) 1695634245000
Date.parse(dateString) 解析时间字符串返回时间戳(UTC) Date.parse("2023-09-25") → 1695600000000
new Date('2023-09-25').getTime() 当前时间的时间戳(毫秒,UTC) 1695634245000

获取时间各部分

方法 返回值范围 示例结果
getFullYear() 年份(四位数) 2023
getMonth() 月份(0-11) 8(9月)
getDate() 日期(1-31) 25
getDay() 星期(0-6) 1(周一)
getHours() 小时(0-23) 15
getMinutes() 分钟(0-59) 30
getSeconds() 秒(0-59) 45
getMilliseconds() 毫秒(0-999) 0

对象的遍历方式有哪些


总结

方法 描述 是否遍历继承属性 是否遍历 Symbol 属性 是否遍历不可枚举属性
for...in 遍历对象自身的和继承的可枚举属性(不包括 Symbol 属性)
Object.keys() 返回对象自身可枚举属性的键数组
Object.values() 返回对象自身可枚举属性的值数组
Object.entries() 返回对象自身可枚举属性的键值对数组
Object.getOwnPropertyNames() 返回对象自身所有属性的键数组(包括不可枚举属性,不包括 Symbol 属性)
Object.getOwnPropertySymbols() 返回对象自身所有 Symbol 属性的数组
Reflect.ownKeys() 返回对象自身所有属性的键数组(包括 Symbol 属性和不可枚举属性)
for...of + Object.keys/values/entries 结合 Object.keysObject.valuesObject.entries 使用

根据具体需求选择合适的遍历方式,可以有效操作 JavaScript 对象。

手写瀑布流布局

6. 完整代码示例

以下是完整的 HTML、CSS 和 JavaScript 代码:

HTML
html 复制代码
<div class="waterfall-container">
  <div class="waterfall-item">Item 1</div>
  <div class="waterfall-item">Item 2</div>
  <div class="waterfall-item">Item 3</div>
  <div class="waterfall-item">Item 4</div>
  <div class="waterfall-item">Item 5</div>
  <div class="waterfall-item">Item 6</div>
  <div class="waterfall-item">Item 7</div>
  <div class="waterfall-item">Item 8</div>
  <div class="waterfall-item">Item 9</div>
  <div class="waterfall-item">Item 10</div>
</div>
CSS
css 复制代码
.waterfall-container {
  display: flex;
  justify-content: space-between;
  padding: 10px;
}

.waterfall-column {
  flex: 1;
  margin: 0 5px;
}

.waterfall-item {
  background-color: #f0f0f0;
  border: 1px solid #ccc;
  margin-bottom: 10px;
  padding: 10px;
  box-sizing: border-box;
}
JavaScript
javascript 复制代码
function waterfallLayout(containerSelector, itemSelector, columns) {
  const container = document.querySelector(containerSelector);
  const items = document.querySelectorAll(itemSelector);

  container.innerHTML = '';

  const columnElements = [];
  for (let i = 0; i < columns; i++) {
    const column = document.createElement('div');
    column.className = 'waterfall-column';
    container.appendChild(column);
    columnElements.push(column);
  }

  items.forEach(item => {
    let minHeightColumn = columnElements[0];
    columnElements.forEach(column => {
      if (column.offsetHeight < minHeightColumn.offsetHeight) {
        minHeightColumn = column;
      }
    });
    minHeightColumn.appendChild(item.cloneNode(true));
  });
}

waterfallLayout('.waterfall-container', '.waterfall-item', 3);

window.addEventListener('scroll', () => {
  const { scrollTop, clientHeight, scrollHeight } = document.documentElement;
  if (scrollTop + clientHeight >= scrollHeight - 10) {
    loadMoreItems();
  }
});

function loadMoreItems() {
  const container = document.querySelector('.waterfall-container');
  const newItems = [
    '<div class="waterfall-item">New Item 1</div>',
    '<div class="waterfall-item">New Item 2</div>',
    '<div class="waterfall-item">New Item 3</div>',
  ];

  newItems.forEach(item => {
    const div = document.createElement('div');
    div.innerHTML = item;
    container.appendChild(div.firstChild);
  });

  waterfallLayout('.waterfall-container', '.waterfall-item', 3);
}

手写poromise

kotlin 复制代码
class MyPromise {
  constructor(executor) {
    this.status = 'pending'; // 初始状态
    this.value = undefined; // 成功时的值
    this.reason = undefined; // 失败时的原因
    this.onFulfilledCallbacks = []; // 成功回调队列
    this.onRejectedCallbacks = []; // 失败回调队列

    // 定义 resolve 函数
    const resolve = (value) => {
      if (this.status === 'pending') {
        this.status = 'fulfilled'; // 状态改为成功
        this.value = value; // 保存成功值
        // 执行所有成功回调
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    // 定义 reject 函数
    const reject = (reason) => {
      if (this.status === 'pending') {
        this.status = 'rejected'; // 状态改为失败
        this.reason = reason; // 保存失败原因
        // 执行所有失败回调
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

    // 执行 executor
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error); // 如果 executor 抛出错误,直接 reject
    }
  }

  // 实现 then 方法
  then(onFulfilled, onRejected) {
    // 如果 onFulfilled 不是函数,则创建一个默认函数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    // 如果 onRejected 不是函数,则创建一个默认函数
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };

    // 返回一个新的 Promise
    const promise2 = new MyPromise((resolve, reject) => {
      // 如果当前状态是 fulfilled
      if (this.status === 'fulfilled') {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value); // 执行成功回调
            resolvePromise(promise2, x, resolve, reject); // 处理返回值
          } catch (error) {
            reject(error); // 如果回调抛出错误,直接 reject
          }
        }, 0);
      }

      // 如果当前状态是 rejected
      if (this.status === 'rejected') {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason); // 执行失败回调
            resolvePromise(promise2, x, resolve, reject); // 处理返回值
          } catch (error) {
            reject(error); // 如果回调抛出错误,直接 reject
          }
        }, 0);
      }

      // 如果当前状态是 pending
      if (this.status === 'pending') {
        // 将回调函数加入队列
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value); // 执行成功回调
              resolvePromise(promise2, x, resolve, reject); // 处理返回值
            } catch (error) {
              reject(error); // 如果回调抛出错误,直接 reject
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason); // 执行失败回调
              resolvePromise(promise2, x, resolve, reject); // 处理返回值
            } catch (error) {
              reject(error); // 如果回调抛出错误,直接 reject
            }
          }, 0);
        });
      }
    });

    return promise2;
  }
}

// 处理 then 返回值的函数
function resolvePromise(promise2, x, resolve, reject) {
  // 如果 promise2 和 x 是同一个对象,抛出 TypeError
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }

  // 如果 x 是一个 Promise
  if (x instanceof MyPromise) {
    x.then(resolve, reject);
  } else {
    // 否则直接 resolve
    resolve(x);
  }
}
相关推荐
Moment2 小时前
从方案到原理,带你从零到一实现一个 前端白屏 检测的 SDK ☺️☺️☺️
前端·javascript·面试
野生的程序媛2 小时前
重生之我在学Vue--第5天 Vue 3 路由管理(Vue Router)
前端·javascript·vue.js
鱼樱前端2 小时前
Vue 2 与 Vue 3 响应式原理详细对比
javascript·vue.js
codingandsleeping3 小时前
前端工程化之模块化
前端·javascript
CodeCraft Studio3 小时前
报表控件stimulsoft操作:使用 Angular 应用程序的报告查看器组件
前端·javascript·angular.js
Liigo4 小时前
初次体验Tauri和Sycamore(3)通道实现
javascript·rust·electron·tauri·channel·sycamore
烛阴4 小时前
JavaScript 性能提升秘籍:WeakMap 和 WeakSet 你用对了吗?
前端·javascript
专注VB编程开发20年5 小时前
JS采集数据爬虫-Fetch API 和 XMLHttpRequest 有什么区别?
开发语言·javascript·爬虫·js
鱼樱前端5 小时前
Vue 2 与 Vue 3 语法区别完整对比
前端·javascript·vue.js
萌萌哒草头将军5 小时前
🚀🚀🚀 服务器防吃灰指南(二) !
java·服务器·javascript