前端进阶问题答疑汇总(mine)

这是我完成答题之后的有问题的问题的记录,如果你们也想试一下的话可以到文末 clone 一波,自己试试。

var/let

  // 1
  function a1() {
    console.log(name); // 显示 undefined 但不会报错,因为已经提升变量了,在运行到定义位置前都是undefined
    console.log(age); // 暂时性死区 ReferenceError
    var name = 'Arthas'
    let age = 21
  }

this

  // 3
  const shape3 = {
    radius: 10,
    diameter() {
      return this.radius * 2
    },
    perimeter: () => 2 * 10 * this.radius
  }
  shape3.diameter() // 20
  shape3.perimeter() // NaN

常规函数内的 this 指向当前作用域(本对象)
箭头函数内的 this 指向它的父级作用域,当前情况下就是指向window

Array

  // 4
   const bird4 = {
    size: 'small'
  }
  const mouse4 = {
    name: 'Monica',
    small: true
  }
  console.log(mouse4.bird4.size); // error
  console.log(mouse4[bird4.size]); // true
  console.log(mouse4[bird4["size"]]); // true
  • 先寻找内部的内容,再找外层 bird4.size = ‘small’; mouse4[‘small’] = true 第三个log同理*

new Number()

  // 7
  let a7 = 3
  let b7 = new Number(3)
  let c7 = 3
  console.log(a7 == b7); // true
  console.log(a7 === b7); // false
  console.log(b7 === c7); // false

new Number() 属于内建的函数构造器,是一个Object
== 的时候 只校验值 true
=== 的时候 校验值与类型 false

class

  // 8
  class Chameleon8 {
    static colorChange(newColor) {
      this.newColor = newColor
      return this.newColor
    }
    colorChange2(newColor) {
      this.newColor = newColor
      return this.newColor
    }
    constructor({ newColor = 'green' } = {}) {
      this.newColor = newColor
    }
  }
  const freddie8 = new Chameleon8({ newColor: 'purple' })
  alert(freddie8.colorChange('orange')) // typeError
  alert(freddie8.colorChange2('red')) // red

static 是定义类的静态方法的关键词,这种方法只能被创造他们的构建器使用,不能传递给实例,所以不能被示例使用

Window

  // 9
  let greting9
  greetign9 = {} // 与上面的单词不符
  console.log(greetign9); // {}

log显示 空对象,是因为我们在全局创建了一个对象
当写错单词时,JS解释器在上浏览器中将它视为 global.greetign9 = {} or window.greetign = {}
如果要避免,可以使用严格模式 “use strict”

new Number()

  // 7
  let a7 = 3
  let b7 = new Number(3)
  let c7 = 3
  console.log(a7 == b7); // true
  console.log(a7 === b7); // false
  console.log(b7 === c7); // false

new Number() 属于内建的函数构造器,是一个Object
== 的时候 只校验值 true
=== 的时候 校验值与类型 false

Function&Object

  // 10
  function bark10() {
    console.log('Woof');
  }
  bark10.animal = 'dog'
  console.log(bark10(), bark10.animal); // Woof undefined , dog

这种写法是可行的,因为函数也是对象(除基本类型之外其他都是对象)
函数属于特殊的对象,上面的那些代码其实并不是一个实际的函数。
函数是一个拥有属性的对象,且属性可以被调用

class

  // 11
 function Person11(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
  }
  const member11 = new Person11('Arthas', 'Monica')

  // Wrong
  Person11.getFullName = function () {
    return `${this.firstName} ${this.lastName}`
  }
  console.log(member11.getFullName()); // TypeError
  /*
	不可以向常规对象那样,给构造函数添加属性
    如果想一次性给所有实例添加属性,使用原型
  */
  
  // Right
  Person11.prototype.getFullName = function () {
    return `${this.firstName} ${this.lastName}`
  }
  console.log(member11.getFullName()); // Arthas Monica

这样做是有益的,如果将此方法添加到构造函数本身,也许不是每个Person11都需要这个方法。
这样会浪费大量的内存空间,因为它们仍然具有该属性,这将占用每个实例的内存空间。
如果只是将它添加到原型中,那么它只存在于内存中的一个位置,但是所有实例都可以访问它

class

  // 12
  function Person12(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
  }
  const arthas12 = new Person12("Arthas", 'zzy')
  const monica12 = Person12('Monica', 'gss')

  console.log(arthas12); // Person {firstName: "Arthas", lastName: "zzy"}
  console.log(monica12, window.firstName, window.lastName); // undefined 'Monica', 'gss'

对于monica12,我们并没有使用 new。
当使用 new 时,this 引用我们创建的空对象
未使用 new 时,this 引用的是全局对象 (global object / window)
所以 当this.firstName = ‘Monica’ 且 this.lastName = ‘gss’ 时
等于 window.firstName = ‘Monica’ window.lastName = ‘gss’
而 monica12 本身则是 undefined

13 click

事件传播的三个阶段
在捕获(captruing)阶段中,事件从祖先元素乡下传播到目标元素。
当时间到达目标(target)元素后
冒泡(bubbling)才开始
captuing - target - bubbling

14 Object

除去基本对象,所有对象都有原型。
基本对象可以访问一些方法和属性,比如 .toString()
所有的这些方法在原型上都是可用的。
虽然JavaScript不能直接在对象上找到这些方法,但JavaScript会沿着原型链找到它们。

隐式类型转换

  // 15
  function sum15(a, b) {
    return a + b
  }
  console.log(sum15(1, +'2')) // 3
  console.log(sum15(1, '2')) // '12'

标记模版字变量

  // 17
    function getPersonInfo17(one, two, three) {
    console.log(one);
    console.log(two);
    console.log(three);
  }
  const person17 = 'Arthas'
  const age17 = 21

  getPersonInfo17`${person17} is ${age17} years old` // "", " is ", " years old"]   "Arthas"   21

使用标记模版字变量,第一个参数总是包含字符串的数组,其余的参数获取的是传递的表达式的值

Object

  // 18
  let obj18 = { a: 1 }
  let b18 = obj18

  console.log(obj18 == b18); // true
  console.log(obj18 === b18); // true
  console.log(obj18 == {a:1}); // false
  console.log(obj18 === {a:1}); // false
  console.log(b18 == {a:1}); // false
  console.log(b18 === {a: 1}); // false
  console.log({a: 1} == {a: 1}); // false
  console.log({a: 1} === {a: 1}); // false

判断其相等与否时,基本类型通过值来进行比较,而对象通过它们的引用(refreence)进行比较。
JavaScript检查对象是否具有对内存中 相同位置的引用

扩展运算符

  // 19
  function getAge19(...args) {
    console.log(typeof args);
  }
  getAge19(21) // object

扩展运算符会返回实参组成的数组,而数组是对象,返回 object

严格模式

  // 20
  function getAge20() {
    'use strict'
    age = 21
    console.log(age)
  }
  getAge20() // ReferenceError

’use strict’ 进入严格模式,未声明变量将抛出 引用错误
如果不使用严格模式,age将会在全局声明 log就会是21

Object

  // 25
  const obj25 = { a: 'Ass', b: 'Monica', a: 'Arthas' }
  console.log(obj25); // {a: 'Arthas', b: 'Monica'}

如果有两个相同的键名,排在前面的会被后面的替换掉。

Array

  // 29
  const a29 = {}
  const b29 = { key: 'b' }
  const c29 = { key: 'c' }

  a29[b29] = 123
  a29[c29] = 456
  console.log(a[b]) // 456

对象的键会被自动转化为字符串。
但是当字符串化一个对象的时候,会变成 “[Object Object]” 所以 a[“Object Object”] = 123
然后又做了一次相同的事情,这时候a[“Object Object”]的值又被改成了 456
所以 a[b] 返回 456

call&bind&apply

  // 33
  const person33 = { name: 'Arthas' }
  function sayHei33(age) {
    console.log(`${this.name} is ${age}`);
  }
  sayHei33.call(person33, 21) // 立即执行
  sayHei33.bind(person33, 21)() // 不会立即执行,需要调用
  sayHei33.apply(person33, [21]) // 参数是一个数组的集合,其余和call一样

reduce

  // 40
    [[0, 1], [2, 3]].reduce(
    (acc, cur, idx, arr) => {
      return acc.concat(cur) // [1, 2, 0, 1, 2, 3]
    },
    [1, 2]
  )
  /*
  	reduce(
      func, -> 累加器 可选
        total -> 初始值,或者计算结束之后的返回值
        currentValue -> 当前元素
        currentIndex -> 当前元素的下标
        arr -> 当前元素所在的数组对象
      initVal -> 初始值 可选
    )
	*/

reduce方法是接受一个函数作为累加器,数组中的每个值从左往右开始缩减,最终计算成一个值。
reduce可以作为一个高阶函数,用于compose函数
reduce参数为空是不会执行回调函数的

setInterval

  // 42
  let timer42 = setInterVal(() => console.log('time'), 1000)
  console.log(timer42) // 某一id
  clearInterVal(timer42)
  console.log(timer42) // null

setInerval 方法返回一个唯一的id,用于clearInterval

45 Promise

Promise.race() 方法中传入多个Promise时,会优先解析。
哪个先成功,哪个就是返回内容

Object

  // 46
  let person46 = { name: 'Arthas' }
  const members46 = [person46]
  const members2_46 = [person46]
  person46 = null
  console.log(members46); // [{name: 'Arthas'}]

  members2_46.name = null
  console.log(members46); // [{name: null}]

map

  // 50
  let a50 = [1, 2, 3].map(num => {
    if (typeof num === 'number') return
    return num * 2
  })
  // [undefined,undefined,undefined]

map中if判定为true,但是return并没有返回任何值,map默认返回 undefined

函数

  // 51
  function getInfo51(member, year) {
    member.name = 'Monica'
    year = '2000'
  }
  const person51 = { name: 'Arthas' }
  const birthYear51 = '1999'
  getInfo51(person51, birthYear51)
  console.log(person51, birthYear51) // {name: 'Monica'}, '1999'

普通参数都是值传递的,但是对象不一样,是引用传递。
person51是个对象,参数member引用与之相同的对象。当修改member51所引用的对待的属性时,person51也被修改了,因为他们引用了相同的对象

class&Function

  // 53
  function Car53() {
    this.make = 'Monica'
    return { make: 'Arthas' }
  }
  const myCar53 = new Car53()
  console.log(myCar53.make) // Arthas

返回属性的时候,属性的值等于 返回 的值,而不是构造函数中设定的值。

let&window

  // 54
  const a54 = () => {
    let x = (y = 10)
  }
  console.log(typeof x); // undefined
  console.log(typeof y); // 10

y 属于全局定义 window.y = 10 所以 typeof y 是 ‘number’
x 内部定义,外部获取不到,所以 typeof x 是 ‘undefined’

new Number()

  // 7
  let a7 = 3
  let b7 = new Number(3)
  let c7 = 3
  console.log(a7 == b7); // true
  console.log(a7 === b7); // false
  console.log(b7 === c7); // false

new Number() 属于内建的函数构造器,是一个Object
== 的时候 只校验值 true
=== 的时候 校验值与类型 false

class

  // 55
  class Dog55 {
    constructor(name) {
      this.name = name
    }
  }
  Dog55.prototype.bark = function () {
    console.log(`woof i am ${this.name}`);
  }
  const pet55 = new Dog55('Mara')
  pet55.bark() // woof i am Mara
  delete Dog55.prototype.bark
  pet55.bark() // TypeError

57 export

引入的模块都是只读的,只有导出他们的模块才可以修改值。
当在导入其模块的文件进行改值时,会抛出异常:[参数]是只读的,不能被修改

defineProperty

  // 61
  const person61 = { name: 'Arthas' }
  Object.defineProperty(person61, 'age', { value: 21 })
  console.log(person61); // {name: 'Arthas', age: 21}
  console.log(Object.keys(person61)); // ['name']

definedProperty 可以给对象添加一个新属性,或者修改已存在的属性.
但是新增的属性,属性默认为不可枚举的,所以 Object.keys()方法返回对象键名,只返回了name
defineProperty 添加的属性默认不可变,但可以通过 writable, configurable 和 enumerable 属性来改变这一行为。

JSON.stringify()

  // 62
  const settings62 = {
    username: 'Arthas',
    level: 21,
    health: 90
  }
  const data62 = JSON.stringify(settings62, ['level', 'health'])
  console.log(data62); // "{"level":19, "health":90}"

JSON.stringify 的第二个参数是 替代者(replacer) replacer可以是一个函数或者数组,用于控制那些值可以转换为字符串。
如果replacer是一个数组,那么就只有包含在数组中的属性会被转化为字符串。
如果replacer是一个函数,这个函数将被对象的每一个属性都调用一次。函数返回的值就是这个属性的值,最终体现在转化后的JSON字符串中。
Chrome下,如果所有函数均返回同一个返回值的时候会有异常,会直接将返回值作为输出结果,而不会输出字符串
如果函数返回undefined,则该属性会排除在外

函数默认值/Object

  // 64
  const value64 = { number: 10 }
  const multiply64 = (x = { ...value64 }) => {
    console.log(x.number *= 2)
  }
  multiply64() // 20
  multiply64() // 20
  multiply64(value64) // 20
  multiply64(value64) // 40

第一次调用的时候属于是传入默认值,所以修改也只是修改默认值 x 对象内的值
第二次调用的时候,x又回到了默认值状态,所以和上一次打印内容相同
第三次调用传入了值,修改 x 的值的时候,属于修改了 value64 对象内的值,为 20
第四次调用与第三次相同,但是第三次调用的时候已经修改了 value64 的值,所以为 40

reduce

  // 65
  [1, 2, 3, 4].reduce((x, y) => {
    return console.log(x, y)
  })
  //  1 2 , undefined 3 , undefined 4

reducer 函数接受四个参数
Accumulator (acc) (累计器)
Current Value (cur) (当前值)
Current Index (idx) (当前索引)
Source Array (src) (源数组)

reducer函数的返回值将会分配给累加器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值
reducer还有一个可选参数 initialValue,该参数将作为第一次调用毁掉函数时的第一个参数的值。如果没有提供默认选择数组中的第一个元素。
第一次调用 x - 1 y - 2
第二次调用 由于没有返回任何值,只是打印,所以会默认返回 undefined 所以 累加器 x - undefined y - 3
第三次 同上 x - undefined y - 4

class

  // 66
  class Dog66 {
    constructor(name) {
      this.name = name
    }
  }
  class Labrador66 extends Dog66 {
    constructor(name, size) {
      super(name)
      this.size = size
    }
    /*
      error

      constructor(name, size) {
        this.size = size;
      }
      // 调用super之前使用this会报错

      constructor(size) {
        super(name);
        this.size = size;
      }
      // 构造器内没有name参数

      constructor(name, size) {
        this.name = name;
        this.size = size;
      }
      // 调用super之前使用this会报错
    */
  }

import

  // 67
  // index.js
  console.log('running index.js');
  import { sum } from './sum.js';
  console.log(sum(1, 2));
    
  // sum.js
  console.log('running sum.js');
  export const sum = (a, b) => a + b;

  // 'running sum.js'  'running index.js'  3

import命令是编译阶段执行的,在代码执行之前。
意味着被导入的模块先被执行,随后才是导入模块的文件
这也是import()与require()的区别
前者先被执行,后者根据代码依次加载依赖

generator

  // 71
  function* startGames71() {
    const 答案 = yield "Do you love JavaScript?"
    if (答案 !== 'Yes') {
      return "Oh wow... Guess we're gone here"
    }
    return "JavaScript loves you back ❤️";
  }
  const game71 = startGames71()
  console.log(/* ? */); // Do you love JavaScript?
  // game71.next().value  
    
  console.log(/* ? */); // JavaScript loves you back ❤️
  // game71.next('Yes').value

*generator函数在遇到 yield 时会暂停其执行。
第一个很简单, 正常的 game71.next().value 即可
yield本身是没有返回值的,所以这时候 常量 ‘答案’ 的值是 undefined
next方法可以携带一个参数,该参数会被当作上一个yield表达式的返回值。
所以调用 game71.next(‘Yes’).value时,undefined被替换成了 ‘Yes’,即达到要求。
/

push

  // 74
  function addToList74(item, list) {
    return list.push(item)
  }
  const result74 = addToList74('apple', ['banana'])
  console.log(result); // 2

push方法返回值是当前数组的长度

freeze

  // 75
  const box75 = { x: 10, y: 20 }
  Object.freeze(box75)
  const shape75 = box75
  shape75.x = 100
  console.log(box75); // {10, 20}

freeze 冻结对象
不可改变对象任何属性,永远保持其原来的变化

function

  // 78
  const add78 = () => { // 为add78的参数
    const cache = {}
    return num => { // num 为赋值后函数的参数(addFunction78)
      if (num in cache) {
        return `from cache ${cache[num]}`
      } else {
        const result = num + 10
        cache[num] = result
        return `Calculated! ${result}`
      }
    }
  }
  const addFunction78 = add78()
  addFunction78(10) // Calculated 20
  addFunction78(10) // from cache 20
  addFunction78(5 * 2) // from cache 20

if( x in y) 语句为判断y内是否存在x键名,有则true,无则false

function

  // 81
  function sayHi81(name) {
    return `Hi there, ${name}`
  }
  console.log(sayHi81()); // Hi there, undefine

函数的参数默认值为undefined

function

  // 88
  function sum88(num1, num2 = num1) {
    console.log(num1 + num2);
  }
  sum88(10) // 20

可以将默认参数设置为另一个默认参数,只要另一个参数定义在要设置的参数之前即可

import

  // 89
  // modules.js
    export default () => 'Hello world'
    export const name = 'Arthas'

  // index.js
    import * as data from './module'
  // console.log(data) // { default: function default(), name: "Lydia" }

*import * as [name] 语法,可以将module.js中所有的 export 导入到 idnex.js 中,并创建了一个 data 的新对象。
data 对象具有默认导出 default属性,其他属性具有指定export的名称即对应的值

prototype

  // 92
  function giveArthasaPizza92() {
    return 'here is pizza'
  }
  const giveArthasChocolate92 = () => 'here`s chocolate... now go hit the gym already'

  console.log(giveArthasaPizza92.prototype); // {constructir: ...}
  console.log(giveArthasChocolate92.prototype); // undefined

常规函数是有 prototype 属性的
剪头函数是没有 prototype 属性的,尝试调用会返回 undefined

function

  // 7
  function getItems94(frultList, favoriteFruit, ...args) {
    return [...fruitList, favoriteFruit, ...args]
  }
  getItems94(["banana", "apple"], "pear", "orange") // [ 'banana', 'apple', 'orange', 'pear' ]

…args 是剩余参数,剩余参数的值是一个包含所有剩余参数的数组,只能放在最后。

  // error code
  function getItems(fruitList, ...args, favoriteFruit) {
    return [...fruitList, ...args, favoriteFruit]
  }
  getItems(["banana", "apple"], "pear", "orange") // SyntaxError

Symbol

  // 97
  const info97 = {
    [Symbol('a')]: 'b'
  }
  console.log(info); // {Symbol('a'): 'b'}
  console.log(Object.keys(info97)); // []

Symbol类型是不可枚举的,而Object.keys()是返回对象上所有可枚举的属性,所以这里打印显示为 []

error 错误汇总

  // 99 错误汇总
  /*
      SyntaxError 语法错误 a 解析代码时发生的语法错误
      ReferenceError 引用错误 a 引用了一个不存在的变量 b 将变量赋值给一个无法被赋值的对象
      RangeError 范围错误 超出有效范围
      TypeError 类型错误 a 当值不是预期类型时,会抛出TypeErrors b 调用对象不存在的方法
      URLError URL错误
      */

&&

  // 100
  let puestion100 = [] && 'im' // 'im' [] 是一个真值

Promise&async&await

  // 102
  const myPromise102 = () => Promise.resolve('i have resolved')
  function firstFunction() {
    myPromise102().then(res => console.log(res))
    console.log('second1');
  }
  async function secondFunction() {
    console.log(await myPromise102())
    console.log('second2')
  }
  firstFunction() // second1 i have resolved
  secondFunction() // i have resolved second2

Promise的执行方式是运行到 Promise,Promise进入微任务队列,知道宏任务完成(打印 ‘second1’),执行微任务(‘i have resolved’)
async/await执行方式是运行到await后,通过await关键字,暂停了后续代码的执行,直到异步代码被解析才开始后面代码的执行,也就是说 执行完 ‘i have resolved’ 之后,才去运行 console.log(‘second2’) 的

setInterval

  // 114
  let config114 = {
    alert: setInterval(() => {
      console.log('Alert');
    }, 1000)
  }
  config114 = null

一般对象赋值为null后,那些对象就会被进行 垃圾回收,因为没有对这些对象的引用了,但是 setInterval的参数是一个箭头函数,回调函数仍然保持着对config114的引用。
只要存在引用,对象就不会被垃圾回收。
所以会一直执行
如果需要暂停就要clearSetInterval()

function

  // 116
  const person116 = {
    name: 'Monica',
    age: 20
  }

  const changeAge116 = (x = { ...person116 }) => x.age += 1
  const changeAgeAndName = (x = { ...person116 }) => {
    x.age += 1
    x.name = 'Arthas'
  }
  changeAge116(person116)
  changeAgeAndName()
  console.log(person116); // { name: 'Monica', age: 21 }

changeAge 方法传递了 person116 参数,意味着 函数内 x 与 person116 在同一位置,操作 x.age 等同于操作 person116.age 所以为 { name: ‘Monica’, age: 21 }
changeAgeAndName 方法设置默认值为一个对象,内部含有解构了的 person116 ,属于一个新的对象,所以这个函数内部 x的操作并不影响 person116,所以最终打印下来是 { name: ‘Monica’, age: 21 }

可选链操作符 ?.

  // 119
  const person119 = {
    firstName: 'Arthas',
    lastName: 'Monica',
    pet: {
      name: 'Woo',
      breed: 'Dutch Tulip Hound'
    },
    getFullName() {
      return `${this.firstName} ${this.lastName}`
    }
  }

  console.log(person119.pet?.name); // Woo
  console.log(person119.pet?.family?.name); // undefined
  console.log(person119.getFullName?.()); // Arthas Monica
  console.log(member.getLastName?.()); // ReferenceError

ES10 或TS3.7+ 新增可选链操作符 ?. 不再需要显示的检测更深层的嵌套值是否有效。
如果尝试获取是 undefined or null 的值,表达式将会短路并返回undefined
person119.pet?.name: person119内是否含有pet属性,有的话获取内部属性 name 的值,否则返回undefined
person119.pet?.family?.name
等同于三元表达式:
person119.pet ? person119.pet.family ? person119.pet.family.name : undefined : undefined
person119.getFullName?.() 判断函数的话在括号()前使用其符号进行判断,有就进行调用,无则返回undefined
member.getLastName?.() 并没有member这个变量,所以走不到下一步就会报 ReferenceError

setter

  // 121
  const config121 = {
    languages: [],
    set language(lang) {
      return this.languages.push(lang)
    }
  }
  console.log(config121.language); // undefined

方法 language 是一个 setter. setter 并不保存实际的值,功能是修改属性,调用 setter ,返回 undefined

saync&generator

  // 124
  async function* range124(start, end) {
    for (let i = start; i <= end; i++) {
      yield Promise.resolve(i) // Promise{i}...
    }
  }
  (async () => {
    const gen = range124(1, 3)
    for await (const item of gen) {
      console.log(item); // 1 2 3
    }
  }
  )()

range124(1, 3)这个函数得到的值是 [Promise{1},Promise{2},Promise{3}]
在进行 for…of 前加了 await 使得原本item的值(Promise{1/2/3})得到了转变,从而拿到了 1 2 3

function

  // 125
  const myFunc125 = ({ x, y, z }) => {
    console.log(x, y.z);
  }
  myFunc125(1,2,3) // undefined undefined undefined

myFunc125函数期望接收一个包含x,y,z属性的对象作为参数。
但实际上只是传递了三个参数,并不含有x,z,y的键值对,x,z,y都含有默认值,就是undefined

解构

  // 127
  const spookyItems127 = ["👻", "🎃", "🕸"];
  ({ item: spookyItems127[3] } = { item: "💀" });
  console.log(spookyItems127); // ["👻", "🎃", "🕸", "💀"]

通过解构,可以从右边的对象中拆出来值,并将值分配给左边对象同名的属性。

Number.isNaN()/isNaN()

  // 7
  const name128 = 'Arthas'
  const age128 = 21

  console.log(Number.isNaN(name128)); // false
  console.log(Number.isNaN(age128)); // false

  console.log(isNaN(name128)); // true
  console.log(isNaN(age128)); // false

Number.isNaN() 判断传递的值是否为数字切等价于 NaN,等价为true,反则false
isNaN() 是通过参数判断是否可以转化为 Number,转化成功为 false,失败为true

Promise&saync&setTimeout

  // 133
  const myPromise133 = Promise.resolve(Promise.resolve('Promise!'))
  function funcOne133() {
    myPromise133.then(res => res).then(res => console.log(res))
    setTimeout(() => console.log("Timeout!", 0));
    console.log("funcOne Last line!");
  }

  async function funcTwo133() {
    const res = await myPromise133;
    console.log(await res);
    setTimeout(() => console.log("Timeout!", 1));
    console.log("funcTwo Last line!");
  }

  funcOne133();
  funcTwo133();
  // funcOne Last line! , Promsie! , Promise! , funcTwo Last line! , Timeout 0, Timeout 1

funcOne133
第一行是Promise异步处理
第二行是定时器,需要等调用栈为空才会执行此操作
第三行执行! funcOne Last line!
此时开始异步Promise处理,得到 Promise!
此时因为接下来还有funcTwo133,调用栈不为空,继续等待
funcTwo
第一行 await 暂停函数等待结果
第二行 log await 暂停函数,知道得到结果 打印 Promise!
第三行是定时器,需要等调用栈为空才会执行此操作
第四行执行! funcTwo Last line!
此时调用栈为空,事件队列中等待的回调函数(定时器们)在此入栈。
执行 funcOne133 函数内的定时器 “Timeout!”, 0 ,接着执行 funcTwo133 函数内的定时器 funcTwo Last line!

import

  // 134
  // 如何在index.js中调用 num.js 中的 num?
  // sun.js
    export default sum(x){
      return x + x
    }
  // index.js
    import * as sum from './index.js'

  // Answer
  // sum.default(4)

导入模块时,使用 * 会以对象中键值对的形式导入文件内所有值,包括默认和具名。
{
default: ‘默认导出’,
name: ‘Arthas’ // 普通导出
}

Object.seal()

  // 136
  const person136 = { name: 'Arthas', age: 1 }
  Object.seal(person136)
  person136.name = 'Moncica' // 可影响对象,产生副作用

Object.seal 防止新属性被添加,或存在属性被删除
但是仍然可以对存在属性进行修改

class

  // 139
  class Counter139 {
    #number = 10
    add() {
      this.#number++
    }
  }
  const counter139 = new Counter139()
  counter139.add()
  console.log(counter139.#number); // SyntaxError

ES10中,通过 # 可以给class添加私有变量。在class外部无法获取该值
尝试获取就会报语法错误

Function&Object

  // 141
  const person141 = {
    name: 'Arthas',
    hobbies: ['coding']
  }
  function addHobby141(hobby, hobbies = person141.hobbies) {
    hobbies.push(hobby)
    return hobbies
  }
  addHobby141('running', [])
  addHobby141('dancing')
  addHobby141('baking', person141.hobbies)

  console.log(person.hobbies); // ['coding', 'dancing', 'baking']

第一次函数调用:第二个参数为空数组,并没有使用默认参数,所以只是push到了空数组内
第二次:第二个参数默认使用person141.hobbies的值,这时函数内的参数 hobbies 与 person141.hobbies 的引用地址相同,所以直接 push 到了 person141对象内的 hobbies 属性中
第三次:同上,只不过是使用的参数直接就是 person141.hobbies 了,所以一样的引用地址,一样的处理方式

class

  // 142
  class Arthas142 {
    constructor() {
      console.log('i am Arthas');
    }
  }
  class Monica142 extends Arthas142 {
    constructor() {
      console.log('i am Monica');
      super()
    }
  }
  const pet142 = new Monica142()
  // i am Monica i am Arthas

当实例化这个实例(new),Monica142 中的 constructor被调用,打印 ‘i am Monica’,随后调用super(),super() 调用父类的构造函数,打印 ‘i am Arthas’

Object

  // 150
  const animals150 = {}
  let dog150 = { emoji: '🐶' }
  let cat150 = { emoji: '🐈' }

  animals150[dog150] = { ...dog150, name: "Mara" }
  animals150[cat150] = { ...cat150, name: "Sara" }

  console.log(animals150[dog150]) // { emoji: "🐈", name: "Sara" }

对象的键名会被转换成字符串。
animals150[dog150] 等同于 animals150[“object Object”]
第二次同理,也就是说 animals150对象内 “object Object” 属性的值被覆盖了。

Object

  // 151
  const user151 = {
    email: "my@email.com",
    updateEmail: email => {
      // this ---> window
      this.email = email
    }
  }

  user151.updateEmail("new@email.com")
  console.log(user151.email) // 'my@email.com'

箭头函数内的this并没有绑定user151,意味着this并不会引用 user151 对象,所以调用事件之后 user151.email 值并不会改变

我自己记录此文件的GitHub地址(希望可以得到你的肯定)

原文GitHub地址

如果对本文有疑问的话,评论区见~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值