Skip to content

js

老派的 this

好题 只要记住

  • function(){} 的 this 指向调用者
  • ()=>{} 的 this 指向定义时的外层函数,若无就是 windows

Implicit Coercion

console.log('3' + 1) // 31 console.log('3' - 1) // 2 since subtraction operator ONLY trigger ToNumber() conversion, no string

Number(null) -> 0 Number(undefined) -> NaN. JSON doesn't have undefined value, when JSON stringify, undefined will be replaced with null in JSON data type.

Under Browser

  • HTMLCollection 是类 Array, 要用 Array.from()

Object.defineProperty

Enumerable 属性:

image-20230223162716724

Configurable属性:定义了后不仅再对这个对象做任何修改都会报错

image-20230223162809788

而且 delete o.a也会无效。这个很重要 所有可以被删除的属性 都不能 Configurable: false

用点运算值和Object.defineProperty()为对象的属性赋值时 默认属性很不相同:

image-20230223162904108

set, get:有set或get就不能有value 否则会报错,也不能有writable

//Uncaught TypeError: Invalid property descriptor.

//Cannot both specify accessors and a value or writable attribute, #

毕竟只能通过一个方法来更改obj的呀~

  • value/writable被称为数据描述符(= 称为赋值运算符);get/set被称为存取描述符
  • 用defineProperty时 所有可选键值均默认为undefined或false

p.s. How to observe an array?

// ×
Object.defineProperty(arr, i, {
    configurable: false,
    enumerable: false,
    get: () => arr[i],
    set: (value) => {
      arr[i] = value // 会溢出
    }
})
// ✅
let v
Object.defineProperty(arr, i, {
      configurable: false,
      enumerable: false,
      get: () => v,
      set: (value) => {
        v = value
       }
})

p.p.s.:关于属性统计表 这个超清晰

image-20230223163623632

promise 相关

  • 一个简易的自制promise

```javascript class Poppy { constructor(executor) { const self = this //原文是构造函数 为了避免下面的bind所以用了变量 但是class里面的方法没法访问到construtor里的变量呀… this.status = 'pending' //只是用作记录 this.data = undefined //同用作记录 this.onResolvedCallBack = [] //我感觉这里也永远都只会有一个 不用数组 try { executor(this.resolve.bind(this), this.reject) } catch (e) { this.reject(e) } return this }

resolve(val) {
  if (val instanceof Promise) { return val.then(resolve, reject) }
  // setTimeout(function () { // 异步执行所有的回调函数
  if (this.status === 'pending') {
    this.status = 'resolved'
    this.data = val

//所以如果是没有异步时间的话 下面这行是没用的。下面这行的意义就在于先把res后要处理的函数存储起来,等待res后再来处理。 this.onResolvedCallBack.forEach(cb => cb(val)||val ) } // }) }

 reject(){}

 then(onResolved, onRejected) {
    onResolved = typeof onResolved === 'function' ? onResolved : function (v) {}
    // 中间无异步时,返回的也是new Poppy
    if (this.status === 'resolved') {
        return new Poppy((resolve, reject) => {
            const x = onResolved(this.data)||this.data
            if (x instanceof Poppy) return x.then(resolve, reject)
            resolve(x)
        })
     }
    // 中间有异步时
   if (this.status === 'pending') {
         return new Poppy((resolve, reject) => {
           // 这一个then里要执行的暂存起来
           // 下下个then就留给这个new Poppy去处理了。而这个new Poppy的执行完毕要等到这一个then处理完后。
           // 就相当于是一个非常长久的waiting后再resolve的了。
           // 所以只要一个Promise链中任何一个环节是有等待操作的,以后的每个then都是有等待操作,并经过这里处理了。
         this.onResolvedCallBack.push((value) => {
              const x = onResolved(value) || this.data
              if(x instanceof Poppy) return x.then(resolve, reject)
              resolve(x)
         })
       })
    }
   }

}

const a = new Poppy((res, reject) => { setTimeout(()=>{res(2)}, 100) // res(4) }) .then(r => { console.log(r) // return new Poppy(res => res(r)) }) .then(a => console.log('boom2', a))

```

  • 浏览器的promise
  • promise+generator的co库
  • 浏览器通过async/await的实现

  • 如何让forEach对异步函数parallely执行?使用不了。因为forEach的本质就是for循环的匿名函数 你又不能操作匿名函数给其加上async。

可以用for...of循环数组item(推荐) 或者

async function asyncForEach(array, callback) {
  for (let index = 0; index < array.length; index++) {
    await callback(array[index], index, array);
  }
}

ref: https://lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795/ d

注意:可别和for...in弄错了 for..in数组得到的是属性key 也就是0,1,2..和其他若有挂载的属性key

事件循环

通过人家代码的这个错误案例,可以体会:

 var result = '';
 var totalPage = 3;
 for(var page=1; page<totalPage; page++) {
  var ajax = new XMLHttpRequest();
  ajax.open('get','https://001.980512.com/qun/api/topic_order_list.htm?size=10&topic_id=2592&mid=9657585943&page' + page);
  ajax.send();
  ajax.onreadystatechange = function () {
     if (ajax.readyState==4 && ajax.status==200) {
       var response = ajax.responseText;
    var respJson = eval('(' + response + ')');
    var data = respJson.data;
    if(data.length > 0) {
     for(var i=0; i<data.length; i++) {
      result = result + data[i].address + ',' + data[i].total_fee + ',' + data[i].link_man + ',' + data[i].link_tel + '\n';
     }
    }
     }
  }
 }

let start = Date.now();
while(Date.now()-start <= 5000);
console.log(result)

这里的 while, 当然要改为 setTimeOut() 移到下一个事件循环

marcrotask queue 包括:script, dom event, setTimeout 一般宏任务由宿主发起,微任务由 js 本身发起