目录
[typeof this !== 'function'](#typeof this !== 'function')
[context = context || window](#context = context || window)
[context._this = this](#context._this = this)
[delete context._this](#delete context._this)
[bind: return _this.apply(context, [...arguments].slice(1));](#bind: return _this.apply(context, [...arguments].slice(1));)
[!arr|| arr == null || typeof arr != 'object'](#!arr|| arr == null || typeof arr != 'object')
[arr instanceof Array ? [] : {}](#arr instanceof Array ? [] : {})
[result[key] = cloneDeep(arr[key])](#result[key] = cloneDeep(arr[key]))
[new :Fn=[...arguments].shift()](#new :Fn=[...arguments].shift())
*寄生组合式继承:call,create,constructor
[Object.defineProperty(obj, prop, descriptor)](#Object.defineProperty(obj, prop, descriptor))
[Object for of](#Object for of)
[*instance of](#*instance of)
[千位分割:num.slice(render, len).match(/\d{3}/g).join(',')](#千位分割:num.slice(render, len).match(/\d{3}/g).join(','))
ES6
防抖
触发事件后在 n 秒内函数只能执行一次,如果在n 秒内又触发了 事件,会重计算函数执行时间。
javascript
function debounce(fun,time) {
let flag // 定义状态
return function () {
clearTimeout(flag)// 在执行之前 清除 定时器的 flag 不让他执行
flag = setTimeout(() => {
fun.call(this,arguments)//拿到正确的this对象,即事件发生的dom
}, time)
}
}
节流
连续触发事件但是在n 秒中只执行一次函数。两种方式可以实现,分别是时间戳版和定时器版。
javascript
function throttle(fun, time) {
let flag // 定义一个空状态
return function () { // 内部函数访问外部函数形成闭包
if (!flag) { // 状态为空执行
flag = setTimeout(() => {
fns.apply(this, arguments) // 改变this指向 把 event 事件对象传出去
flag = null // 状态为空
}, time)
}
}
}
防抖、节流应用
防止某一时间频繁触发
- 防抖debounce:time内只执行一次
- search搜索联想,用户在不断输入值 时,用防抖来节约请求资源。
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
- 节流throttle: 间隔time执行
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
改变this
call
typeof this !== 'function'
context = context || window
context._this = this
delete context._this
javascript
// 给function的原型上面添加一个 _call 方法
Function.prototype._call = function (context) {
// 判断调用者是否是一个函数 this 就是调用者
if (typeof this !== 'function') {
throw new TypeError('what is to be a function')
}
// 如果有 context 传参就是传参者 没有就是window
context = context || window
// 保存当前调用的函数
context._this = this
// 截取传过来的参数
/*
arguments
a: 1
fn: ƒ fns()
*/
// 通过 slice 来截取传过来的参数
const local = [...arguments].slice(1)
// 传入参数调用函数
let result = context._this(...local)
// 删属性
delete context._this
return result
}
let obj = { a: 1 }
function fns(a, b) {
console.log(a, b);
console.log(this)
}
fns._call(obj, 23, 555)
bind: return _this.apply(context, [...arguments].slice(1));
深拷贝
!arr|| arr == null || typeof arr != 'object'
arr instanceof Array ? [] : {}
for (const key in arr)
result[key] = cloneDeep(arr[key])
javascript
function cloneDeep(arr = {}) {
// 终止递归
if (!arr|| arr == null || typeof arr != 'object' ) return arr
// 用 instanceof 判断原型链上是否有该类型的原型 是 Array => [] ! Arrays =>{}
let result=arr instanceof Array ? [] : {}
// forin 循环对象的key值
for (const key in arr) {
// 对象 key 赋值 result
result[key] = cloneDeep(arr[key])
}
return result
}
setTimeout()
倒计时
javascript
//返回值timeoutID是一个正整数,表示定时器的编号。
let timeoutID = scope.setTimeout(function[, delay]),//delay表示最小等待时间,真正等待时间取决于前面排队的消息
clearTimeout(timeoutID) //取消该定时器。
javascript
function timedCount() {
c -=1;
if(c===0){
clearTimeout(t);
return;
}
t = setTimeout(function() {
timedCount()
}, 1000);
}
setTimeout模拟实现setInterval
javascript
// 使用闭包实现
function mySetInterval(fn, t) {
let timer = null;
function interval() {
fn();
timer = setTimeout(interval, t);
}
interval();
return {
// cancel用来清除定时器
cancel() {
clearTimeout(timer);
}
};
}
setInterval模拟实现setTimeout
javascript
function mySetTimeout(fn, time) {
let timer = setInterval(() => {
clearInterval(timer);
fn();
}, time);
}
// 使用
mySetTimeout(() => {
console.log(1);
}, 2000);
new :Fn=[...arguments].shift()
"_new"函数,该函数会返回一个对象,
该对象的构造函数为函数参数 、原型对象为函数参数的原型,核心步骤有:
- 创建一个新对象
- 获取函数参数
- 将新对象的原型对象和函数参数的原型连接起来
- 将新对象和参数传给构造器执行
- 如果构造器返回的不是对象,那么就返回第一个新对象
javascript
const _new = function() {
const object1 = {}
const Fn = [...arguments].shift()
object1.__proto__ = Fn.prototype
const object2 = Fn.apply(object1, arguments)
return object2 instanceof Object ? object2 : object1
}
*寄生组合式继承:call,create,constructor
通过寄生组合式继承使"Chinese"构造函数继承于"Human"构造函数。要求如下:
-
给"Human"构造函数的原型上添加"getName"函数,该函数返回调用该函数对象的"name"属性
-
给"Chinese"构造函数的原型上添加"getAge"函数,该函数返回调用该函数对象的"age"属性
-
在"Human"构造函数的原型上添加"getName"函数
-
在"Chinese"构造函数中通过call函数借助"Human"的构造器来获得通用属性
-
Object.create函数返回一个对象,该对象的__proto__属性为对象参数的原型。此时将"Chinese"构造函数的原型和通过Object.create返回的实例对象联系起来
-
最后修复"Chinese"构造函数的原型链,即自身的"constructor"属性需要指向自身
-
在"Chinese"构造函数的原型上添加"getAge"函数
javascript
function Human(name) {
this.name = name
this.kingdom = 'animal'
this.color = ['yellow', 'white', 'brown', 'black']
}
Human.prototype.getName = function() {
return this.name
}
function Chinese(name,age) {
Human.call(this,name)//call函数借助"Human"的构造器来获得通用属性
this.age = age
this.color = 'yellow'
}
//返回的对象__proto__属性为对象参数的原型
Chinese.prototype = Object.create(Human.prototype)//使用现有的对象来作为新创建对象的原型
//修复"Chinese"构造函数的原型链,即自身的"constructor"属性需要指向自身
Chinese.prototype.constructor = Chinese
Chinese.prototype.getAge = function() {
return this.age
}
Object.defineProperty(obj, prop, descriptor)
Object.create
该函数创建一个新对象,使用现有的对象来提供新创建的对象的proto,核心步骤有:
- 创建一个临时函数
- 将该临时函数的原型指向对象参数
- 返回该临时对象的实例
Object.create法创建一个新对象,使用现有的对象来提供新创建的对象的proto。
javascript
const _objectCreate = proto => {
if(typeof proto !== 'object' || proto === null) return
const fn = function() {}
fn.prototype = proto
return new fn()
}
Object.freeze
Object.freeze = writable: false + Object.seal = writable: false + Object.preventExtensions + configable: false
- Symbol 类型作为 key 值的情况,也要冻结
- 只冻结对象自有 的属性(使用 for ... in 会把原型链上的可枚举属性遍历出来)。
- 注意不可扩展性(不能添加新属性,使用 Object.preventExtensions() 或 Object.seal() 实现,同时也相当于把原型链冻结)。
key:
- Object.getOwnPropertyNames/Symbol
- forEach
- Object.define Property:configurable,writable
- Object.preventExtensions(object)
javascript
const _objectFreeze = object => {
if(typeof object !== 'object' || object === null) {
throw new TypeError(`the ${object} is not a object`)
}
const keys = Object.getOwnPropertyNames(object);
const symbols = Object.getOwnPropertySymbols(object);
[...keys, ...symbols].forEach(key => {
Object.defineProperty(object, key, {
configurable: false,
writable: false,
})
})
Object.preventExtensions(object)
}
Object for of
javascript
// 创建一个构造函数
function MyObject() {
// 为构造函数的实例对象添加两个属性
this.prop1 = 'Value 1';
this.prop2 = 'Value 2';
}
// 在原型上添加一个自定义的迭代器方法
MyObject.prototype[Symbol.iterator] = function () {
// 获取实例对象的所有属性名并存储在数组 keys 中
const keys = Object.keys(this);
let index = 0;
// 返回一个迭代器对象,包含 next 方法
return {
next: () => {
// 如果还有属性未遍历完
if (index < keys.length) {
// 获取当前属性名 key,并递增索引 index
const key = keys[index++];
// 返回包含当前属性名和对应值的对象,并设置 done 为 false 表示未遍历完
return { value: [key, this[key]], done: false };
} else {
// 如果所有属性都已遍历完,返回 done 为 true 表示遍历结束
return { done: true };
}
},
};
};
// 创建一个实例对象
const instance = new MyObject();
// 使用 for...of 遍历实例对象的属性
for (const [key, value] of instance) {
// 打印属性名和对应值
console.log(key, value);
}
*instance of
- 获取首个对象参数的原型对象
- 获取Fn函数的原型对象
- 进入死循环,当两个参数的原型对象相等时返回true
- 当两个参数的原型对象不相等时获取首个对象参数原型的原型并且循环该步骤直到null时返回false
javascript
const _instanceof = (target, Fn) => {
let proto = target.__proto__
let prototype = Fn.prototype
while(true) {
if(proto === Fn.prototype) return true
if(proto === null) return false
proto = proto.__proto__
}
}
const _instanceof = (target, Fn) => {
return Fn.prototype.isPrototypeOf(target);
}
算法
合法的URL
URL结构一般包括协议、主机名、主机端口、路径、请求信息、哈希
- 域名不区分大小写:"www"子域名(可选)、二级域名、"com"顶级域名
- 只能包含字母(a-z、A-Z)、数字(0-9)和连字符(-)(但-不能再首尾)
javascript
https://www.bilibili.com/video/BV1F54y1N74E/?spm_id_from=333.337.search-card.all.click&vd_source=6fd32175adc98c97cd87300d3aed81ea
//开始: ^
//协议: http(s)?:\/\/
//域名: [a-zA-Z0-9]+-[a-zA-Z0-9]+|[a-zA-Z0-9]+
//顶级域名 如com cn,2-6位: [a-zA-Z]{2,6}
//端口 数字: (:\d+)?
//路径 任意字符 如 /login: (\/.+)?
//哈希 ? 和 # ,如?age=1: (\?.+)?(#.+)?
//结束: $
// https:// www.bilibili com /video/BV1F54y1N74E ?spm..
/^(http(s)?:\/\/)?(([a-zA-Z0-9]+-[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)+([a-zA-Z]{2,6})(:\d+)?(\/.+)?(\?.+)?(#.+)?$/.test(url)
千位分割:num.slice(render, len).match(/\d{3}/g).join(',')
javascript
const format = (n) => {
let num = n.toString() // 拿到传进来的 number 数字 进行 toString
let len = num.length // 在拿到字符串的长度
// 当传进来的结果小于 3 也就是 千位还把结果返回出去 小于3 不足以分割
if (len < 3) {
return num
} else {
let render = len % 3 //传入 number 的长度 是否能被 3 整除
if (render > 0) { // 说明不是3的整数倍
return num.slice(0, render) + ',' + num.slice(render, len).match(/\d{3}/g).join(',')
} else {
return num.slice(0, len).match(/\d{3}/g).join(',')
}
}
}
let str = format(298000)
console.log(str)