alert 输出的是字符串
一、手写call&bind
~function anonymous(proto){
function bind(context = window, ...args){
return (...amArgs) => {
this.apply(context, args.conact(amArgs));
}
}
function call (context, ...args){
context === null ? context = window : null;
let type = typeof context;
if(type !== 'object' && type !== 'function' && type !== 'symbol' ){
switch(type){
case "number":
context = new Number(context);
break;
case 'string':
context = new String(context);
break;
case 'boolean':
context = new Boolean(context);
break;
}
}
context.$fn = this;
let result = context.$fn(...args)
delete context.$fn;
return result;
}
proto.call = call
proto.bind = bind
}(Function.prototype)
二、节流防抖
节流: 多少秒再执行,如果没到执行时间内继续点击,则重新计算执行时间 应用: input输出
function debounce(fn, delay){
let timer = null;
return function (){
if(timer){
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.call(this, ...arguments)
timer = null;
}, delay)
}
}
// 示例:
handleChange = (e) => {
this.value = e.target.value;
}
Input.onChange = debounce(handleChange, 500);
Input.onChange = function(){
if(timer){
clearTimeout(timer);
}
timer = setTimeout(() => {
handleChange.call(this, ...arguments)
}, 500)
}
防抖: 设置两秒间隔点击一次,无论你点击多少次,都是两秒之后执行 应用: resize,scroll
1、时间戳
function throttle(fn, interval){ // 此时立即执行
let last = new Date().getTime();
return function(){
let now = new Date().getTime();
if(now - last > interval){
last = now;
fn.apply(this, [...arguments])
}
}
}
2、定时器
function throttle(fn, interval){
let timer = null
return function(){
if(!timer ){
timer = setTimeout(() => {
fn.apply(this, [arguments])
clearTimeout(timer)
}, interval)
}
}
}
3、时间戳和定时器结合方式
function throttle(fn, delay){ // 节流 10
let timer = null;
let startTime = new Date().getTime(); 30
return function (){
let curTime = new Date().getTime();
let remaining = delay - (curTime - startTime);
let context = this;
let args = arguments;
clearTimeout(timer);
if(remaining <= 0){
fn.apply(context, args);
startTime = curTime;
} else {
timer = setTimeout(fn, remaining);
}
}
}
三、实现一个new
function self_new(Func, ...args){
// 默认创建一个实例对象(而且是属于当前这个类的一个实例)
let obj = {};
obj.__proto__ == Func.prototype; // IE 大部分浏览中不允许我们直接操作__proto__;
// let obj = Object.create(Dog.prototype); 等价于上面两行
let result = Func.call(obj, ...args);
if((typeof result === 'object' && result !== null) || ( typeof result === 'function') ){
return result
}
return obj;
// 也会把类当做普通函数执行
// 执行的时候要保证this指向创建的实例
}
四、继承的四种方式
1、原型继承
function A () {
this.x = 100;
}
A.prototype.getX = function getX () {
console.log(this.x)
}
function B (){
this.y = 200;
}
// 原型继承
B.prototype = new A()
B.prototype.getY = function getY(){
console.log(this.y);
}
let b = new B;
// 特点: 并不会把父类的方法克隆给子类,而是建立了子类和父类的原型链查找机制
// 重定向子类的原型后,默认会丢失原有的constructor属性,
// 任何一个子类可以修改父类上的属性方法,
// 父类的私有属性方法变成子类的公有属性
2、call继承
function A (){
this.x = 100;
}
A.prototype.getX = function getX(){
console.log(this.x)
}
// 把父类当做普通函数执行,让其执行的时候,方法中的this变为子类的实例即可
function B(){
A.call(B);
this.y = 200;
}
B.prototype.getY = function getY(){
console.log(this.y)
}
let b = new B;
// 只能继承父类的私有属性,继承的私有属性赋值给子类实例的私有属性
// 父类的原型方法无法被继承
3、寄生组合继承(perfect)
// call继承实现私有属性继承
// 原型继承实现公有属性继承
function A (){
this.x = 100;
}
A.prototype.getX = function getX(){
console.log(this.x)
}
// 把父类当做普通函数执行,让其执行的时候,方法中的this变为子类的实例即可
function B(){
A.call(B);
this.y = 200;
}
// Object.create :创建一个空对象,让其__proto__ 指向A.prototype
B.prototype = Object.create(A.prototype);
B.prototype.constructor =
B.prototype.getY = function getY(){
console.log(this.y)
}
let b = new B;
4、class继承
class A {
constructor(){
this.x = 100;
}
// 设置A.prototype上的方法
num = 1000;
// 把A当做普通对象设置的属性和方法
static n = 2000;
static getH () {
console.log('123123')
}
getX(){
console.log(this.x)
}
}
class B extends A{
constructor(){
super();
this.y = 300;
}
getY(){
console.log(this.y);
}
}
五、深拷贝
JOSN.parse(JSON.stringify(obj))
缺陷: 转义之后,正则 => {} 函数 => null
function deepClone(obj){
if(obj === null) return null;
// 如果是基本数据值或者函数,也可以直接返回即可(函数无需要克隆)
if(typeof obj !== 'object') return obj;
// 如果是正则
if(Object.toString.call(obj) === '[Object RegExp]') return new RegExp(obj);
// 如果是日期格式
if(Object.toString.call(obj) === '[Object Date]') return new Date(obj);
// obj.constructor:找到所属类原型上的constructor,而原型上的constructor指向的事当前类的本身 ==> 保证传递进来什么类型的值,我们最后创建的newObj也是对应类型
let newObj = new obj.constructor;
for(let key in obj){
if(!obj.hasOwnProperty(key)) break;
newObj[key] = deepClone(obj[key])
}
return newObj;
}
六、实现promise
class MyPromise{
constructor(executor){
// 每一个promise实例都有一个状态和结果属性
this.PromiseStatus = 'pending';
this.PromiseValue = undefined;
this.resoveFnArr = [];
this.rejectFnArr = []
// 定义resolve/reject方法用来改变promise实例的状态和结果
let change = (status, value) => {
if(this.PromiseStatus !== 'pending') return;
this.PromiseValue = value;
this.PromiseStatus = status;
let fnArr = status === 'resolved'? this.resoveFnArr: this.rejectFnArr;
fnArr.forEach(item => {
if(typeof item !== 'function'){
return
}
item(this.PromiseValue);
})
}
let resolve = result => {
if(this.resoveFnArr.length){
change('resolved', result)
return
}
let delayTimer = setTimeout(() => {
change('resolved', result)
clearTimeout(delayTimer)
}, 0)
}
let reject = resason => {
if(this.resoveFnArr.length){
change('rejected', resason)
return
}
let delayTimer = setTimeout(() => {
change('resolved', result)
clearTimeout(delayTimer)
}, 0)
}
// 每一次new Promise 都会执行executor函数
try{
executor(resolve, reject);
} catch(err){
reject(err);
}
}
then(resolveFn, rejectFn){
// 每一次执行then都会返回一个新的promise实例
// this.resoveFnArr.push(resolveFn);
// this.rejectFnArr.push(rejectFn);
// 如果传递的参数不是函数(null/或者不传递),我们让成功或者失败传递顺延
if(typeof resoveFn !== 'function'){
resolveFn = (result) => {
return result;
}
}
if(typeof rejectFn !== 'function'){
rejectFn = (reason) => {
return MyPromise.reject(reason);
}
}
return new MyPromise((resolve, reject) => {
// 执行resolve/reject决定新的实例是成功还是失败的
// 只要执行新实例的executor函数中的resolve/reject就知道新的实例是成功的还是失败的
this.resoveFnArr.push((result) => {
try{
//不报错,则接受方法的返回结果,会根据结果判断成功还是失败
let x = resolveFn(result);
console.log('设置then执行的数据', x , x instanceof MyPromise)
if(x instanceof MyPromise){
x.then(resolve, reject);
return
}
resolve(x);
} catch(err){
// 执行报错代表新实例是失败的
reject(err)
}
});
this.rejectFnArr.push((reason) => {
try{
// 不报错,则接受方法的返回结果,会根据结果判断成功还是失败
let x = rejectFn(reason);
if(x instanceof MyPromise){
x.then(resolve, reject);
return
}
resolve(x);
}catch(err){
// 执行报错代表新实例是失败的
reject(err)
}
});
})
}
// MyPromise.prototype.catch(fn) === MyPromise.prototye.then(null, fn)
catch(rejectFn){
return this.then(null, rejectFn);
}
// 静态方法
static resolve(result){
return new MyPromise((resolve, reject) => {
resolve(result);
})
}
static reject(reason){
return new MyPromise((resolve, reject)=> {
reject(reason);
})
}
static all(arr){
return new MyPromise((resolve,reject) => {
let index = 0;
let results = [];
for(let i = 0; i < arr.length; i++){
let item = arr[i];
if(!(item instanceof MyPromise)) continue;
item.then( result => {
index++;
results[i] = result;
if(index === arr.length){
resolve(results);
}
}).catch(reason => {
reject(reason)
})
}
})
}
}