手写代码实现
防抖和节流
防抖
function debounce(func, ms = 500) {
let timer;
return function (...args) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(this, args);
}, ms);
};
}
节流
function throttle(fn, delay) {
// 记录上一次函数触发的时间
var lastTime = 0;
return function() {
// 记录当前函数触发的时间
var nowTime = Date.now();
if (nowTime - lastTime > delay) {
// 修正this指向问题
fn.call(this);
// 同步时间
lastTime = nowTime;
}
}
}
手动实现new
JS里面new的使用方法
//构造函数
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.height = 1.88
Person.prototype.eat = function () {
console.log(this.name + ' eat')
}
var john = new Person('john', 18)
console.log(john.name,john.age,john.height)//john 18 1.88
john.eat()//john eat
手动实现new第一版代码
//第一版代码
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.height = 1.88
Person.prototype.eat = function () {
console.log(this.name + ' eat')
}
//new_ 函数为我们实现的new方法
function new_(){
var obj = new Object()
var Constructor = [].shift.call(arguments)//取出第一个参数顺便去掉arguments第一个参数
obj.__proto__ = Constructor.prototype//让实例的__proto__指向构造函数的prototype
Constructor.apply(obj,arguments)//apply和call的区别就是传入参数的区别,apply传入数组,所以这里要用apply
return obj
}
var owen = new_(Person,'owen',20)
console.log(owen.name,owen.age,owen.height)
owen.eat()
但是函数如果有返回值情况会有一点变化
1.返回一个对象
//构造函数 返回一个对象
function Person(name, age) {
this.name = name
this.age = age
return {
name: name,
age: age
}
}
Person.prototype.height = 1.88
Person.prototype.eat = function () {
console.log(this.name + ' eat')
}
var john = new Person('john', 18)
console.log(john.name,john.age,john.height)//john 18 undefined
john.eat()//TypeError: john.eat is not a function
如果返回的是对象的话,实例只能访问到返回对象中的属性
2.返回一个基本数据类型
//构造函数 返回的是一个基本数据类型
function Person(name, age) {
this.name = name
this.age = age
return 'hello'
}
Person.prototype.height = 1.88
Person.prototype.eat = function () {
console.log(this.name + ' eat')
}
var john = new Person('john', 18)
console.log(john.name,john.age,john.height)//john 18 1.88
john.eat()//john eat
如果返回一个基本数据类型,则会忽略这个返回值,依然返回创建的实例对象
所以重写new方法还需要考虑返回值的类型
// 第二版的代码
function new_() {
var obj = new Object(),
Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
var ret = Constructor.apply(obj, arguments);
return typeof ret === 'object' ? ret : obj;
};
手动实现call / apply / bind
call
//手动实现call
Function.prototype.call2 = function(context,...args){
if(typeof context !== object || typeof context !== function){
context = Object(context)
}
var result,
key = Symbol('key')
context[key] = this
result = context[key](...args)
delete context[key]
return result
}
apply
//手动实现apply
//apply的参数是用数组传递
Function.prototype.apply2 = function(context,args){
if(typeof context !== object || typeof context !== function){
context = Object(context)
}
var result,
key = Symbol('key')
context[key] = this
result = context[key](...args)
delete context[key]
return result
}
bind
无参数传递
//先写一个没有参数传递的版本
Function.prototype.bind2 = function (context) {
var _this = this
return function () {//bind返回的是一个函数
//this.call(context) 这里的this是调用这个返回函数的this,不一定是实例对象
_this.call(context)
}
}
测试一下
var obj = {
a: 100,
b: 200
}
function add() {
return this.a + this.b
}
var fn = add.bind2(obj)
console.log(fn())//但这里输出的的undifined 为什么呢?
//因为fn对应的是bind2里返回的函数
function () {
_this.call(context)
}
//这个函数是没有返回值的,所以返回undifined
再测试一下
var obj = {
a: 100,
b: 200
}
function add() {
console.log(this.a+this.b)
}
var fn = add.bind2(obj)
console.log(fn())//输出300 因为我们这是在函数里直接打印所以打印出300
有参数传递
Function.prototype.bind2 = function (context) {
var _this = this
var outerArgs = Array.prototype.slice.call(arguments, 1)
return function () {
var innerArgs = Array.prototype.slice.call(arguments)
_this.apply(context, outerArgs.concat(innerArgs))
}
}
测试一下
var obj = {
a: 100,
b: 200
}
function add(c, d) {
console.log(this.a + this.b + c + d)
}
var fn = add.bind2(obj, 1)//函数科里化
//第二次传参
fn(1)// 302
作为构造函数时
bind返回的函数如果作为构造函数,搭配new关键字出现的话,我们的绑定this就需要“被忽略”。
Function.prototype.bind2 = function (context) {
var _this = this
var fNOP = function(){}
var outerArgs = Array.prototype.slice.call(arguments, 1)
var fBound = function(){
var innerArgs = Array.prototype.slice.call(arguments)
//为什么这里可以判断 `this instanceof fBound` 是因为fBound返回的时候这个函数还没有执行到内部
_this.apply(this instanceof fBound ? this :context, outerArgs.concat(innerArgs))
}
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
Promise
class Promise1 {
// 我们调用的时候是传入((resolve,reject)=>{
// })
constructor(executor) {
this.status = "pending"
this.value = undefined
this.reason = undefined
//成功存放的数组
this.onResolvedCallbacks = []
// 失败存放的数组
this.onRejectedCallbacks = []
let resolve = value => {
if (this.status === 'pending') {
this.status = 'fulfilled';
this.value = value;
// 一旦resolve执行,调用成功数组的函数
this.onResolvedCallbacks.forEach(fn => fn());
}
};
let reject = reason => {
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
// 一旦resolve执行,调用成功数组的函数
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject)
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
if (this.status == 'fulfilled') {
onFulfilled(this.value)
} else if (this.status == 'rejected') {
onRejected(this.reason)
} else if (this.status == 'pending') {
this.onResolvedCallbacks.push(() => {
onFulfilled(this.value);
})
}
}
}
var p1 = new Promise1((resolve, reject) => {
setTimeout(()=>{
resolve(1)
},1000)
}).then(value => {
console.log(value)
}, reason => {
console.log(value)
})