万网做网站给网站源码,wordpress精简版下载,网站刷流量有用吗,东莞网络问政平台实现New
首先创建一个新的空对象设置原型#xff0c;将对象的原型设置为函数的prototype对象让函数的this指向这个对象#xff0c;执行构造函数的代码判断函数的返回值类型#xff0c;如果是值类型#xff0c;返回创建的对象。如果是引用类型#xff0c;就返回这个引用类…实现New
首先创建一个新的空对象设置原型将对象的原型设置为函数的prototype对象让函数的this指向这个对象执行构造函数的代码判断函数的返回值类型如果是值类型返回创建的对象。如果是引用类型就返回这个引用类型的对象
function myNew(constructor, ...args) {// 如果不是一个函数就报错if (typeof constructor ! function) {throw myNew function the first param must be a function;}// 基于原型链 创建一个新对象继承构造函数constructor的原型对象上的属性let newObj Object.create(constructor.prototype);// 将newObj作为this执行 constructor 传入参数let res constructor.apply(newObj, args);// 判断函数的执行结果是否是对象typeof null 也是object所以要排除nulllet isObject typeof res newObject res ! null;// 判断函数的执行结果是否是函数let isFunction typeof res function;// 如果函数的执行结果是一个对象或函数, 则返回执行的结果, 否则, 返回新创建的对象return isObject || isFunction ? res : newObj;
}// 用法
function Person(name, age) {this.name name;this.age age;// 如果构造函数内部return 一个引用类型的对象则整个构造函数失效而是返回这个引用类型的对象
}
Person.prototype.say function() {console.log(this.age);
};
let p1 myNew(Person, poety, 18);
console.log(p1.name); //poety
console.log(p1); //Person {name: poety, age: 18}
p1.say(); //18测试结果 call、apply、bind
实现call
思路接受传入的context上下文如果不传默认为window将被调用的方法设置为上下文的属性使用上下文对象来调用这个方法删除新增属性返回结果。
//写在函数的原型上
Function.prototype.myCall function (context) {// 如果要调用的方法不是一个函数则报错if (typeof this ! function) {throw new Error(Type error);}// 判断 context 是否传入,如果没有传就设置为 windowcontext context || window;// 获取参数[...arguments]把类数组转为数组let args [...arguments].slice(1);let result null;// 将被调用的方法设置为context的属性,this即为要调用的方法context.fn this;// 执行要被调用的方法result context.fn(...args);// 删除手动增加的属性方法delete context.fn;// 将执行结果返回return result;
};//测试
function f(a, b) {console.log(a b);console.log(this.name);
}
let obj {name: 1,
};
f.myCall(obj, 1, 2); // 31测试结果 实现apply
思路除了传参方式是数组其它与call没区别
Function.prototype.myApply function (context) {if (typeof this ! function) {throw new Error(Type error);}let result null;context context || window;// 与上面代码相比我们使用 Symbol 来保证属性唯一,也就是保证不会重写用户自己原来定义在 context 中的同名属性const fnSymbol Symbol();context[fnSymbol] this;// 执行要被调用的方法,处理参数和 call 有区别判断是否传了参数数组if (arguments[1]) {//传了参数数组result context[fnSymbol](...arguments[1]);} else {//没传参数数组result context[fnSymbol]();}delete context[fnSymbol];return result;
};//测试
function f(a, b) {console.log(a, b);console.log(this.name);
}
let obj {name: 张三,
};
f.myApply(obj, [1, 2]); //1 2,张三测试结果 实现bind
思路bind返回的是一个函数需要判断函数作为构造函数的情况当作为构造函数时this指向实例不会被任何方式改变this所以要忽略传入的context上下文。
bind可以分开传递参数所以需要将参数拼接。如果绑定的是构造函数还需要继承构造函数原型上的属性和方法保证不丢失。
Function.prototype.myBind function (context) {// 判断调用对象是否为函数if (typeof this ! function) {throw new Error(Type error);}// 获取参数const args [...arguments].slice(1);const fn this; // 保存this的值代表调用bind的函数//返回一个函数此函数可以被作为构造函数调用也可以作为普通函数调用const Fn function () {// 根据调用方式传入不同绑定值// 当作为构造函数时,this 指向实例不会被任何方式改变 this要忽略传入的context上下文return fn.apply(this instanceof Fn ? this : context,// bind可以分开传递参数(如f.bind(obj, 1)(2))所以需要将参数拼接这里使用apply参数拼接成一个数组args.concat(...arguments)//当前的这个 arguments 是指 Fn 的参数也可以用剩余参数的方式);};//对于构造函数要保证原函数的原型对象上的属性不能丢失Fn.prototype Object.create(fn.prototype);return Fn;
};// 1.先测试作为构造函数调用
function Person(name, age) {console.log(name);console.log(age);console.log(this); //构造函数this指向实例对象
}
// 构造函数原型的方法
Person.prototype.say function () {console.log(say);
};
var obj {name: cc,age: 18,
};
var bindFun Person.myBind(obj, cxx);
var a new bindFun(10);
// cxx
// 10
// Person {}
a.say(); // say// 2.再测试作为普通函数调用
function normalFun(name, age) {console.log(name);console.log(age);console.log(this); // 普通函数this指向绑定bind的第一个参数 也就是例子中的obj
}
var obj {name: aa,age: 18,
};
var bindNormalFun normalFun.myBind(obj, cc);
bindNormalFun(12);
// cc
// 12
// { name: aa, age: 18 }测试结果 防抖和节流
防抖
防抖是指在事件被触发n秒后在执行回调如果在这n秒内时间又被触发则重新计时。
可以使用在一些点击请求的事件上避免因为用户的多次点击向后端发送多次请求。
//fn是需要防抖的函数,delay是等待时间
function debounce(fn, delay 500) {let timer null;// 这里返回的函数是每次用户实际调用的防抖函数return function(...args) { //...args是es6的剩余参数语法将多余的参数放入数组用来代替arguments对象// 如果已经设定过定时器了就清空上一次的定时器if(timer) {clearTimeout(timer); }// 开始一个新的定时器延迟执行用户传入的方法注定时器的返回值是一个数值作为定时器的编号可以传入clearTimeout来取消定时器timer setTimeout(() { //这里必须是箭头函数不然this指向window,要让this就指向fn的调用者fn.apply(this, args); }, delay) }
}节流
节流就是一定时间内执行一次事件即使重复触发也只有一次生效。
可以使用在监听滚动scroll事件上通过事件节流来降低事件调用的频率。
定时器版本
throttle(fn, delay 500) {let timer null;return function(...args) {// 当前有任务了直接返回if(timer) {return;}timer setTimeout(() {fn.apply(this, args);//执行完后需重置定时器不然timer一直有值无法开启下一个定时器timer null; }, delay)}
}时间戳版本
// 节流
function throttle(fn, delay 500) {let prev Date.now();// 上一次执行该函数的时间return function(...args) {let now Date.now();//返回从UTC到当前时间的毫秒数// 如果差值大于等于设置的等待时间就执行函数if (now - prev delay) {fn.apply(this, args);prev Date.now();}};
}实现instanceof
instanceof用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。
myInstanceof(instance, constructor) {//如果不是对象或者是null直接返回falseif (typeof instance ! object || instance null) {return false;}// 获取对象的原型let proto Object.getPrototypeOf(instance);// 获取构造函数的 prototype 对象let prototype constructor.prototype;// 判断构造函数的 prototype对象是否在对象的原型链上while (true) {// 到达原型链终点null说明没找到if (!proto) {return false;}if (proto prototype) {return true;}// 如果没有找到就继续从其原型上找proto Object.getPrototypeOf(proto);}
}//测试
let Fn function () { }
let p1 new Fn()
console.log(myInstanceof(p1, Fn));//true
console.log(myInstanceof([], Fn));//false
console.log(myInstanceof([], Array)) // true
console.log(myInstanceof(function(){}, Function)) // true测试结果 实现Ajax
创建一个XMLHttpRequest对象 在这个对象上使用open方法创建一个HTTP请求参数为请求方法、请求地址、是否异步和用户的认证信息 通过send方法来向服务器发起请求post请求可以入参作为发送的数据体 监听请求成功后的状态变化根据状态码进行相应的出来。onreadystatechange设置监听函数当对象的readyState变为4的时候代表服务器返回的数据接收完成这个时候可以通过判断请求的状态如果状态是200则为成功404或500为失败。
function ajax(url) {//1.创建XMLHttpRequest对象const xhr new XMLHttpRequest();//2.使用open方法创建一个GET请求xhr.open(GET,url);//xhr.open(GET,url,true);//true代表异步已完成事务的通知可供事件监听器使用;如果为falsesend() 方法直到收到答复前不会返回//3.发送请求xhr.send(); //4.监听请求成功后的状态变化(readyState改变时触发)根据状态码(0~5)进行相应的处理xhr.onreadystatechange function () {//readyState为4代表服务器返回的数据接收完成if (xhr.readyState 4) { //请求的状态为200或304代表成功if(xhr.status 200 || xhr.status 304) {//this.response代表返回的数据handle(this.response);} else {//this.statusText代表返回的文本信息console.error(this.statusText);}}};
}使用Promise封装Ajax
function ajax(url) {return new Promise((resolve, reject) {let xhr new XMLHttpRequest()xhr.open(get, url)xhr.send() xhr.onreadystatechange () {if (xhr.readyState 4) {if (xhr.status 200 || xhr.status 304) {resolve(this.response)} else {reject(new Error(this.statusText));}}}})
}
//使用
let url /data.json
ajax(url).then(res console.log(res)).catch(reason console.log(reason))