js核心基础

术语索引

https://developer.mozilla.org/en-US/docs/Glossary

  • 可枚举性 enumerable: 可枚举是集合的属性,隐式要求每个元素都是唯一的,for ... in
  • 迭代 iterate可迭代 迭代器是借鉴 C++等语言的概念,迭代器的原理就像指针一样,它指向数据集合中的某个元素,你可以获取它指向的元素,也可以移动它以获取其它元素。迭代器类似于数组中下标的拓展,各种数据结构,如链表(List)、集合(Set)、映射(Map)都有与之对应的迭代器。迭代器是专门为了遍历这一操作设计的。迭代是按照某种顺序逐个访问列表中的每一项,是将输出做为输入,再次进行相同动作处理。for ...of
  • 递归 recursion: 自己调用自己,自己包含自己。从计算机角度讲,递归是迭代的特例
  • 遍历:按规则访问非线性结构中的每一项。强调非线性结构(树, 图). 而迭代一般适用于线性结构(数组, 队列).

遍历、枚举、迭代
递归是重复调用函数自身实现循环。迭代是函数内某段代码实现循环,而迭代与普通循环的区别是:循环代码中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。

数组对象其实是一个特殊对象,他拥有普通对象的全部特性,所以不止负值索引,小数索引,连字符串索引都是可以的,只是用这些索引向数组添加属性时,数组的 length 不会增加罢了,而只有当索引是正整数或其对应数字串时,length 才会增加

自己出的一个面试题 涉及symbol,for, 和...

operator 操作符 细节

连续声明多个变量

Object 的几个遍历方法 对比

  • for..of 遍历 enumerable, string-keyed 属性

  • for..in 遍历 enumerable, string-keyed 属性(包括inherit-property) for in 的顺序问题,准确的说是基于不同浏览器有不同的实现方式。对于大多数是这样的:先遍历出整数属性String(Math.trunc(Number(prop)) === prop(integer properties,按照升序),然后其他属性按照创建时候的顺序遍历出来

  • ...obj 拷贝own, enumerable 属性(包括Symbol-keyed)

  • Object.assign(target,...sources) 同…拷贝own, enumerable 属性(包括Symbol-keyed) 内部对 target 执行 set,对 source 执行 get。正因为 source-obj 会 invoke property 的 getter所以 prototype 不适合做 target,请改用Object.getOwnPropertyDescriptor()配合Object.defineProperty()

  • Object.keys() 返回 own, enumerable, string-keyed 属性

  • Object.getOwnPropertyNames() 返回 own, string-keyed 属性(包括non-enumerable) non-enumerable 属性的创建只有一种方式:Object.defineProperty(obj1, 'non-enumerable-key1', {value: 'xx', enumerable: false})

  • Object.getOwnPropertySymbols() 同上,但是只是 Symbol-keyed 属性

Object.is(v1,v2) 判断的还是两个 v 的指针

this 详解

网道这里解释的很好!!
官方 MDN
知乎解释

  • 给当前元素的某一个事件行为绑定函数,方法执行时的 this 就是绑定的当前元素本身
  • 自执行函数中的 this 一般都是 window,严格模式下是 undefined
  • 回调函数中的 this 一般都是 window,严格模式下是 undefined
  • 箭头函数在创建执行上下文的时候,在初始化上下文环境时,不会创建 this 属性,所以在箭头函数中如果使用到 this 会根据作用域链向上级上下文寻找,箭头函数中所使用的 this,都是来自上级函数作用域链,即上级函数被谁调用这个 this 就是谁
  • 构造函数时的 this 是指实例

箭头函数

  • 箭头函数有作用域(词法作用域),词法作用域简单来讲就是,一切变量(包括 this)都根据作用域链来查找。.箭头函数中的 this 因为绑定了词法作用域,所以始终指向自身外的第一个 this(由于自身没有声明 this,所以会去作用域链上找 this),也就是始终等于调用它的函数的 this(以为这个 this 离它最近)
  • 不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 Rest 参数代替。
  • 不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误。
  • 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。
  • 准确的说 this、super、arguments、new.target 都没有自己的,全都来自父作用域,父作用域能找到的 就不会 undefined

骚操作

  • 实现 sleep 阻塞目的:

    1. while()限定时间条件达到
    const expire = Date.now() + 1000
    while(Date.now()<expire)
    // after that, do something
    
    1. promise 异步
    const wait = (timeout) => {
      return new Promise((resolve) => setTimeout(resolve, timeout));
    };
    wait(2000).then(() => setRefreshing(false));
    /**
    new promise((reslove, reject) = > {
        setTimeout  (()=>{
            reslove()
        }, 2000)
    })
    */
    

    冷知识

    赋值详详详详解
    神奇的 JS 连续赋值语句
    JS 赋值语句 永远返回值,声明语句 永远返回 undefined
    JavaScript 中赋值语句的返回值就是等号右边的值,例子中 obj.getThis 的值是一个匿名函数,非严格模式下 this 会指向 window

    var obj = {
      name: "My Object",
      getThis: function () {
        console.log(this);
      },
    };
    (obj.getThis = obj.getThis)(); // window
    //
    if (x = 10) // 会判断为10,隐式转换为true
    

解构赋值

  1. 解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象,字符串被转为类数组对象,数值和布尔型则转为包装对象。由于 undefined 和 null 无法转为对象,所以对它们进行解构赋值,都会报错。
const [a, b, c, d, e] = "hello";
a; // "h"
b; // "e"
c; // "l"
d; // "l"
e; // "o"

//字符串转为的对象有length属性
let { length: len } = "hello";
len; // 5

let { toString: s } = 123;
s === Number.prototype.toString; // true

let { toString: s } = true;
s === Boolean.prototype.toString; // true

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
  1. 数组是特殊的对象,所以可以对数组进行对象属性的解构
let arr = [1, 2, 3];
let { 0: first, [arr.length - 1]: last } = arr;
first; // 1
last; // 3
  1. 数组的解构赋值也可以这样使用 let [,m] = [2,3]
  2. 设置解构赋值的默认值
function move({ x = 0, y = 0 } = {}) {
  return [x, y];
}
  1. 如果解构赋值语句不是变量声明语句(前面没有 var,let,const),即对已经声明的变量进行进行解构赋值需要注意加上括号 注:数组的解构赋值[x,y]=[y,x]好像不用加括号
let x;
({ x } = { x: 1 }); // 和立即执行函数一样,该语句的前面一行最好加上分号,否则可能会被当做函数调用
  1. 解构赋值 可以直接提取 JSON 数据,当作 object 处理

按位运算 妙用

  1. http://www.matrix67.com/blog/archives/263
  2. http://www.matrix67.com/blog/archives/264
  3. http://www.matrix67.com/blog/archives/266
  4. http://www.matrix67.com/blog/archives/268

switch case 不加 break 会怎样

看一段代码:

switch (direction) {
  case "U":
  case "R":
  case "D":
  case "L":
}

在这个语句中,如果 direction=U。那么四个 case 语句都将执行。如果 direction=R。将执行剩下三个语句。
原因是 switch 语句原理是跳转到 caseX 位置执行剩下的语句,直到最后或者遇见 break 为止。
比如 React 源码中有过这样使用

switch (type) {
  case "string":
  case "number":
    invokeCallback = true;
    break;
  case "object":
    switch (children.$$typeof) {
      case REACT_ELEMENT_TYPE:
      case REACT_PORTAL_TYPE:
        invokeCallback = true;
    }
}

事件 event 捕获和冒泡详解

一个 event 详解

https://zh.javascript.info/bubbling-and-capturing
DOM 事件标准描述了事件传播的 3 个阶段:

捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
目标阶段(Target phase)—— 事件到达目标元素。没有被单独处理:捕获阶段和冒泡阶段的处理程序都在该阶段被触发。
冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡。

如果我们在同一阶段有多个事件处理程序,并通过 addEventListener 分配给了相同的元素,则它们的运行顺序与创建顺序相同

注册事件 handler 的三种方式

  1. 使用 dom 对象的同名 property 赋值:document.querySelector('button').onclick = function (e){}
  2. 使用addEventListener()方法
  3. 在 html 的 dom 的 attribute 中 直接 inline event handler 不建议,html 和 js 这样 mix up 在一起不易管理也低效,只能用于一个 handler 只 handle 单个元素的情况
    inline event 也有点优点
    实质上,当事件处理程序被指定为 HTML 属性,指定的代码被包装在有 以下参数 的函数中。_该 inline handler 函数的入参:event / this_

EventTarget 接口

https://wangdoc.com/javascript/events/eventtarget.html

  • addEventListener(type, listener[, options={capture, once, passive, signal} / useCapture=false ])
  • removeEventListener(type, listener[, options={capture} / useCapture=false])
  • dispatchEvent() cancelled = !target.dispatchEvent(event instance)

事件代理

ul.addEventListener('click', function (event) {event.target blabla...})

取消各种

  • event.preventDefault 取消浏览器对当前事件的默认行为。比如点击链接的默认跳转页面
  • event.stopPropagation 阻止事件在 DOM 中继续传播(addEventListener 时 默认未指定触发阶段的情况下,这里即取消冒泡阶段),防止再触发定义在别的节点上的监听函数。但是不包括在当前节点上其他的事件监听函数
  • event.stopImmediatePropagation 阻止同一个事件的其他监听函数被调用。取消冒泡阶段 基础上,取消自己的

自定义事件

new CustomEvent(typeArg, {detail: null})

判断类型的 4 种方法

https://www.cnblogs.com/onepixel/p/5126046.html

  • typeof
  • instanceof 内部实质:A.__proto__ === B.prototype, 有个极端抬扛的情况是,一个网页有多个 iframe 即多个全局执行环境时,iframe1 的 arr1 肯定不会 === iframe2 的 Array 的,这时候用 Array.isArray(arr)来判断
  • constructor 找到构造函数
  • Object.toString() 使用:Object.prototype.toString.call(true) 解释:If this method is not overridden in a custom object, toString() returns “[object type]” 如[].toString.call('sss') // "[object String]"

symbol 的应用场景

Relative Post

promise

Relative Post

深入理解try catch(error) finally

  • try 的 {} 是必须的,即使只有一行
  • try 之后至少一个(catch 或 finally)
  • 可以嵌套 try,最里面 throw 了但是没有 catch 的话,会向上一层层找 catch
  • If the finally-block returns a value, this value becomes the return value of the entire try-catch-finally statement;否则就按前面最后一个执行的 block 的 return
  • 最佳实践
  • react 的 顶层 try catch - Error Boundaries: componentDidCatch(error, errorInfo) {} & static getDerivedStateFromError(error) {}
  • react 中的错误捕获 & 错误边界: 错误边界不能捕获的异常有两个
    1. 事件处理(使用 try catch);
    2. 异步代码(局部的话就async await + try catch; 全局的解决方案是:window.addEventListener(‘error’, e=>{}) 和 window.addEventListener(“unhandledrejection”,e=>{}))
    3. 服务端渲染
    4. 自身错误(将边界组件和业务组件分离,各司其职)

fetch & xmlhttprequest & axios 对他们的封装 & websocket & request/response header body, http1/2 协议

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
fetch & Ajax & axois 对比 及 xss 和 csrf 攻击 安全问题
https://juejin.cn/post/6844904184748195848

跨域 和 csrf 攻击

https://juejin.cn/post/6844903934310498312

localStorage & indexedDB & sessionStorage & cookie & session

babel 详解

https://zhuanlan.zhihu.com/p/43249121


   转载规则


《js核心基础》 Ryan Who 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
mongoDB mongoDB
简介史前时代: LAMP/LNMP(Linux, Apache/Nginx, Mysql, PHP)现在 MEAN(MongoDB, Express,Angular.js,Node) Mongo
2020-10-20
下一篇 
handlebars模版引擎 handlebars模版引擎
简介 Handlebars 是一个 Javascript 模板引擎,能让你轻松高效的编写语义化模板,它是 Mustache 模板引擎的一个扩展,Handlebars 和 Mustache 都是弱逻辑的模板引擎,能将 Web 前端的视图和代码
2020-09-17
  目录