携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
01.实现一个new
实现步骤:
- 创建一个新的对象
- 让这个对象的隐式原型 (
__proto__)指向显示原型(prototype) - 改变构造函数的this指向,让构造函数的this指向新创建的对象
- 执行构造函数
- 如果构造函数中没有返回对象,则返回上面创建出来的对象
function MyNew(fn, ...args) {
// 创建一个新对象
let obj = {}
// 让这个对象的隐式原型 (__proto__)指向显示原型(prototype)
obj.__proto__ = fn.prototype
// 改变构造函数的this指向,让构造函数的this指向新创建的对象,
// 执行构造函数
fn.apply(obj, args)
// 如果构造函数中没有返回对象,则返回上面创建出来的对象
return obj
}
function Person(name, age) {
this.name = name
this.age = age
}
let p = new Person('小明', 10)
let p1 = MyNew(Person, '二明', 20)
console.log(p)
console.log(p1)
02.Js实现继承
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.eat = function () {
console.log('我会吃饭');
}
function Student(name, age, className) {
Person.call(this, name, age)
this.className = className
}
// 继承父类的共有属性
// 子类的 显示原型指向父类的 显示原型
Student.prototype = Object.create(Person.prototype)
// 并且原型的构造函数指向自己
Student.prototype.constructor = Student
let s = new Student('小明', 10, '六年级')
console.log(s.name)
console.log(s.age)
console.log(s.className)
s.eat()
03.实现instanceof
instanceof 的作用,就是判断一个对象是否属于某个类
接上面的继承而来的移到题目
console.log(s instanceof Person)
console.log(s instanceof Student)
实现:
function MyInstanceof(left, right) {
// 就是让左边的对象实例去找 右边的构造函数的原型
let l = left.__proto__;
let r = right.prototype
// 如果从对象的原型向上找不为 null ,就一直向上找
while (l) {
if (l === r) return true
l = l.__proto__
}
return false
}
console.log(MyInstanceof(s, Student))
console.log(MyInstanceof(s, Person))
04.实现call
call的作用
- 指定函数内部的
this - 让函数执行
Function.prototype.MyCall = function (context) {
// 参数检测
context = context ? Object(context) : window
// 拿到要执行的函数 ,其实就是原来的函数 fn.MyCall()
// 谁调用的MyCall谁就是 this
// 给 第一个参数添加一个属性,等于正在调用的函数,
// 收集参数
let args = []
for (let i = 1; i < arguments.length; i++) {
args.push(arguments[i])
}
context.fn = this
let ret = context.fn(...args)
delete context.fn
return ret
}
let obj = {
name: '小明'
}
function fn(a, b) {
console.log(this)
return a + b
}
console.log(fn.MyCall(obj, 1, 2))
05.实现apply
作用:
- 也是改变
this指向,只不过传递的参数是一个数组
实现:
Function.prototype.MyApply = function (context, args) {
// 参数检测
context = context ? Object(context) : window
// 拿到要执行的函数 ,其实就是原来的函数 fn.MyApply()
// 谁调用的谁就是 this
// 给 第一个参数添加一个属性,等于正在调用的函数
context.fn = this
if (!args) {
return context.fn()
}
let ret = context.fn(...args)
delete context.fn
return ret
}
let obj = {
name: '小明'
}
function fn(a, b) {
console.log(this)
return a + b
}
console.log(fn.MyApply(obj, [1, 2]))
06.实现bind
功能:
- 改变函数的
this指向 - 返回出一个新的函数
代码实现:
Function.prototype.MyBind = function (context) {
context = context ? Object(context) : window
// 取外层函数的参数
let outArgs = Array.prototype.slice.call(arguments, 1)
let that = this // 保存外部函数
function res() {
// 收集内层参数
let innerArgs = Array.prototype.slice.call(arguments)
// 执行原函数
return that.apply(context, outArgs.concat(innerArgs))
}
return res
}
let obj = {
name: '小明'
}
function fn(a, b) {
console.log(this)
return a + b
}
// 返回一个新的函数
let res = fn.MyBind(obj, 1, 2)
console.log(res())
07.实现map方法
功能:
- 遍历数组,接受一个函数。
Array.prototype.MyMap = function (fn) {
// 保存结果
let ret = []
// this 就是当前调用的数组
let arr = this
// 遍历数组
for (let i = 0; i < arr.length; i++) {
// 拿到 fn的返回结果,放到最终的结果里面
ret.push(fn(arr[i], i, arr))
}
return ret
}
let arr = [1, 2, 3]
console.log(arr.MyMap((item) => item * 2))
08.实现find函数
Array.prototype.MyFind = function (fn) {
let arr = this
for (let i = 0; i < arr.length; i++) {
if (fn(arr[i], i, arr)) {
return arr[i]
}
}
}
// 找到符合条件的第一个元素
console.log([1, 2, 3].MyFind(item => item > 1))
09.实现filter函数
// 返回一个新数组
// 找到符合条件的元素放到新数组里面
Array.prototype.MyFilter = function (fn) {
let ret = []
let arr = this
for (let i = 0; i < arr.length; i++) {
if (fn(arr[i], i, arr)) {
ret.push(arr[i])
}
}
return ret
}
console.log([1, 2, 3, 4].MyFilter(item => item > 1));
10.实现some函数
// 如果有一个符合条件,就返回 true
// 否则返回 false
Array.prototype.MySome = function (fn) {
let arr = this
for (let i = 0; i < arr.length; i++) {
if (fn(arr[i], i, arr)) {
return true
}
}
return false
}
console.log([1, 2, 3].MySome(item => item > 100));
11.实现every方法
// 所有条件都满足,才返回 true
Array.prototype.MyEvery = function (fn) {
let arr = this
for (let i = 0; i < arr.length; i++) {
if (!fn(arr[i], i, arr)) {
return false
}
}
return true
}
console.log([1, 2, 3, 4].MyEvery(item => item > 10));
12.reduce方法
Array.prototype.MyReduce = function (fn, initialValue) {
// 拿到数组
let arr = this
// 先检测有没有传初始值
let val = initialValue ? initialValue : this[0]
// 计算 循环的初始位置
let index = initialValue ? 0 : 1
for (let i = index; i < arr.length; i++) {
// 将 fn 函数计算的结果重新赋值给 val,
// 当做下一次调用 fn 函数的第一个参数
val = fn(val, arr[i], index, arr)
}
return val
}
console.log([1, 2, 3, 4, 5].MyReduce((acc, curr) => {
return acc += curr
}, 5))
13.实现findIndex方法
找到满足条件的元素的 索引
Array.prototype.MyFindIndex = function (fn) {
let arr = this
for (let i = 0; i < arr.length; i++) {
if (fn(arr[i], i, arr)) {
return i
}
}
return -1
}
console.log([1, 2, 3].MyFindIndex(item => item === 2))
14.实现concat方法
Array.prototype.MyConcat = function (...args) {
console.log(args)
// 返回一个新的数组
let ret = []
// 取出原数组
let arr = this
if (!args) return [...arr]
// 遍历 args
for (let i = 0; i < args.length; i++) {
if (Array.isArray(args[i])) {
arr.push(...args[i])
} else {
arr.push(arr[i])
}
}
ret = [...arr]
// 返回一个新数组
return ret
}
let x = [1, 2, 3].MyConcat([4], [5])
console.log(x)
15.实现防抖函数
- 每次执行
fn函数的时候把上一次的定时器清空
let input = document.querySelector('input')
// 调用形式,返回的是一个函数
function MyDebounce(fn, delay) {
let timer = null
let _debounce = function () {
// 在每次调用 debounce 函数之前,先清空上一次的定时器
clearTimeout(timer)
timer = setTimeout(() => {
fn()
timer = null
}, delay);
}
return _debounce
}
input.oninput = MyDebounce(function () {
console.log('hihiihi');
}, 1000)
16.实现节流函数
- 无论函数调用的频率有多快,但是它真实
执行的频率是一定的。
节流函数原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效
例:(连续不断动都需要调用时用,设一时间间隔),像dom的拖拽,如果用消抖的话,就会出现卡顿的感觉,因为只在停止的时候执行了一次,这个时候就应该用节流,在一定时间内多次执行,会流畅很多
function MyThrottle(fn, wait) {
let lastTime = 0
let _throttle = function () {
// 当前时间
let now = new Date().getTime()
// 如果当前时间 - 上一次执行时间的差值 大于设置的等待时间就执行函数
if (now - lastTime > wait) {
lastTime = now
fn()
}
}
return _throttle
}
let input = document.querySelector('input')
input.oninput = MyThrottle(function () {
console.log('hiihi')
}, 1000)