Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1 - JavaScript 基础 #1

Open
Linjiayu6 opened this issue Jun 3, 2020 · 17 comments
Open

1 - JavaScript 基础 #1

Linjiayu6 opened this issue Jun 3, 2020 · 17 comments

Comments

@Linjiayu6
Copy link
Owner

Linjiayu6 commented Jun 3, 2020

JS 基础

[JS基础] 1 - 内存空间

- 基本类型, 引用类型
- 变量对象 和 堆内存

[JS基础] 2 - 执行上下文

- JS执行环境: 全局, 函数环境, eval
- 执行栈: 全局在最底下, 函数执行才入栈, 遇到return立刻出栈

[JS基础] 3 - 变量对象 Variable Object

- 函数的执行上下文 Execution Context, 分为两个阶段 创建 和 执行
- 创建阶段 VO: 变量声明,函数声明提升
- 执行阶段 AO (入栈执行)

[JS基础] 4 - 作用域与作用域链 scope / scope chain

- EC创建阶段: VO, 作用域链, this
- EC执行阶段: AO赋值, 其他code .....

[JS基础] 5 - 闭包 Closure

1. 函数执行的地方: Function Call Stack 函数调用栈
2. 在Function Call Stack 函数调用栈里面,存放着可执行上下文EC
3. 执行上下文EC, 告诉函数你周遭的环境是什么样的。
   生命周期有两个:
   - 创建: 又可以简单的理解为 你写代码的环境。主要负责VO, scopechain, this 的声明。
        声明包含函数提升声明 和 变量声明
        变量给它分配个内存空间, 函数或对象类型的是key分配个内存空间,对象类型放到堆内存中。

   - 执行: 负责AO参数赋值, 其他代码执行。

4. 可执行环境分为: 全局环境 和 函数环境。可以简单理解为作用域
   而作用域链是在你写代码阶段已确定的作用域环境。

5. 当EC在执行阶段,会push进函数调用栈,此时当前函数里参数的获取 是按照作用域链创建的来的。
6. 闭包: 我个人理解是作用域链的应用。上级函数保存当前函数执行的内容。

[JS基础] 6 - 执行机制, 同步异步, 事件循环, 宏任务, 微任务

# 事件循环 Event Loop
本质是: 
1. 作为单线程js对于异步事件的处理机制 

2. 或者可以说是 只有一个主线程js的处理逻辑

3. 如何保证主线程, 有序并高效 或非阻塞 的处理呢? => 事件循环机制 Event Loop

4. 异步任务也是有优先级的,分为 宏任务 MacroTask, 微任务 MicroTask

[JS基础] 7 - this, call/apply/bind/箭头函数

1. 在执行上下文 EC 的创建阶段this已经被创建出来了

2. 独立函数运行,this指向函数内部, 但因为非严格模式下,this 会指向window
   对象调用的函数,this指向对象

3. this绑定
   - call, apply
   - bind
   - 利用闭包和apply你自己实现个 bind方法
   - 手动绑定 例如const that = this

[JS基础] 8 - 从 Chrome 看 闭包 / this / 作用域链

闭包的产生条件:

函数a 里 写着函数b。
b执行的时候, 用到了a_EC.VO  a的执行下上文的变量对象。
(要用到人家a里的才产生, 知道window下的不算)

[JS基础] 9 - 函数式编程 Functional Programming

没有完成 TODO

[JS基础] 10 - 构造函数 原型 原型链 继承 new

创建对象
- 工厂模式? 问题是重复分配内存给相同的函数或方法,寻求共享模式。
- 构造函数? 对象私有化
- prototype: 方法共享方式 (其实也是利用引用类型)。
  __proto__: 指针, 某个对象要使用共享方法, 用指针指向该引用类型即可。
  prototype chain: 继承 想共享方法都连在一起。

- 继承? 原理是什么? prototype chain
- new都干了啥? 创建对象,私有内容赋值(this的绑定),指针__proto__指向共享的公共内容

[JS基础] 11 - Promise

[JS基础] 12 - 深拷贝 VS 浅拷贝

1. 值类型 基本类型 or 引用类型?
2. 遍历对象的三个方法及不同? (for - in , Object.keys() ,  Object.getOwnPropertyNames())
3. 浅拷贝?
4. 浅拷贝 + 迭代? code? 问题? 解决?
5. 深拷贝? 
   三种 (JSON, 浅拷贝+循环, 浅拷贝+循环+校验)
6. 会遇到什么问题? 怎么解决?

[JS基础] 13 - 其他 JS 基础

[JS基础] 14 - V8的回收机制 ♻️ / 内存泄露

[JS基础] 15 - 节流 防抖 / Event Bus / new实现

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jun 11, 2020

实现caller

npm 版本规则
websocket polling
笔试 css九宫格 异步任务并发数限制
js array string api https://www.jianshu.com/p/5477e281c30e

1. 懒加载与动态 import 语法的坑
3. 说说怎么本地调试 npm 包,考察 npm link
6. Tree-shaking 原理
7. 微前端了解多少,如果让你做微前端的技术选型,你怎么考虑
8. 疯狂问项目,思考和看法

11. Node 框架用的什么, Koa 与 Express 相比有什么不同
12. Node 服务部署,运维 /  node容灾处理  🔥  / node如何捕获异常 🔥
13. 懒加载怎么做 / 懒加载原理实现方法 🔥 🔥
15. Node 底层了解多少
17. 用户弱网环境问题排查与优化
19. SSO 鉴权流程
24. 如何自己实现一个组件按需加载
30. Node Stream 是干什么的
34. async 的异常捕获
42. 聊聊尾递归 / 尾递归函数优化 🔥
47. 扫码登录的实现逻辑
56. 算法,最大连续子序列(dp) 🔥
67. 将json字符串'{"a": 1, "b": "str", "c":[2, 3], "d":{"e": 4}}'
69. 给定一个数组,求该数组所有的自子数组
78. 买卖股票一次获得的最大利润(动态规划)  🔥
82. 对flutter的了解 🔥

1. 单链表的对折 🔥
2. 块级作用域  IIFE 🔥 🔥 🔥
3. 你项目怎么接入ci的,整个流水线是怎样【描述】
git提交 => lint执行 => 触发hook => 读取yml文件执行命令 => 部署 => 调用机器人接口发布企业微信群周知
4. web worker 🔥
https://leetcode-cn.com/problems/add-two-numbers/

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jun 23, 2020

面试可参考
Google面试
2020年前端面试复习必读精选文章

  • 1 - this / apply / call / bind
  • 2 - debounce 防抖 / throttle 节流
  • 3 - 深拷贝 浅拷贝
  • 4 - EventBus
  • 5 - instanceOf
  • 6 - new 实现
  • 7 - Object.create() 实现
  • 8 - 继承 / 构造函数 / 原型继承
  • 9 - JSONP
  • 10 - 数组拍平
  • 11 - Promise / Promise.all / Promise.race 串行异步 或 并行异步
  • 12 - 迭代器Iterator
  • 13 - Symbol.iterator 实现对象在for of上可遍历

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 3, 2020

1 - this / apply / call / bind 实现

1.1 - apply / call

/**
 * fn.apply(context, [xxx])
 * fn.call(context, a, b, c, ...)
 * fn.bind(context)(a, b, c)
 */
Function.prototype._call_ = function (context) {
  var context = Object(context) || window // Object() 自动包装对象
  // let args = [...arguments].slice(1);
  const args = Array.prototype.slice.call(arguments, 1)
  // 放在对象或window去执行, this是 调用该方法的函数 eg: A.call(xxx), this 是 A
  context.fn = this
  
  var result = context.fn(...args)
  delete context.fn
  return result
}

function fn (...args) { console.log(this.a, args) }
const obj = { a: 1, b: 2}

fn._call_(obj, '参数')
Function.prototype._apply_ = function (context) {
  var context = context || window
  const args = Array.prototype.slice.call(arguments, 1)
  context.fn = this
  context.fn(...args)
  delete context.fn
}
fn._apply_(obj, [1, 2, 3])

1.2 - bind

基础版本

Function.prototype._bind_ = function (context) {
  context = context || window

  let args = Array.prototype.slice.call(arguments, 1)
  const fn = this
  return function () {
    const bindArgs = Array.prototype.slice.call(arguments, 0)
    return fn.apply(context, args.concat(bindArgs))
    // 或 fn.call(context, ...argList)
  }
}

const obj = { name: 1 }
function executor (age, unv) {
  console.log(this.name)
  console.log(age)
  console.log(unv)
}
executor._bind_(obj)(18, 'hkbu')

进阶版本 - new this指向会丢失 🔥

sisterAn/JavaScript-Algorithms#81

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 3, 2020

2 - debounce 防抖 / throttle 节流

/**
 * 【debounce 防抖】
 *   场景: 输入框输入查询内容,接口请求,新内容都需要每次都重新请求接口
 *   触发后, 如果有重复触发的, 都再次重新执行

 * 【throttle 节流】 
 *   场景: 避免多次触发 例如已经提交过的, 在处理中的不允许再次提交
 *   eg: 往下拉刷新接口等,需要锁住 防止多次下拉刷新提交
 *   正在执行的, 不允许触发执行
 */

const throttle = (fn, delay) => {
  let flag = true
  return (...args) => {
    if (flag === false) return
    flag = false
    setTimeout(() => { 
      fn.call(this, ...args)  // 这里容易错
      flag = true
    }, delay)
  }
}

const debounce = (fn, delay) => {
  let timer = null
  return (...args) => {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, delay)
  }
}

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 3, 2020

3 - 深拷贝 浅拷贝

[对象key值遍历] Object.keys = for in + hasOwnProperty

[类型判断] Object.prototype.toString.call(value) [object Object] 类型判断 

[队列从头pop] array.shift()

浅拷贝

const shallowClone = target => {
  // for in + hasOwnProperty 或 Object.keys()
  const result = {}
  for (let key in target) {
    if (target.hasOwnProperty(key)) {
      result[key] = target[key]
    }
  }
  return result
}

深拷贝I: 递归 + 浅拷贝

const deepClone1 = target => {
  const result = {}
  
  Object.keys(target).forEach(key => {
    const value = target[key]
    // Object.prototype.toString.call(value) 类型判断
    if (Object.prototype.toString.call(value) === '[object Object]') {
      result[key] = deepClone1(value)
    } else {
      result[key] = value
    }
  })
  return result
}

深拷贝II: JSON.parse(JSON.stringify(xxxx))

JSON.parse(JSON.stringify(obj))

深拷贝III: 浅拷贝 + 迭代 + 重复引用处理 => N叉🌲 遍历

  • shift() 从队列头pop
const deepClone2 = source => {
  const dictionary = {}
  const result = {}

  const stack = [{ source, result }]
  while (stack && stack.length !== 0) {
    const { source, result } = stack.shift() // 从头移除一个 或用 pop也行

    Object.keys(source).forEach(key => {
      const value = source[key]

      if (dictionary[key] === value) {
        console.error('err 重复引用类型')
        return 
      }

      dictionary[key] = value
      if (Object.prototype.toString.call(value) === '[object Object]') {
        result[key] = {}
        stack.push({ source: value, result: result[key] })
      } else {
        result[key] = value
      }
    })
  }
  return result
}
var target = {
  a: {
    b: {
      c: 123
    }
  },
  d: {
    e: 456
  },
  f: 111
}

function deepClone (target) {
  var result = {}
  var map = new Map()
  // [{ key: a, val: { ... }, result }, { key: d, val: { ... }, result }, { key: f, val: 111, result }]
  var stack = Object.keys(target).map((key) => ({ key, val: target[key], obj: result }))

  while (stack && stack.length > 0) {
    var { key, val, obj } = stack.shift()

    // 重复引用过滤
    if (map.get(key) === val) return
    map.set(key, val)
    if (Object.prototype.toString.call(val) === '[object Object]') {
      var temp = Object.keys(val).map(i => {
        obj[key] = {}
        return { key: i, val: val[i], obj: obj[key] }
      })
      stack = stack.concat(temp)
    } else {
      obj[key] = val
    }
  }

  return result
}

deepClone(target)

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 3, 2020

4 - EventBus

class EventEmitter {
  constructor () {
    this.queueObj = {}
  }

  on (key, fn) {
    if (typeof key !== 'string' && typeof fn !== 'function') {
      return
    }

    if (key in this.queueObj) {
      this.queueObj[key].push(fn)
    } else {
      this.queueObj[key] = [fn]
    }
  }

  emit (key, ...args) {
    if (key in this.queueObj) {
      this.queueObj[key].forEach((fn) => {
        if (args.length > 0) {
          fn.apply(this, args)
        } else {
          fn.call(this)
        }
      })
    } else {
      console.error('没有该key值')
    }
  }

 delete (key) {
    if (key in this.queueObj) {
      delete this.queueObj[key]
    }
  }

  remove (key, fn) {
    if (this.queueObj[key]) {
      const index = this.queueObj[key].indexOf(fn)  // 数组.indexOf(查询内容位置)
      if (index > -1) {
        this.queueObj[key].splice(index, 1) // splice 删除第index的结点开始 1个
      }
    }
  }

  get (key) {
    if (key in this.queueObj) {
      console.log(this.queueObj[key])
    } else {
      console.error('error get�失败')
    }
  }
}

const event = new EventEmitter()
event.on('key', function (x) { console.log('x', x) })
event.on('key', function (y) { console.log('y', y) })
event.on('key', function (z) { console.log('z', z) })

event.emit('key', [1, 2, 3])
event.get('key')

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 3, 2020

5 - instanceOf

/*
   instanceObj instanceOf Class 实例对象是否属于某个类
   eg: p instanceof Person
   
   instanceObj = new Class()
   instanceObj._proto_ = Class.prototype 🔥
   Class.prototype.constructor = Class

  只需要判断, 实例对象 _proto_ 指针是否指向 类的原型
*/

function _instanceOf (instanceObj, Class) {
  const target = Class.prototype   
  const proto = instanceObj._proto_
  while (proto) {
    if (proto === target)  return true 
    proto = proto._proto_
  }

  return false
}

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 3, 2020

6 - new

function _new (Class, ...args) {
 // 1. 创建对象
  const obj = {}

 // 2. 公共方法或属性指向
 // 或 obj = Object.create(Class.prototype)
  obj.__proto__ = Class.prototype

 // 3. 私有属性或方法执行
  const result = Class.apply(obj, args)

 // 4. 如果返回的不是一个对象, 则直接返回obj
  return result instanceof Object ? result : obj
}

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 3, 2020

7 - Object.create() 实现

目的: 在原型链上层 再封装个proto

xxx = {
  _proto_: { 
     prototype
   }
}

// Object.create(原型对象) 封装个指针指向目标值
const objectCreate = prototype => {
  // 目标 obj._proto_ = prototype
  function F () {}
  F.prototype = prototype
  return new F()
}

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 3, 2020

8 - 继承

1. 构造函数继承  
Parent.apply(this, argsArr) 默认返回this
Parent.call(this, a, b, c) 默认返回this

2. 原型方法继承  I  
# 本质: 包一层_proto_ 指向公共
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child

3. 原型方法继承  II 
# 本质: 包一层_proto_ 指向公共
Child.prototype = new Parent()
Child.prototype.constructor = Child

4. ES6
class A extends React.Component {
    constructor (props) {
       super(...props)
    }
}
// 1. 继承构造器里的内容 直接执行Class就行
// 2. 继承原型的方法, 原型链的创建
function Parent (surname, home) {
  this.surname = surname
  this.home = home
}

Parent.prototype = {
  construtor: Parent,
  getParent: function () { console.log(this.surname + this.home) }
}

// 🔥  继承构造器内容
function Child (surname, home, givename) {
  Parent.call(this, surname, home)

  // const args = Array.prototype.slice.call(arguments) 类数组转为数组
  // Parent.apply(this, args)
  this.givename = givename 
}

//  🔥  原型链继承方式 Child.prototype = { _proto_: { Parent.prototype } }
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
Child.prototype.getChild = function () {
  console.log(this)
}

// 或者 
Child.prototype = new Parent()
Child.prototype.constructor = Child

const child = new Child('林', '中国', '😃')
child.getChild()
child.getParent()

console.log(child instanceof Child)
console.log(child instanceof Parent)

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 4, 2020

9 - JSONP

  • 一定是 ....?xxxx&callback=callbackName
  • callback 作为参数, 必须使用该值
  • callbackName 是回调的名称 用来window绑定 eg: window[callbackName]
  • 最后使用return new Promise() .... 将结果传递
function JSONP (options = {}) {
    const { url = '', paramsObj = {}, callbackName = '' } = options
    if (typeof(url) !== 'string' || typeof(callbackName) !== 'string') {
        console.error('url or callbackName formatting error')
        return
    }

    if (Object.prototype.toString.call(paramsObj) !== '[object Object]') {
        console.error('paramsObj formatting error')
        return
    }

    // 处理 paramsObj 重点是这里, 一定要是callback结尾
    paramsObj.callback = callbackName
    let paramList = []
    for (let key in paramsObj) {
        const value = paramsObj[key]
        paramList.push(key + '=' + value)
    }
    const paramstr = paramList.join('&')
    const reqUrl = url + '?' + paramstr

    // 处理标签
    const el = document.createElement('script')
    el.setAttribute('src', reqUrl)
    document.body.appendChild(el)

    // 回调处理 🔥
    return new Promise((resolve, reject) => {
        window[callbackName] = (resp) => {
            resolve(resp)
            delete window[callbackName]
            el.parentNode.removeChild(el)
        }
    })
}

JSONP({
    url: 'http://photo.sina.cn/aj/index',
    paramsObj: {
        page: 1,
        cate: 'recommend'
    },
    callbackName: 'jsoncallback'
}).then(data => {
    console.log(data)
})

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 4, 2020

10 - 数组拍平

  • reduce + 递归
  • 循环 + 递归
  • array.flat(Infinity)
const array = [1, [2], [3, [4, [5]]]]

// 拍平
function flatten (array, result = []) {
    for (let i = 0; i < array.length; i ++) {
        // 递归完成
        // Array.isArray(array[i])
        if (Object.prototype.toString.call(array[i]) === '[object Array]') {
            flatten(array[i], result)
        } else {
            result.push(array[i])
        }
    }
    return result
}
console.log(flatten(array, []))

// 用reduce实现
function flatten_reduce (array) {
    array.reduce((accumulator, current) => {
        if (Array.isArray(current)) {
            return accumulator.concat(flatten_reduce(current)) // 需要再次递归完成
        } else {
            return accumulator.concat(array) // 直接连接
        }
    }, [])
}
flatten_reduce(array)

@Linjiayu6
Copy link
Owner Author

11 - Promise 实现

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 9, 2020

12 - Iterator 迭代器实现 (单链表结构)

/**
 * 迭代器 Iterator
 * 
 * 本质: 单链表 SingleLinkList
 * 引用: Generator -> async await
 * 描述: [666, 888, 000]
 *      指针默认指向0位置, 当执行 返回 { done: 是否到头标识, value: 当前值 }
 *      例如: 
 *      it = iterator([666, 888, 000])
 *      it.next() // { done: false, value: 666 }
 *      it.next() // { done: false, value: 888 }
 *      it.next() // { done: true, value: 000 } / 到头了 不允许再往下了
 */


function _iterator_ (queue) {
  let pointer = 0
  return {
    next: function () {
      // 迭代器 到头了
      if (pointer === queue.length - 1) {
        return { done: true, value: queue[pointer] }
      }
      pointer ++ // 指针指向
      return { done: false, value: queue[pointer - 1] }
    }
  }
}

let it = _iterator_([666, 888, 000])
console.log(it.next()) // {done: false, value: 666}
console.log(it.next()) // {done: false, value: 888}
console.log(it.next()) // {done: true, value: 0}

@Linjiayu6
Copy link
Owner Author

13 - Symbol.iterator 实现对象 for of 可遍历

Obj.prototype[Symbol.iterator] 原型链上写该方法即可

class Obj {
  constructor(value) {
    this.value = value
    this.next = null
  }

  // Obj.prototype[Symbol.iterator] 写迭代器方法
  [Symbol.iterator] = function () {
    let current = this
    return {
      next: function () {
        if (current) {
          const value = current.value
          current = current.next // 指向下一个指针
          return { done: false, value }
        }
    
        return { done: true, value: undefined }
      }
    }
  }
}

var one = new Obj(1)
var two = new Obj(2)
var three = new Obj(3)

one.next = two
two.next = three
console.log(one)

for (let p of one) {
  console.log(p)
}

image

@mayuelei66
Copy link

good jiayu!

@Dragon-Rider
Copy link

nice jaiyu!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants