-
Notifications
You must be signed in to change notification settings - Fork 2
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
Comments
|
面试可参考
|
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指向会丢失 🔥 |
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)
}
} |
3 - 深拷贝 浅拷贝
浅拷贝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叉🌲 遍历
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) |
4 - EventBusclass 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') |
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
} |
6 - newfunction _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
} |
7 - Object.create() 实现目的: 在原型链上层 再封装个proto xxx = {
_proto_: {
prototype
}
}
// Object.create(原型对象) 封装个指针指向目标值
const objectCreate = prototype => {
// 目标 obj._proto_ = prototype
function F () {}
F.prototype = prototype
return new F()
} |
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) |
9 - JSONP
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)
}) |
10 - 数组拍平
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) |
11 - Promise 实现 |
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} |
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)
} |
good jiayu! |
nice jaiyu! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
JS 基础
[JS基础] 1 - 内存空间
[JS基础] 2 - 执行上下文
[JS基础] 2.1 - 函数声明 变量声明
[JS基础] 2.2 - 类型及类型判断
[JS基础] 3 - 变量对象 Variable Object
[JS基础] 4 - 作用域与作用域链 scope / scope chain
[JS基础] 5 - 闭包 Closure
[JS基础] 6 - 执行机制, 同步异步, 事件循环, 宏任务, 微任务
[JS基础] 7 - this, call/apply/bind/箭头函数
[JS基础] 8 - 从 Chrome 看 闭包 / this / 作用域链
[JS基础] 9 - 函数式编程 Functional Programming
[JS基础] 10 - 构造函数 原型 原型链 继承 new
[JS基础] 11 - Promise
[JS基础] 12 - 深拷贝 VS 浅拷贝
[JS基础] 13 - 其他 JS 基础
[JS基础] 14 - V8的回收机制 ♻️ / 内存泄露
[JS基础] 15 - 节流 防抖 / Event Bus / new实现
The text was updated successfully, but these errors were encountered: