1. 手写call、apply和bind
2. 手写防抖和节流
3. 手写函数柯里化
4. 手写rgb转16进制
5. 手写驼峰转换
1. 手写call 、apply和 bind
转载自博文
call
Function.prototype.myCall = function( context ){
// 1. 判断有没有传入要绑定的对象,没有默认为window;如果是基本类型的话通过Object()方法进行转换
var context = Object(context) || window;
// 2. 给context添加一个fn属性,值为this,也就是fn()
context.fn = this;
// 3. 保存返回值
let result = '';
// 4. 取出传递的参数,第一个参数是this
// 截取除第一个参数外剩余参数的方法
const args = [...arguments].slice(1);
// const args = Array.prototype.slice.call(arguments , 1);
// const args = Array.from(arguments).slice(1);
// 5. 执行方法,传入参数
// ... 是es6的展开数组
result = context.fn(...args);
// 6. 删除该属性
delete context.fn;
// 7. 返回结果
return result;
}
// 测试
const obj = {
value :'hello'
}
function fn(name , age){
return {
value : this.value ,
name ,
age
}
}
let res = fn.myCall(obj , 'LL' , 25);
console.log(res) // { value: 'hello', name: 'LL', age: 25 }
apply
Function.prototype.myApply = function( context , args ){
var context = Object(context) || window;
context.fn = this;
let result = '';
// 4. 判断有没有传入第二个参数 args,如果传入就将第二个参数展开
if(!args){
// 没有传入,直接返回该函数
result = context.fn();
}else{
// 传入了,将参数展开
result = context.fn(...args);
}
delete context.fn;
return result;
}
// 测试用例
const obj = {
value :'hello'
}
function fn(name , age){
return {
value :this.value ,
name ,
age
}
}
let res = fn.myApply(obj ,[ 'LL' , 25]);
console.log(res) // { value: 'hello', name: 'LL', age: 25 }
bind
Function.prototype.myBind = function( context ){
// 1. 判断this是不是一个函数
if(typeof this !== 'function'){
// 不是函数,抛出错误
throw new Error('不是一个函数');
}
// 2. 暂存this
const self = this;
// 3. 获取传入的参数
// 拿到第一组参数,如果没传,是一个空数组
const args1 = [...arguments].slice(1);
// 第二次调用bindFn
const bindFn = function(){
// 获取第二个参数
const args2 = [...arguments];
// 将第一部分参数和第二部分参数合并到一起,进行返回
return self.apply(context , args1.concat(args2));
}
return bindFn
}
// 测试用例
const obj = {
value :'hello'
}
function fn(name , age){
return {
value :this.value ,
name ,
age
}
}
let res = fn.myBind(obj)('HH' , 30);
console.log(res)
2. 手写防抖和节流
转载自 博文
function submit() {
console.log("submit");
}
防抖
const debounce = (fn, delay) => {
let timerId = null;
return (...args) => {
if (timerId) {
window.clearTimeout(timerId);
}
timerId = setTimeout(() => {
fn.apply(this, args);
timerId = null;
}, delay);
};
};
const btnDebounce = debounce(submit, 1000);
节流
const throttle = (fn, delay) => {
let canUse = true;
return (...args) => {
if (canUse) {
fn.apply(this, args);
canUse = false;
setTimeout(() => (canUse = true), delay);
}
};
};
// 间隔设为3秒,效果比较明显
const btnThrottle = throttle(submit, 3000);
3. 手写函数柯里化
函数柯里化定义:柯里化是指这样一个函数(假设叫做createCurry),他接收函数A作为参数,运行后能够返回一个新的函数。并且这个新的函数能够处理函数A的剩余参数。
eg:
function add(a,b,c){
return a+b+c
}
function curryAdd(a) {
return function(b){
return function(c){
return a+b+c
}
}
}
add(1,2,3)
curryAdd(1)(2)(3)
封装 摘自 博文
function progressCurrying(fn, args) {
var _this = this
var len = fn.length;
var args = args || [];
return function() {
var _args = Array.prototype.slice.call(arguments);
Array.prototype.push.apply(args, _args);
// 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
if (_args.length < len) {
return progressCurrying.call(_this, fn, _args);
}
// 参数收集完毕,则执行fn
return fn.apply(this, _args);
}
}
4. 手写rgb转16进制
function rgb2hex(sRGB) {
var regexp=/rgb\((\d+),\s*(\d+),\s*(\d+)\)/;
var ret=sRGB.match(regexp);
if(!ret){
return sRGB;
}else{
var str='#';
for(var i=1;i<=3;i++){
var m=parseInt(ret[i]);
if(m<=255&&m>=0){
str+=(m<16?'0'+m.toString(16):m.toString(16));
}else{
return sRGB;
}
}
return str;
}
}
5. 手写驼峰转换
function cssStyle2DomStyle(sName) {
var arr = sName.split('')
if(arr.indexOf('-')==0) {
arr.splice(0,1)
}
for(var i =0; i<arr.length;i++) {
if(arr[i]=='-') {
arr.splice(i,1)
arr[i]= arr[i].toUpperCase()
}
}
return arr.join('')
}