1-函数防抖和节流
/*
* debounce:函数防抖
* @params
* func:自己最终要执行的任务
* wait:多久操作一次算是频繁触发「默认值:300ms」
* immediate:控制触发的边界 「默认值:false结束边界 true开始边界」
* @return
* proxy处理函数,处理函数会在频繁触发的时候,频繁执行;
* 函数内部,控制我们想要操作的func只执行一次;
*/
const debounce = function debounce(func, wait, immediate) {
if (typeof func !== "function") throw new TypeError('func must be an function!');
if (typeof wait === "boolean") immediate = wait;
if (typeof wait !== "number") wait = 300;
if (typeof immediate !== "boolean") immediate = false;
let timer = null;
return function proxy(...params) {
let now = !timer && immediate,
result;
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
// 清除最后一次定时器
clearTimeout(timer);
timer = null;
// 符合执行的是最后一次「触发在结束边界」
if (!immediate) result = func.call(this, ...params);
}, wait);
// 符合第一次立即执行「触发在开始的边界」
if (now) result = func.call(this, ...params);
return result;
};
}
const handle = function handle(ev) {
console.log(this, ev);
};
submit.onclick = debounce(handle, true);
/*
* throttle:函数节流
* @params
* func:自己最终要执行的任务
* wait:触发的频率「默认值:300ms」
* @return
* proxy处理函数
*/
const throttle = function throttle(func, wait) {
if (typeof func !== "function") throw new TypeError('func must be a function!');
wait = +wait;
if (isNaN(wait)) wait = 300;
let timer = null,
previous = 0;
return function proxy(...params) {
let now = +new Date,
remaining = wait - (now - previous),
result;
if (remaining <= 0) {
// 两次间隔时间已经超过WAIT了,此时我们立即执行
if (timer) {
clearTimeout(timer);
timer = null;
}
previous = now;
result = func.call(this, ...params);
return result;
}
// 没有定时器我们才设置,有定时器说明上次还没执行呢,只有上一次执行了,我们在开启下一次
if (!timer) {
timer = setTimeout(() => {
clearTimeout(timer);
timer = null;
previous = +new Date;
result = func.call(this, ...params);
}, remaining);
}
return result;
};
}
const handle = function handle(ev) {
console.log(this, ev);
// console.log('OK');
};
window.onscroll = throttle(handle);
2-hasPubProperty
需求:
封装检测某个属性是否为对象的公有属性方法
思路1:
既是其属性又不是私有的属性
检测属性=> in 「不论是私有还是公有」
检测私有属性 => hasOwnProperty
function hasPubProperty(obj, attr) {
return (attr in obj) && !obj.hasOwnProperty(attr);
}
// 弊端:不能检测既是私有的,也是公有的属性
思路2:
不管私有是否存在,只要公有中有,则当前属性就是对象的公有属性
Object.prototype.hasPubProperty = function hasPubProperty(attr) {
// 找到当前对象的原型,而且一直向上找,直到找到Object.prototype为止;
// 查找的时候,只要某个原型对象中有attr这个属性,这个属性就是对象的公有属性
let proto = Object.getPrototypeOf(this);
while (proto) {
if (proto.hasOwnProperty(attr)) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
};
let obj = {
name: 'obj',
toString() {}
};
console.log(obj.hasPubProperty('name')); //=>false
console.log(obj.hasPubProperty('toString')); //=>true
3-重写内置new
需求:
function Dog(name) {
this.name = name;
}
Dog.prototype.bark = function () {
console.log('wangwang');
}
Dog.prototype.sayName = function () {
console.log('my name is ' + this.name);
}
/*
let sanmao = new Dog('小黑');
sanmao.sayName();
sanmao.bark();
*/
function _new() {
//=>完成你的代码
}
let sanmao = _new(Dog, '小黑');
sanmao.bark(); //=>"wangwang"
sanmao.sayName(); //=>"my name is 小黑"
console.log(sanmao instanceof Dog); //=>true
思路:
了解new做了哪些事
- 让构造函数中的this指向这个实例对象
- this.xxx = xxx 都是给实例对象设置私有属性和方法
- 如果构造函数没有return或者返回的是原始值,则把创建的实例对象返回;若返回的是对象,则以自己返回的为主
const _new = function _new(Ctor, ...params) {
// 1.格式校验:函数 & 有原型对象 & 不是Symbol/BigInt
if (typeof Ctor !== "function") throw new TypeError(`${Ctor} is not a constructor!`);
let name = Ctor.name,
proto = Ctor.prototype,
obj,
result;
if (/^(Symbol|BigInt)$/i.test(name) || !proto) {
throw new TypeError(`${name} is not a constructor!`);
}
// 2.创建当前类的一个实例对象
obj = Object.create(proto);
// 3.把构造函数像普通函数一样执行,但是this需要指向创建的实例对象
result = Ctor.call(obj, ...params);
// 4.看函数的返回值,如果没有写返回值,或者返回的是原始值,我们默认返回实例对象;
// 如果返回的是对象,则以自己返回的为主;
if (result !== null && /^(object|function)$/i.test(typeof result)) return result;
return obj;
};
let sanmao = _new(Dog, '小黑');
sanmao.bark(); //=>"wangwang"
sanmao.sayName(); //=>"my name is 小黑"
console.log(sanmao instanceof Dog); //=>true
4-queryURLParams
需求:
获取URL地址中的问号参数信息(哈希信息)
思路1:
创建a便签,把url字符串赋值给href,通过解构出hash和search,再对字符串处理
/*
* @params
* attr:需要获取这个属性的信息(不传递获取的是所有的信息)
* @return
* 具体某个属性信息值
* 包含所有信息的对象
*/
String.prototype.queryURLParams = function queryURLParams(attr) {
attr = attr + '';
let obj = {},
link = document.createElement('a');
link.href = this;
let {
hash,
search
} = link;
if (hash) obj['_HASH'] = hash.substring(1);
if (search) {
search.substring(1).split('&').forEach(item => {
let [key, value] = item.split('=');
obj[key] = value;
});
}
if (attr !== "undefined") return obj[attr];
return obj;
};
let url = "http://www.zhufengpeixun.cn/?name=leon&age=18#amazing";
console.log(url.queryURLParams("name")); //=> "leon"
console.log(url.queryURLParams("_HASH")); //=> "amazing"
console.log(url.queryURLParams()); //=> {_HASH: "amazing", name: "leon", age: "18"}
思路2:
正则
/*
* @params
* attr:需要获取这个属性的信息(不传递获取的是所有的信息)
* @return
* 具体某个属性信息值
* 包含所有信息的对象
*/
String.prototype.queryURLParams = function queryURLParams(attr) {
attr = attr + '';
let obj = {};
this.replace(/#([^?=&#]+)/g, (_, $1) => obj['_HASH'] = $1);
this.replace(/([^?=&#]+)=([^?=&#]+)/g, (_, $1, $2) => obj[$1] = $2);
if (attr !== "undefined") return obj[attr];
return obj;
};
let url = "http://www.zhufengpeixun.cn/?name=leon&age=18#amazing";
console.log(url.queryURLParams("name")); //=> "leon"
console.log(url.queryURLParams("_HASH")); //=> "amazing"
console.log(url.queryURLParams()); //=> {_HASH: "amazing", name: "leon", age: "18"}
5-手撕call
Function.prototype.call = function call(context, ...params) {
// this->fn context->obj params->[10,20]
if (context == null) context = window;
if (!/^(object|function)$/i.test(typeof context)) context = Object(context);
let key = Symbol(),
result;
context[key] = this;
result = context[key](...params);
delete context[key];
return result;
};
const fn = function fn(x, y, ev) {
console.log(this, x, y, ev);
return x + y;
};
let result = fn.call('AA', 10, 20);
console.log(result); // {"AA", Symbol(): ƒ} 10 20 undefined
6-手撕apply
思路:
闭包的保存作用 “柯理化函数” => 预处理思想
Function.prototype.bind = function bind(context, ...params) {
return (...args) => {
return this.call(context, ...params.concat(args));
};
};