关于javascript:jsliang-求职系列-JavaScript-基础

8次阅读

共计 16849 个字符,预计需要花费 43 分钟才能阅读完成。

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 前言
三 DOM 罕用 API
四 null 和 undefined 的区别
五 事件流
 5.1 addEventListener
 5.2 原理
 5.3 案例
 5.4 练习题
 5.5 阻止冒泡
 5.6 onmouseover 和 onmouseenter 区别
 5.7 科普
六 typeof 和 instanceof 的区别
七 一句话形容 this
八 JS 地位
九 JS 拖拽
十 setTimeout 实现 setInterval
十一 实现 Sleep
十二 执行上下文
 12.1 执行上下文类型
 12.2 执行栈
十三 函数式编程
 13.1 函数式编程特点
 13.2 纯函数
十四 渐进式网络应用(PWA)
 14.1 长处
 14.2 毛病
十五 规范化
 15.1 CommonJS 标准
 15.2 AMD 标准
 15.3 CMD 标准
 15.4 ES6 Modules 标准
十六 babel 编译原理
十七 题集
 17.1 数组常见 API
 17.2 常见 DOM API
 17.3 数组去重
 17.4 数字化金额
 17.5 遍历问题
 17.6 setTimeout
 17.7 requestAnimationFrame
 17.8 暂时性死区
 17.9 输入打印后果
 17.10 输入打印后果
 17.11 Event Loop
 17.12 输入打印后果
 17.13 使 a == 1 && a == 2 成立
十八 More

二 前言

返回目录

在 JavaScript 温习过程中,可能会碰到:

  1. nullundefined 的区别?
  2. addEventListener 函数?

这样杂七杂八的问题,亦或者 a == 1 && a == 2 这样乏味的问题。

将它们归类到 JavaScript 根底,并在本篇文章中一一讲述。

同时,会有十几道简略题目练手。

三 DOM 罕用 API

返回目录

能够应用 documentwindow 元素的 API 来操作文档自身或获取文档的子类(Web 页面中的各种元素)。

// 获取元素
const node = document.getElementById(id); // 或者 querySelector(".class|#id|name");

// 创立元素
const heading = document.createElement(name); // name: p、div、h1...
heading.innerHTML = '';

// 增加元素
document.body.appendChild(heading);

// 删除元素
document.body.removeChild(node);

示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>DOM 操作 </title>
  <style>
    div {
      border: 1px solid #ccc;
      padding: 50px;
      width: 100px;
    }
  </style>
</head>
<body>
  <div id="dom1"> 元素 1</div>
  <div class="dom2"> 元素 2</div>
  
  <button class="btn"> 点我 </button>

  <script>
    (function() {const btn = document.querySelector('.btn');

      // 注册点击事件
      btn.onclick = function() {const dom1 = document.getElementById('dom1');

        // 第一种增加元素
        const newDom1 = document.createElement('p');
        newDom1.innerHTML = '<a href="https://github.com/LiangJunrong/document-library">jsliang 的文档库 </a>';
        dom1.appendChild(newDom1);

        // 第二种增加元素
        const newDom2 = document.createElement('ul');
        newDom2.innerHTML = `
          <li>aaa</li>
          <li>bbb</li>
        `;
        document.body.appendChild(newDom2);

        // 移除元素
        const dom2 = document.querySelector('.dom2');
        document.body.removeChild(dom2);
      }
    })()
  </script>
</body>
</html>

四 null 和 undefined 的区别

返回目录

  • null 示意 的对象,也就是此处不应该有值;而 undefined 示意未定义。
  • 在转换数字的时候,Number(null)0,而 Number(undefined)NaN

应用场景细分如下:

  • null
  1. 作为函数的参数,示意该函数的参数不是对象。
  2. 作为对象原型链的起点。Object.prototype.__proto__ === null
  • undefined
  1. 变量被申明然而没有赋值,等于 undefined
  2. 调用函数时,对应的参数没有提供,也是 undefined
  3. 对象没有赋值,这个属性的值为 undefined
  4. 函数没有返回值,默认返回 undefined

五 事件流

返回目录

什么是事件流:事件流形容的是从页面中接管事件的程序,DOM 2 级事件流包含上面几个阶段。

  • 事件捕捉阶段
  • 处于指标阶段
  • 事件冒泡阶段

如何让事件先冒泡后捕捉:

DOM 规范事件模型中,是先捕捉后冒泡。然而如果要实现先冒泡后捕捉的成果,对于同一个事件,监听捕捉和冒泡,别离对应相应的处理函数,监听到捕捉事件,先暂缓执行,直到冒泡事件被捕捉后再执行捕捉之间。

5.1 addEventListener

返回目录

addEventListener 办法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。

addEventListener 事件指标能够是文档上的元素 ElementDocumentWindow 或者任何其余反对事件的对象(例如 XMLHttpRequest)。

参考文档:EventTarget.addEventListener – MDN

  • 语法:target.addEventListener(type, listener, options/useCapture)
  1. type:示意监听事件类型的字符串
  2. listener:所监听的事件触发,会承受一个事件告诉对象。
  3. options:一个指定无关 listener 属性的可选参数对象。可选值有 capture(事件捕捉阶段流传到这里触发)、once(在 listener 增加之后最多值调用一次)、passive(设置为 true 时示意 listener 永远不会调用 preventDefault())。
  4. useCapture:在 DOM 树中,注册了 listener 的元素,是否要先于它上面的 EventTarget 调用该 listener

addEventListener 的第三个参数波及到冒泡和捕捉,为 true 时是捕捉,为 false 时是冒泡。

或者是一个对象 {passive: true},针对的是 Safari 浏览器,禁止 / 开启应用滚动的时候要用到

  • 示例
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title> 监听器 </title>
</head>
<body>
  <table id="outside">
    <tr><td id="t1">one</td></tr>
    <tr><td id="t2">two</td></tr>
  </table>

  <script>
    (function() {
      // 增加函数
      const modifyText = (text) => {const t2 = document.querySelector('#t2');
        if (t2.firstChild.nodeValue === text) {t2.firstChild.nodeValue = 'two';} else {t2.firstChild.nodeValue = text;}
      }

      // 给 Table 增加事件监听器
      const element = document.querySelector('#outside');
      element.addEventListener('click', function() {modifyText('four') }, false);
    })()
  </script>
</body>
</html>

如上,这个示例简略实现了点击 two 切换到 four,点击 four 再切换到 two 的成果。

5.2 原理

返回目录

事件捕捉和事件冒泡别离是 网景(Netscape)和 IEDOM 事件产生程序的形容。

网景 认为 DOM 接管的事件应该最先是 window,而后到 document,接着一层一层往下,最初才到具体的元素接管到事件,即 事件捕捉

IE 则认为 DOM 事件应该是具体元素先接管到,而后再一层一层往上,接着到 document,最初才到 window,即 事件冒泡

最初 W3C 对这两种计划进行了对立:将 DOM 事件分为两个阶段,事件捕捉和事件冒泡阶段。

当一个元素被点击,首先是事件捕捉阶段,window 最先接管事件,而后一层一层往下捕捉,最初由具体元素接管;之后再由具体元素再一层一层往上冒泡,到 window 接管事件。

所以:

  • 事件冒泡:当给某个指标元素绑定了事件之后,这个事件会顺次在它的父级元素中被触发(当然前提是这个父级元素也有这个同名称的事件,比方子元素和父元素都绑定了 click 事件就触发父元素的 click)。
  • 事件捕捉:和冒泡相同,会从下层传递到上层。

5.3 案例

返回目录

联合自定义事件耍个例子:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title> 自定义事件 </title>
</head>
<body>
  <ul class="ul">
    <li class="li">
      <button class="btn"> 点我 </button>
    </li>
  </ul>
  
  <script>
    window.onload = function() {const myEvent = document.createEvent('CustomEvent');
      myEvent.initEvent('myEvent', true, true);

      const btn = document.querySelector('.btn');
      btn.addEventListener('myEvent', function(e) {console.log('button');
      })

      const li = document.querySelector('.li');
      li.addEventListener('myEvent', (e) => {console.log('li');
      })

      const ul = document.querySelector('.ul');
      li.addEventListener('myEvent', (e) => {console.log('ul');
      })

      document.addEventListener('myEvent', (e) => {console.log('document');
      })

      window.addEventListener('myEvent', (e) => {console.log('window');
      })

      setTimeout(() => {btn.dispatchEvent(myEvent);
      }, 2000);
    };
  </script>
</body>
</html>

Chrome 输入下程序是:button -> li -> ul -> document -> window

如果是捕捉的话,那么则相同。

5.4 练习题

返回目录

点击一个 input 顺次触发的事件

const text = document.getElementById('text');

text.onclick = function (e) {console.log('onclick')
}
text.onfocus = function (e) {console.log('onfocus')
}
text.onmousedown = function (e) {console.log('onmousedown')
}
text.onmouseenter = function (e) {console.log('onmouseenter')
}

正确程序是:onmouseenter -> onmousedown -> onfocus -> onclick

如果加上 onmouseup,那就是:

  • onmouseenter -> onmousedown -> onfocus -> onmouseup -> onclick

5.5 阻止冒泡

返回目录

  • event.stopPropagation();
btn.addEventListener('myEvent', function(e) {console.log('button');
  event.stopPropagation();})

通过阻止冒泡,程序只会输入 button,而不会持续输入 li 等。

5.6 onmouseover 和 onmouseenter 区别

返回目录

这两者都是移入的时候触发,然而 onmouseover 会触发屡次,而 onmouseenter 只在进去的时候才触发。

5.7 科普

返回目录

并不是所有的事件都有冒泡,例如:

  • onblur
  • onfocus
  • onmouseenter
  • onmouseleave

六 typeof 和 instanceof 的区别

返回目录

  • typeof:对某个变量类型的检测,根本类型除了 null 之外,都能失常地显示为对应的类型,援用类型除了函数会显示为 function,其余都显示为 object
  • instanceof 次要用于检测某个构造函数的原型对象在不在某个对象的原型链上。

typeof 会对 null 显示谬误是个历史 Bug,typeof null 输入的是 object,因为 JavaScript 早起版本是 32 位零碎,为了性能思考应用低位存储变量的类型信息,000 结尾代表是对象然而 null 示意为全零,所以它错误判断为 object

另外还有 Object.prototype.toString.call() 进行变量判断。

具体可见:JavaScript – 变量

七 一句话形容 this

返回目录

对于函数而言,指向最初调用函数的那个对象,是函数运行时外部主动生成的一个外部对象,只能在函数外部应用;对于全局而言,this 指向 window

八 JS 地位

返回目录

  • clientHeight:示意可视区域的高度,不蕴含 border 和滚动条
  • offsetHeight:示意可视区域的高度,蕴含了 border 和滚动条
  • scrollHeight:示意了所有区域的高度,蕴含了因为滚动被暗藏的局部
  • clientTop:示意边框 border 的厚度,在未指定的状况下个别为0
  • scrollTop:滚动后被暗藏的高度,获取对象绝对于由 offsetParent 属性指定的父坐标(CSS 定位的元素或 body 元素)间隔顶端的高度。

九 JS 拖拽

返回目录

  1. 通过 mousedownmousemovemouseup 办法实现
  2. 通过 HTML5 的 DragDrop 实现

十 setTimeout 实现 setInterval

返回目录

这算另类知识点吧,原本打算归类手写源码系列的,然而想想太 low 了,没牌面,入根底系列吧:

const say = () => {
  // do something
  setTimeout(say, 200);
};

setTimeout(say, 200);

革除这个定时器:

let i = 0;

const timeList = [];

const say = () => {
  // do something
  console.log(i++);
  timeList.push(setTimeout(say, 200));
};

setTimeout(say, 200);

setTimeout(() => {for (let i = 0; i < timeList.length; i++) {clearTimeout(timeList[i]);
  }
}, 1000);

十一 实现 Sleep

返回目录

如下,实现 1000 毫秒后执行其余内容:

const sleep = time => {return new Promise((resolve, reject) => {setTimeout(() => {resolve(time);
    }, time);
  });
};

sleep(1000).then((res) => {console.log(res);
});

十二 执行上下文

返回目录

12.1 执行上下文类型

返回目录

JavaScript 中有 3 种执行上下文类型:

  • 全局执行上下文:这是默认或者说根底的上下文,任何不在函数外部的代码都在全局上下文中。它会执行两件事:创立一个全局的 window 对象(浏览器的状况下),并且设置 this 的值等于这个全局对象。一个程序中只会有一个全局执行上下文。
  • 函数执行上下文:每当一个函数被调用时, 都会为该函数创立一个新的上下文。每个函数都有它本人的执行上下文,不过是在函数被调用时创立的。函数上下文能够有任意多个。每当一个新的执行上下文被创立,它会按定义的程序执行一系列步骤。
  • Eval 函数执行上下文:执行在 eval 函数外部的代码也会有它属于本人的执行上下文,但因为 JavaScript 开发者并不常常应用 eval,所以在这里我不会探讨它。

12.2 执行栈

返回目录

执行栈,也就是在其它编程语言中所说的“调用栈”,是一种领有 LIFO(后进先出)数据结构的栈,被用来存储代码运行时创立的所有执行上下文。

当 JavaScript 引擎第一次遇到你的脚本时,它会创立一个全局的执行上下文并且压入以后执行栈。每当引擎遇到一个函数调用,它会为该函数创立一个新的执行上下文并压入栈的顶部。

引擎会执行那些执行上下文位于栈顶的函数。当该函数执行完结时,执行上下文从栈中弹出,管制流程达到以后栈中的下一个上下文。

let a = 'Hello World!';

function first() {console.log('Inside first function');
  second();
  console.log('Again inside first function');
}

function second() {console.log('Inside second function');
}

first();
console.log('Inside Global Execution Context');

十三 函数式编程

返回目录

函数式编程(Functional Programming,简称 FP)。

函数式编程:通过对面向对象式编程代码的拆分,将各个性能独立进去,从而达到性能独立、易复用等目标。

举例:代码转换

['john-reese', 'harold-finch', 'sameen-shaw'] 
// 转换成 
[{name: 'John Reese'}, {name: 'Harold Finch'}, {name: 'Sameen Shaw'}]

对下面代码进行转换。

const arr = ['john-reese', 'harold-finch', 'sameen-shaw'];
const newArr = [];
for (let i = 0, len = arr.length; i < len ; i++) {let name = arr[i];
  let names = name.split('-');
  let newName = [];
  for (let j = 0, naemLen = names.length; j < naemLen; j++) {let nameItem = names[j][0].toUpperCase() + names[j].slice(1);
    newName.push(nameItem);
  }
  newArr.push({name : newName.join(' ') });
}
return newArr;

这份代码中,有 2 个局部:

  1. 拆分数组中字符串,将字符串变成人名。john-reese -> John Reese
  2. 将数组转换成对象。['John Reese'] -> [{name: 'John Reese'}]

所以咱们间接能够改变:

/**
 * @name 扭转人名展现形式
 * @param {array} arr 须要扭转的数组
 * @param {string} type 反对不同格局的人名
 */
const changeName = (arr, type) => {return arr.map(item => item.split(type).map(name => name[0].toUpperCase() + name.slice(1)).join(' '));
};

/**
 * @name 数组扭转成对象
 * @param {array} arr 须要扭转的数组
 * @param {string} key 对应变成什么字段
 * @return {object} 返回扭转后的对象
 */
const arrToObj = (arr, key) => {return arr.map(item => ({ [key]: item }));
};

const result = arrToObj(changeName(['john-reese', 'harold-finch', 'sameen-shaw'], '-'), 'name');
console.log(result); // [{ name: 'John Reese'}, {name: 'Harold Finch'}, {name: 'Sameen Shaw'} ]

嗨,这不就是对性能封装吗?一般来说工作中呈现 2 次以上的代码才进行封装。

函数式编程就是对能够抽离的性能都进行抽取封装。

到这里好像把握了真谛,jsliang 也没具体理解定义撒,心愿没误导。

13.1 函数式编程特点

返回目录

  1. 函数是一等公民。能够利用这点让它反对抽取到内部。
  2. 申明做某件工夫。函数式编程大多数申明某个函数须要做什么,而不是它怎么做的。
  3. 便于垃圾回收。函数外部的变量不便垃圾回收,不会产生太多的变量,用户不须要大量的定义。
  4. 数据不可变。函数式编程要求所有的数据都是不可变的,如果须要批改某个对象,应该新建后再批改,而不是净化本来的数据。
  5. 无状态。不论什么时候运行,同一个函数对雷同的输出返回雷同的输入,而不依赖内部状态的变动。
  6. 无副作用。性能 A 应该仅仅为了实现它的实现,而不会随着内部的扭转而扭转,这样当它执行结束之后,就能够将其外部数据进行回收。并且它不会批改传入的参数。

重视援用值(Object、Array)的传递,尽可能不要净化传入的数据。

13.2 纯函数

返回目录

纯函数的概念有 2 点:

  1. 不依赖内部状态(无状态):函数的运行后果不依赖全局变量,this 指针,IO 操作等。
  2. 没有副作用(数据不变):不批改全局变量,不批改入参。

长处:

  • 便于测试和优化
  • 可缓存性
  • 自文档化
  • 更少 Bug

十四 渐进式网络应用(PWA)

返回目录

渐进式网络应用(PWA)是谷歌在 2015 年底提出的概念。基本上算是 Web 应用程序,但在外观和感觉上与原生 App 相似。反对 PWA 的网站能够提供脱机工作、推送告诉和设施硬件拜访等性能。

14.1 长处

返回目录

  • 更小更快: 渐进式的 Web 应用程序比原生应用程序小得多。他们甚至不须要装置。这是他们没有节约磁盘空间和加载速度十分快。
  • 响应式界面: PWA 反对的网页可能主动适应各种屏幕大小。它能够是手机、平板、台式机或笔记本。
  • 无需更新: 大多数挪动应用程序须要每周定期更新。与一般网站一样,每当用户交互产生且不须要应用程序或游戏商店批准时,PWA 总是加载最新更新版本。
  • 高性价比:原生挪动利用须要别离为 Android 和 iOS 设施开发,开发成本十分高。另一方面,PWA 有着雷同的性能,但只是先前价格的一小部分,开发成本低。
  • SEO 劣势:搜索引擎能够发现 PWA,并且加载速度十分快。就像其余网站一样,它们的链接也能够共享。提供良好的用户体验和后果,在 SEO 排名进步。
  • 脱机性能:因为 Service Worker API 的反对,能够在脱机或低 internet 连贯中拜访 PWAs。
  • 安全性:PWA 通过 HTTPS 连贯传递,并在每次交互中爱护用户数据。
  • 推送告诉:通过推送告诉的反对,PWA 轻松地与用户进行交互,提供十分棒的用户体验。
  • 绕过利用商店:原生 App 如果须要任何新的更新,须要利用商店几天的审批,且有被回绝或禁止的可能性,对于这方面来说,PWA 有它独特的劣势,不须要 App Store 反对。更新版本能够间接从 Web 服务器加载,无需 App Store 批准。
  • 零装置:在浏览过程中,PWA 会在手机和平板电脑上有本人的图标,就像挪动应用程序一样,但不须要通过简短的装置过程。

14.2 毛病

返回目录

  • 对系统性能的拜访权限较低:目前 PWA 对本机系统性能的拜访权限比原生 App 无限。而且,所有的浏览器都不反对它的全副性能,但可能在不久的未来,它将成为新的开发规范。
  • 少数 Android,多数 iOS:目前更多的反对来自 Android。iOS 零碎只提供了局部。
  • 没有审查规范:PWA 不须要任何实用于利用商店中本机利用的审查,这可能会加快进程,但不足从应用程序商店中获取推广效益。

十五 规范化

返回目录

CommonJS 标准、AMD 标准、CMD 标准、ES6 Modules 标准这 4 者都是前端规范化的内容,那么它们之间区别是啥呢?

在没有这些之前,咱们通过:

  • 一个函数就是一个模块。function fn() {}
  • 一个对象就是一个模块。let obj = new Object({...})
  • 立刻执行函数(IIFE)。(function() {})()

15.1 CommonJS 标准

返回目录

这之后,就有了 CommonJS 标准,其实 CommonJS 咱们见得不少,就是 Node 的那套:

  • 导出:module.exports = {}exports.xxx = 'xxx'
  • 导入:require(./index.js)
  • 查找形式:查找当前目录是否具备文件,没有则查找当前目录的 node_modules 文件。再没有,冒泡查问,始终往零碎中的 npm 目录查找。

它的特点:

  1. 所有代码在模块作用域内运行,不会净化其余文件
  2. require 失去的值是值的拷贝,即你援用其余 JS 文件的变量,批改操作了也不会影响其余文件

它也有本人的缺点:

  1. 利用层面。在 index.html 中做 var index = require('./index.js') 操作报错,因为它最终是后盾执行的,只能是 index.js 援用 index2.js 这种形式。
  2. 同步加载问题。CommonJS 标准中模块是同步加载的,即在 index.js 中加载 index2.js,如果 index2.js 卡住了,那就要等很久。

15.2 AMD 标准

返回目录

为什么有 AMD 标准?

答:CommonJS 标准不中用:

  1. 实用客户端
  2. 期待加载(同步加载问题)。

所以它做了啥?

能够采纳异步形式加载模块。AMDAsynchronous Module Definition 的缩写,也就是“异步模块定义”,记住这个 async 就晓得它是异步的了。

15.3 CMD 标准

返回目录

CMD (Common Module Definition), 是 seajs 推崇的标准,CMD 则是依赖就近,用的时候再 require

AMD 和 CMD 最大的区别是对依赖模块的执行机会解决不同,留神不是加载的机会或者形式不同,二者皆为异步加载模块。

15.4 ES6 Modules 标准

返回目录

  • 导出:
  1. export a
  2. export {a}
  3. export {a as jsliang}
  4. export default function() {}
  • 导入:
  1. import './index'
  2. import {a} from './index.js'
  3. import {a as jsliang} from './index.js'
  4. import * as index from './index.js'

特点:

  1. export 命令和 import 命令能够呈现在模块的任何地位,只有处于模块顶层就能够。如果处于块级作用域内,就会报错,这是因为处于条件代码块之中,就没法做动态优化了,违反了 ES6 模块的设计初衷。
  2. import 命令具备晋升成果,会晋升到整个模块的头部,首先执行。

CommonJS 区别:

  • CommonJS 模块是运行时加载,ES6 Modules 是编译时输入接口
  • CommonJS 输入是值的拷贝;ES6 Modules 输入的是值的援用,被输出模块的外部的扭转会影响援用的扭转
  • CommonJs 导入的模块门路能够是一个表达式,因为它应用的是require() 办法;而 ES6 Modules 只能是字符串
  • CommonJS this 指向以后模块,ES6 Modulesthis 指向 undefined
  • ES6 Modules 中没有这些顶层变量:argumentsrequiremoduleexports__filename__dirname

十六 babel 编译原理

返回目录

  • babylonES6/ES7 代码解析成 AST
  • babel-traverseAST 进行遍历转译,失去新的 AST
  • AST 通过 babel-generator 转换成 ES5

这一块的话 jsliang 并没有过分深究,单纯了解的话还是容易了解的:

  1. 黑白七巧板组成的形态,拆分进去失去整机(ES6/ES7 解析成 AST
  2. 将这些整机换成黑白的(AST 编译失去新 AST
  3. 将黑白整机拼装成新的形态(AST 转换为 ES5

十七 题集

返回目录

17.1 数组常见 API

返回目录

  • push:数组尾部增加元素
  • unshift:数组头部增加元素
  • pop:数组尾部移除元素
  • shift:数组头部移除元素
  • splice:删除数组元素
  • slice:截取数组元素
  • indexOf:查找某元素第一次呈现的地位
  • lastIndexof:查找某元素最初一次呈现的地位
  • findIndex:查找元素第一次呈现的地位
  • forEach:遍历元素
  • map:遍历元素
  • filter:过滤元素
  • some:蕴含某元素
  • every:所有元素和某元素统一
  • includes:查看是否蕴含某元素
  • concat:合并元素
  • join:合并元素,变成字符串
  • toString:变成字符串
  • sort:元素排序

17.2 常见 DOM API

返回目录

  • 获取
  • 创立
  • 增加
  • 删除
// 获取元素
const node = document.getElementById(id); // 或者 querySelector(".class|#id|name");

// 创立元素
const heading = document.createElement(name); // name: p、div、h1...
heading.innerHTML = '';

// 增加元素
document.body.appendChild(heading);

// 删除元素
document.body.removeChild(node);

17.3 数组去重

返回目录

数组去重是个常常提及的点:

const arr = [1, 1, 2, 3, 3];
// 冀望失去:[1, 2, 3]

// 办法一:for 配合新数组截取
const newArr1 = [];
for (let i = 0; i < arr.length; i++) {if (!newArr1.includes(arr[i])) {newArr1.push(arr[i]); 
  }
}
console.log('newArr1:', newArr1);

// 办法二:应用 Set
const newArr2 = [...new Set(arr)];
console.log('newArr2:', newArr2);

// 办法三:应用 filter
const newArr3 = arr.filter((item, index) => arr.lastIndexOf(item) === index);
console.log('newArr3:', newArr3);

有一次面试碰到的有意思的发问是:不应用数组 API 进行去重。

留神:不能应用 pushindexOfAPI

17.4 数字化金额

返回目录

  • 办法一:暴力遍历
const num = String(1234567890);
let result = '';

for (let i = num.length - 1; i >= 0; i--) {if (i !== num.length - 1 && i % 3 === 0) {result = num[i] + ',' + result;
  } else {result = num[i] + result;
  }
}

console.log(result);
  • 办法二:API 技巧
console.log(String(1234567890).split('').reverse().reduce((prev, next, index) => (index % 3) === 0 ? next +',' + prev : next + prev)
);
  • 办法三:API 技巧
console.log((1234567890).toLocaleString('en-US')
);
  • 办法四:正则表达式
String(1234567890).replace(/\B(?=(\d{3})+(?!\d))/g, ',');

17.5 遍历问题

返回目录

以下代码执行后,array 的后果是?

let array = [, 1, , 2, , 3];
array = array.map((i) => ++i)
  • A:[, 2, , 3, , 4]
  • B:[NaN, 2, NaN, 3, NaN, 4]
  • C:[1, 2, 1, 3, 1, 4]
  • D:[null, 2, null, 3, null, 4]

答案:A

解释:

  1. forEach()filter()reduce()every()some() 都会跳过空位。
  2. map() 会跳过空位,但会保留这个值
  3. join()toString() 会将空位视为 undefined,而 undefinednull 会被解决成空字符串。

17.6 setTimeout

返回目录

for (var i = 0; i < 5; i++) {setTimeout(() => {console.log(i);
  }, 1000);
}

以上代码执行后果?

  • A:5 5 5 5 5
  • B:0 0 0 0 0
  • C:0 1 2 3 4
  • D:1 2 3 4 5

答案:A

解析:

  1. var ifor 中应用,会造成变量净化,从而导致全局有一个遍历 i,这个 i 运行到最初,就是 5
  2. setTimeout 是宏工作,在 script 这个宏工作执行结束后才执行,所以收集到的 i5
  3. 最终输入 5 个 5

17.7 requestAnimationFrame

返回目录

for (let i = 0; i < 5; i++) {requestAnimationFrame(() => {console.log(i);
  });
}

以上代码执行后果:

  • A:1 2 3 4 5
  • B:0 1 2 3 4
  • C:4 4 4 4 4
  • D:5 5 5 5 5

答案:B

解析:

  1. let i 使 for 造成块级作用域。
  2. requestAnimationFrame 相似于 setTimeout,然而它能够当成一个微工作来看,是在微工作队列执行结束后,执行 UI 渲染前,调用的一个办法。
  3. 因而,这道题并不是指 requestAnimationFrame 会收集 i,而是 let 造成了块级作用域的问题,如果改成 var i,照样输入 5 个 5

17.8 暂时性死区

返回目录

1、上面代码输入什么?

let a = 1;
let test = function() {console.log(a);
  a++;
}
test();

2、上面代码输入什么?

let a = 1;
let test = function() {console.log(a);
  let a = 2;
  a++;
}
test();

答案:

第一道题输入:1

第二道题输入:Uncaught ReferenceError: Cannot access 'a' before initialization

解析:

其起因是在同一个 block 中,let 在前面从新定义的,那么就不能在之前援用该变量。同时,也不能取嵌套外层的值。

17.9 输入打印后果

返回目录

function sayHi() {console.log(name);
  console.log(age);
  var name = "Lydia";
  let age = 21;
}

sayHi();

下面代码输入后果?


答案:undefined、报错

解析:

这道题转变一下就看明确了:

function sayHi() {
  var name; // 变量晋升 - 变量申明
  console.log(name); // undefined
  console.log(age); // let 存在暂时性死区,不会变量晋升
  name = "Lydia"; // 变量晋升 - 变量赋值
  let age = 21;
}

sayHi();

17.10 输入打印后果

返回目录

function myFunc() {console.log(a);
  console.log(func());

  var a = 1;
  function func() {return 2;}
}

myFunc();

请问输入啥?


答案:undefined 2

解析:不难,不解析了

17.11 Event Loop

返回目录

for (var i = 0; i < 3; i++) {setTimeout(() => console.log(i), 1);
}

for (let i = 0; i < 3; i++) {setTimeout(() => console.log(i), 1);
}

下面代码输入后果?


答案和解析:

第一道题目:varfor 中存在变量净化,同步代码 for 执行结束之后,再执行宏工作 setTimeout,发现以后 i 都成为 3 了,所以输入 3、3、3

第二道题目:letfor 中会造成块级作用域,每次迭代的时候 i 都是一个新值,并且每个值都存在于循环内的块级作用域,所以输入 0、1、2

17.12 输入打印后果

返回目录

let date = new Date();

for (var i = 0; i < 5; i++) {setTimeout(function() {console.log(new Date - date, i); // 1
  }, 1000);
}

console.log(new Date - date, i); // 2

请问输入啥?


答案:

0 5
1001 5
1004 5
1005 5
1006 5
1007 5

解析:题目先走宏工作 script,所以定义了 date 之后,执行正文为 2 这行的 console

而后 5 个宏工作,都是定时器 setTimeout,所以会在之后执行,输入:1000 5,然而定时器也不肯定准时的,所以有可能是 10011002 或者其余的。

17.13 使 a == 1 && a == 2 成立

返回目录

尝试编码,使:if(a == 1 && a == 2 && a == 3) {} 这种状况成立。

  • 办法一

在类型转换的时候,咱们晓得了对象如何转换成原始数据类型。如果部署了 [Symbol.toPrimitive],那么返回的就是 Symbol.toPrimitive 的返回值。

当然,咱们也能够把此函数部署在 valueOf 或者是 toString 接口上,成果雷同。

// 利用闭包缩短作用域的个性
let a = {[Symbol.toPrimitive]: (function () {
    let i = 1;
    return function () {return i++;}
  })()}
  • 办法二

利用 Object.definePropertywindow/global 上定义 a 属性,获取 a 属性时,会调用 get

let val = 1;
Object.defineProperty(window, 'a', {get: function() {return val++;}
});
  • 办法三
var a = [1, 2, 3];
a.join = a.shift;

数组的 toString 办法返回一个字符串,该字符串由数组中的每个元素的 toString() 返回值经调用 join() 办法连贯(由逗号隔开)组成。

因而,咱们能够从新 join 办法。返回第一个元素,并将其删除。

十八 More

返回目录

还有很多基础知识,或者题目,jsliang 没精力一一增加进来了,尽量将原文放文章中了。

  • [x] [[译] 送你 43 道 JavaScript 面试题](https://juejin.im/post/684490…【浏览倡议:1h】

这篇文章还是挺不错的,jsliang 做的第一遍还是错了一些题,哈哈。

那么本篇文章就到这里,祝小伙伴早日找到适合 Offer


<img alt=” 常识共享许可协定 ” style=”border-width:0″ src=”https://i.creativecommons.org/l/by-nc-sa/4.0/88×31.png” />
<span xmlns:dct=”http://purl.org/dc/terms/” property=”dct:title”>jsliang 的文档库 </span> 由 梁峻荣 采纳 常识共享 署名 - 非商业性应用 - 雷同形式共享 4.0 国内 许可协定进行许可。
基于 https://github.com/LiangJunro… 上的作品创作。
本许可协定受权之外的应用权限能够从 https://creativecommons.org/l… 处取得。

正文完
 0