[关闭]
@artman328 2022-08-02T08:00:09.000000Z 字数 5409 阅读 411

JavaScript 技巧集锦

JavaScript js cookbook


一、字符串处理

1、如何将包含空白(可能是空格、tab、回车等)的字符串以空格做分隔符变换成不包含空串的字符串数组?

  1. //仅包含一个分隔空格
  2. "It is power of the dream".split(" ")
  3. //['It', 'is', 'power', 'of', 'the', 'dream']
  4. //包含多个不同数量的间隔空白字符
  5. "It is power of the dream".split(" ")
  6. //['It', '', 'is', 'power', 'of', 'the', '', '', '', 'dream'] 包含空串!
  7. //解决方案
  8. "It is power of the dream".replace(/\s+/g," ").split(" ")
  9. //['It', 'is', 'power', 'of', 'the', 'dream']
  10. //or:
  11. "It is power of the dream".split(/\s+/g)
  12. //['It', 'is', 'power', 'of', 'the', 'dream']

在正则表达式中,\s 代表一切空白字符,包括空格、换行、TAB等。

二、类与对象

1、如何为自定义类中的一维数组和二维数组定义迭代器?

(1)一维数组

  1. class Employee {
  2. constructor(employee_id, firstName, lastName) {
  3. this.employee_id = employee_id
  4. this.firstName = firstName
  5. this.lastName = lastName
  6. }
  7. get fullName() {
  8. return this.firstName + " " + this.lastName
  9. }
  10. set fullName(fullName) {
  11. fullName = fullName.split(/\s+/g)
  12. this.firstName = fullName[0]
  13. this.lastName = fullName[1]
  14. }
  15. }
  16. /*
  17. 这是一个管理员工的类,它将被用来针对整个员工群体进行管理,
  18. 比如添加员工到集合中、从集合中删除员工等。这些管理行为
  19. 可以应用程序逻辑进行控制。
  20. */
  21. class EmployeeCollection {
  22. constructor(employees = []) {
  23. this.employees = employees
  24. }
  25. add(employee){
  26. // 检查 employee 对象数据的合法性、操作者的权限等
  27. // 如果满足要求才:
  28. this.employees.push(employee)
  29. }
  30. remove(employee_id) {
  31. // 检查操作者的权限,如果满足才:
  32. const index = this.employees.findIndex((emp)=>emp.employee_id==employee_id)
  33. if(index >= 0){ // found
  34. this.employees.splice(index,1)
  35. }
  36. }
  37. [Symbol.iterator]() {
  38. let index = 0
  39. return {
  40. next: () => {
  41. if (index < this.employees.length) {
  42. return {
  43. value: this.employees[index++],
  44. done: false
  45. }
  46. }
  47. return {
  48. done: true
  49. }
  50. }
  51. }
  52. }
  53. }
  54. let employeeCollection = new EmployeeCollection([
  55. new Employee(1, "Billy", "Gilman"),
  56. new Employee(2, "Tracy", "Taylor"),
  57. new Employee(3, "Emily", "Brown")
  58. ])
  59. //iterate the collection
  60. for (let emp of employeeCollection) {
  61. console.log(emp.fullName)
  62. }
  63. /* output:
  64. Billy Gilman
  65. Tracy Taylor
  66. Emily Brown
  67. */
  68. employeeCollection.remove(2)
  69. for (let emp of employeeCollection) {
  70. console.log(emp.fullName)
  71. }
  72. /* output:
  73. Billy Gilman
  74. Emily Brown
  75. */

(2) 二维数据

要求:按从左到右,从上到下的顺序遍历所有网格中的单元格。
以下示意图说明了单元格的索引号(0~47)和其所在行、列索引之间的互换关系。

  1. class Grid {
  2. constructor(rows = 1, columns = 1) {
  3. this.rows = rows
  4. this.columns = columns
  5. this.cells = []
  6. for (let r = 0; r < rows; r++) { // 构建二维数组
  7. this.cells[r] = []
  8. for (let c = 0; c < columns; c++) {
  9. this.cells[r][c] = columns * r + c
  10. }
  11. }
  12. }
  13. [Symbol.iterator] = function () {
  14. let idx = 0
  15. return {
  16. next: () => {
  17. if (idx < this.rows * this.columns) {
  18. const r = Math.floor(idx / this.columns)
  19. const c = idx % this.columns
  20. const res = {
  21. value: this.cells[r][c],
  22. done: false
  23. }
  24. idx++;
  25. return res;
  26. }
  27. else {
  28. return { done: true }
  29. }
  30. }
  31. }
  32. }
  33. }
  34. let grid = new Grid(6, 8)
  35. // console.log(grid)
  36. for (let cell of grid) {
  37. console.log(cell)
  38. }
  39. /* output:
  40. 0
  41. 1
  42. ...
  43. 47
  44. */

三、DOM(文档对象模型)相关

1、如何确定事件处理顺序

  1. --------------------------------
  2. | div.grand-parent |
  3. | ------------------------ |
  4. | | div.parent | |
  5. | | ------------- | |
  6. | | | div.child | | |
  7. | | ------------- | |
  8. | ------------------------ |
  9. --------------------------------

在以上的DOM结构中,如果一个事件发生在 div.child 元素上,如何在它的前辈元素中捕获并处理此事件?如何确定处理顺序?

1.1 两种事件顺序

1.1.1 事件捕获(Event Capturing)顺序

事件捕获处理顺序如下:

  1. document
  2. | |
  3. ---------------------| |-----------
  4. | div.grand-parent | | |
  5. | -----------------| |------- |
  6. | | div.parent | | | |
  7. | | -------------| |---- | |
  8. | | | div.child \ / | | |
  9. | | --------------------- | |
  10. | ---------------------------- |
  11. ------------------------------------
1.1.2 事件冒泡(Event Bubbling)顺序
  1. document
  2. / \
  3. ---------------------| |-----------
  4. | div.grand-parent | | |
  5. | -----------------| |------- |
  6. | | div.parent | | | |
  7. | | -------------| |---- | |
  8. | | | div.child | | | | |
  9. | | --------------------- | |
  10. | ---------------------------- |
  11. ------------------------------------

2、W3C标准的事件处理顺序

W3C标准的事件顺序是(当div.child发生事件时):

  1. document ----------> div.child -----------> document
  2. 事件捕获 事件冒泡
  1. document
  2. | | / \
  3. ---------------------| |---| |--------
  4. | div.grand-parent | | | | |
  5. | -----------------| |---| |---- |
  6. | | div.parent | | | | | |
  7. | | -------------| |---| |- | |
  8. | | | div.child \ / | | | | |
  9. | | ------------------------- | |
  10. | -------------------------------- |
  11. ----------------------------------------

3、确定事件响应顺序

addEventListener(event_type,handle_func,useCapture) 函数来确定事件响应顺序。其中的第三个参数 useCapture 是一个 bool 型参数,用于说明事件的响应函数应该在哪一个阶段执行。

true
在事件捕获阶段执行。即子孙触发的事件应该被父辈先于子孙响应。
false
在事件冒泡阶段执行。即子孙触发的事件应该被父辈后于子孙响应。

以下例子演示了事件处理顺序。

  1. <!DOCTYPE html>
  2. <html lang="en" data-name="document">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Custom Attributes</title>
  8. <style>
  9. div {
  10. padding: 20px;
  11. border: 1px dashed #ccc;
  12. margin-top: 20px;
  13. width: 80%;
  14. }
  15. div.grand-parent{
  16. width: 500px;
  17. background-color: rgb(190, 190, 234);
  18. }
  19. div.parent {
  20. background-color: rgb(239, 186, 186);
  21. }
  22. div.child {
  23. background-color: rgb(218, 246, 236);
  24. }
  25. </style>
  26. </head>
  27. <body>
  28. <div class="grand-parent" data-name="grand-parent">
  29. div.grand-parent
  30. <div class="parent" data-name="parent">
  31. div.parent
  32. <div class="child" data-name="child">
  33. div.child
  34. </div>
  35. </div>
  36. </div>
  37. <script>
  38. log = (useCapture,e)=>console.log(
  39. "事件由:",
  40. e.target.dataset.name,
  41. " 触发,在",
  42. useCapture?"捕获":"冒泡",
  43. "阶段由:",
  44. e.currentTarget.dataset?e.currentTarget.dataset.name:"document",
  45. " 响应。"
  46. )
  47. const $ = (sel) => document.querySelector(sel)
  48. document.addEventListener("click",(e)=>{
  49. log(true,e)
  50. },true)
  51. document.addEventListener("click",(e)=>{
  52. log(false,e)
  53. },false)
  54. $(".grand-parent").addEventListener("click",(e)=>{
  55. log(true,e)
  56. },true)
  57. $(".grand-parent").addEventListener("click",(e)=>{
  58. log(false,e)
  59. },false)
  60. $(".parent").addEventListener("click",(e)=>{
  61. log(true,e)
  62. },true)
  63. $(".parent").addEventListener("click",(e)=>{
  64. log(false,e)
  65. },false)
  66. $(".child").addEventListener('click',(e)=>{
  67. log(true,e)
  68. },true)
  69. $(".child").addEventListener('click',(e)=>{
  70. log(false,e)
  71. })
  72. </script>
  73. </body>
  74. </html>

如果在 div.child 上点击鼠标,会得到以下输出。

  1. 事件由: child 触发,在 捕获 阶段由: document 响应。
  2. 事件由: child 触发,在 捕获 阶段由: grand-parent 响应。
  3. 事件由: child 触发,在 捕获 阶段由: parent 响应。
  4. 事件由: child 触发,在 捕获 阶段由: child 响应。
  5. 事件由: child 触发,在 冒泡 阶段由: child 响应。
  6. 事件由: child 触发,在 冒泡 阶段由: parent 响应。
  7. 事件由: child 触发,在 冒泡 阶段由: grand-parent 响应。
  8. 事件由: child 触发,在 冒泡 阶段由: document 响应。

四、其它

1、如何判断坐标系中两个矩形物体是否碰撞?

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注