【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))` ![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a8248f9771b640f18a2d4dd8de7ae93b~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp) ## 从这个简单例子来看,`new`操作符做了两件事: 1. 创建了一个全新的对象。 2. 这个对象会被执行`[[Prototype]]`(也就是`__proto__`)链接。 ## promise和async区别 * promise是个`对象Es6语法`,async是个`函数`,es7语法 * promise 处理异步是另一种`地狱回调`,`async是测底拉平`,更加优雅 * async的底层是promise ## **事件捕捉** **与冒** **泡模型** ![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f15e5763991c4b5492b45bbdfa57e060~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp) ![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/67b9e94f570a4bff8a46101d717336b1~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp) ![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a049cdc4b32346acad7b0f4174e045b6~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp) ![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9f578e73f3404327b1216f89affa7a7a~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp) ### 如何阻止事件冒泡? ie:阻止冒泡ev.cancelBubble = true; 非IE ev.stopPropagation(); ### 如何阻止默认事件? (1)return false;(2) ev.preventDefault(); ### Javascript的事件流模型都有什么? "事件捕捉":是从上往下,window,document,document.documentelment(获取的html) document,body 、........目标元素 "事件冒泡":是从下往上:反之 "DOM事件流":三个阶段:事件捕捉、目标阶段、事件冒泡 ![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/da8d4d7142bf4d0bb5d5fc8a624790a6~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp) ## null和undefined的区别? **nul** l是一个**表示"无"的对象** ,**转为数值时为0** ; **undefined** 是一个表示"无"的**原始值** ,**转为数值时为NaN** 。 当声明的变量还未被初始化时,变量的默认值为undefined。 null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。 ## post 和get 区别 ![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/61dc6c5ada8b4c41812d86cbd7d56e50~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp) ## 前端性能值有哪些,如何量化 ### 首次内容绘制【 **First Contentful Paint, FCP**】 * **定义**: 浏览器首次渲染DOM内容的时间。 * **量化** : 通过`PerformanceObserver`API监测`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.timing`或`PerformanceObserver`监测`responseStart`和`requestStart`的差值。 ### 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 ` ## XSS攻击 一种通过向网页注入恶意脚本(如JavaScript、HTML、CSS等)实现攻击的网络安全漏洞 ### **防御XSS攻击的关键措施** 1. **输入过滤与转义** * 对用户输入内容进行严格过滤,使用`htmlspecialchars()`或`htmlentities()`等函数转义特殊字符(如`<`、`>`、`&`)[1](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fmeism5%2Farticle%2Fdetails%2F90414134 "https://blog.csdn.net/meism5/article/details/90414134")[2](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43681537%2Farticle%2Fdetails%2F84585554 "https://blog.csdn.net/weixin_43681537/article/details/84585554")。 * **示例** :PHP中`htmlspecialchars($input, ENT_QUOTES)`可转义单双引号。 2. **输出编码** * 在将数据输出到页面时,根据上下文(HTML、JavaScript、CSS)选择合适的编码方式[5](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_30929195%2Farticle%2Fdetails%2F97704632 "https://blog.csdn.net/weixin_30929195/article/details/97704632")。 3. **设置安全HTTP头部** * 启用`X-XSS-Protection`头部强制浏览器启用XSS过滤[3](https://link.juejin.cn?target=https%3A%2F%2Fruokouling.com%2Fask%2Fwhat-is-xss-attack.html "https://ruokouling.com/ask/what-is-xss-attack.html")。 * 使用`Content-Security-Policy (CSP)`限制脚本来源[5](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_30929195%2Farticle%2Fdetails%2F97704632 "https://blog.csdn.net/weixin_30929195/article/details/97704632")。 4. **使用HttpOnly Cookie** * 为敏感Cookie设置`HttpOnly`属性,阻止JavaScript访问,降低信息泄露风险[1](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fmeism5%2Farticle%2Fdetails%2F90414134 "https://blog.csdn.net/meism5/article/details/90414134")[6](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_40780243%2Farticle%2Fdetails%2F108898229 "https://blog.csdn.net/weixin_40780243/article/details/108898229")。 5. **避免内联脚本与动态DOM操作** * 减少使用`eval()`、`innerHTML`等高风险API,优先通过文本节点操作DOM[6](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_40780243%2Farticle%2Fdetails%2F108898229 "https://blog.csdn.net/weixin_40780243/article/details/108898229")。 ## CSRF攻击是什么? 是一种利用用户在`已登录状态下对目标网站的信任`,通过`诱导`用户触发`恶意请求`的攻击方式。攻击者`伪造用户的身份,执行非用户本意的敏感操作`(如转账、修改密码等 ### 预防 **Token 验证** 、**SameSite Cookie** 、**双重认证** 和 **请求来源校验** 等 ### **与 XSS 攻击的区别** | **特性** | **XSS 攻击** | **CSRF 攻击** | |----------|-------------|---------------| | **利用对象** | 利用用户对网站的信任 | 利用网站对用户浏览器的信任 | | **攻击目标** | 窃取用户数据或劫持会话 | 伪造用户身份执行敏感操作 | | **防御重点** | 过滤用户输入与输出 | 校验请求来源与身份 | ## 三栏布局的实现方案有哪些? 浮动布局、flex布局、绝对定位布局、grid布局`grid-template-columns` 定义三列,中间自适应、圣杯/双飞翼布局 ## 变量提升 JavaScript **预编译阶段的特性** ,表现为**变量和函数的声明** 会被**隐式提升** 到当前**作用域(全局或函数作用域)的顶端** ,但**赋值操作**仍保留在原位置 ## 一个图片 url 访问后直接下载怎样实现? ### **HTML的`download`属性** 在``标签中添加`download`属性,浏览器会直接下载文件: ```ini 下载图片 ``` ### **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) ``` *** ** * ** *** ### **Navigator 对象**(浏览器信息) #### **浏览器识别** ```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` :获取屏幕分辨率[4](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_33806509%2Farticle%2Fdetails%2F93203542 "https://blog.csdn.net/weixin_33806509/article/details/93203542")[9](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fcainiaoyihao_%2Farticle%2Fdetails%2F117883001 "https://blog.csdn.net/cainiaoyihao_/article/details/117883001") * `screen.availWidth`/`screen.availHeight` :获取可用屏幕尺寸(排除任务栏)[9](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fcainiaoyihao_%2Farticle%2Fdetails%2F117883001 "https://blog.csdn.net/cainiaoyihao_/article/details/117883001")[10](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fqq_34771938%2Farticle%2Fdetails%2F120353624 "https://blog.csdn.net/qq_34771938/article/details/120353624") ## 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文档的``区域添加以下meta标签来禁用双击缩放功能: ```ini ``` 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.keys`、`Object.values` 或 `Object.entries` 使用 | 否 | 否 | 否 | 根据具体需求选择合适的遍历方式,可以有效操作 JavaScript 对象。 ## 手写瀑布流布局 #### 6. **完整代码示例** 以下是完整的 HTML、CSS 和 JavaScript 代码: ##### HTML ```html

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
``` ##### 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 = [ '
New Item 1
', '
New Item 2
', '
New Item 3
', ]; 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); } } ```

相关推荐
上单带刀不带妹28 分钟前
手写 Vue 中虚拟 DOM 到真实 DOM 的完整过程
开发语言·前端·javascript·vue.js·前端框架
前端风云志30 分钟前
typescript结构化类型应用两例
javascript
gnip2 小时前
总结一期正则表达式
javascript·正则表达式
爱分享的程序员2 小时前
前端面试专栏-算法篇:18. 查找算法(二分查找、哈希查找)
前端·javascript·node.js
翻滚吧键盘2 小时前
vue 条件渲染(v-if v-else-if v-else v-show)
前端·javascript·vue.js
你这个年龄怎么睡得着的2 小时前
为什么 JavaScript 中 'str' 不是对象,却能调用方法?
前端·javascript·面试
南屿im2 小时前
JavaScript 手写实现防抖与节流:优化高频事件处理的利器
前端·javascript
西陵3 小时前
Nx带来极致的前端开发体验——借助CDD&TDD开发提效
前端·javascript·架构
叹一曲当时只道是寻常3 小时前
vue中添加原生右键菜单
javascript·vue.js
旷世奇才李先生3 小时前
Next.js 安装使用教程
开发语言·javascript·ecmascript