前端强化(六月)

阅读: 评论:0

前端强化(六月)

前端强化(六月)

深入this

1.this

箭头函数的绑定无法被修改(new也不行)。

/*** 非严格模式*/var name = 'window'function Person (name) {this.name = name;this.show1 = function () {console.log(this.name)}this.show2 = () => console.log(this.name)this.show3 = function () {return function () {console.log(this.name)}}this.show4 = function () {return () => console.log(this.name)}
}var personA = new Person('personA')
var personB = new Person('personB')personA.show1()
personA.show1.call(personB)personA.show2()
personA.show2.call(personB)personA.show3()()
personA.show3().call(personB)
personA.show3.call(personB)()personA.show4()()
personA.show4().call(personB)
personA.show4.call(personB)()正确答案如下:personA.show1() // personA,隐式绑定,调用者是 personA
personA.show1.call(personB) // personB,显式绑定,调用者是 personBpersonA.show2() // personA,首先personA是new绑定,产生了新的构造函数作用域,// 然后是箭头函数绑定,this指向外层作用域,即personA函数作用域
personA.show2.call(personB) // personA,同上personA.show3()() // window,默认绑定,***调用者是window***
personA.show3().call(personB) // personB,显式绑定,调用者是personB
personA.show3.call(personB)() // window,默认绑定,***调用者是window***personA.show4()() // personA,箭头函数绑定,this指向外层作用域,即personA函数作用域
personA.show4().call(personB) // personA,箭头函数绑定,call并没有改变外层作用域,// this指向外层作用域,即personA函数作用域
personA.show4.call(personB)() // personB,解析同题目1,最后是箭头函数绑定,// this指向外层作用域,即改变后的person2函数作用域复制代码

2. call

foo.call(obj)(window) foo里面的this还是第一个

function foo() {console.log( this.a );
}var obj = {a: 2
};var bar = function() {foo.call( obj );
};bar(); // 2
setTimeout( bar, 100 ); // 2// 硬绑定的bar不可能再修改它的this
bar.call( window ); // 2
复制代码

3. 隐式绑定

function foo(el) {console.log( el, this.id );
}var obj = {id: "awesome"
}var myArray = [1, 2, 3]
// 调用foo(..)时把this绑定到obj
myArray.forEach( foo, obj );
// 1 awesome 2 awesome 3 awesome
复制代码

4. 手写一个new实现


function Person() {...}
// 使用内置函数new
var person = new Person(...)// 使用手写的new,即create
var person = create(Person, ...)function create() {// 创建一个空的对象var obj = new Object(),// 获得构造函数,arguments中去除第一个参数Con = [].shift.call(arguments);// 链接到原型,obj 可以访问到构造函数原型中的属性obj.__proto__ = Con.prototype;// 绑定 this 实现继承,obj 可以访问到构造函数中的属性var ret = Con.apply(obj, arguments);// 优先返回构造函数返回的对象return ret instanceof Object ? ret : obj;
};
复制代码

5. ES6 call 和 apply 的模拟实现

1 call 
Function.prototype.call = function (context) {context = context ? Object(context) : window; context.fn = this;let args = [...arguments].slice(1);let result = context.fn(...args);delete context.fnreturn result;
}
2 apply
Function.prototype.apply = function (context, arr) {context = context ? Object(context) : window; context.fn = this;let result;if (!arr) {result = context.fn();} else {result = context.fn(...arr);}delete context.fnreturn result;
}
复制代码

6. 进阶序列问题:用 JS 实现一个无限累加的函数 add

add(1); // 1 add(1)(2); // 3 add(1)(2)(3); // 6 add(1)(2)(3)(4); // 10 // 以此类推

function add(a) {function sum(b) { // 使用闭包a = a + b; // 累加return sum;}String = function() { // 重写toString()方法return a;}return sum; // 返回一个函数
}add(1); // 1
add(1)(2);  // 3
add(1)(2)(3); // 6
add(1)(2)(3)(4); // 10 
我们知道打印函数时会自动调用 toString()方法,函数 add(a) 返回一个闭包 sum(b),函数 sum() 中累加计算 a = a + b,只需要重写String()方法返回变量 a 就OK了。
复制代码

7. ES6 中如何获取URL地址中的参数

function query(url){var paramsArr=url.split('?')[1].split('&')//[c=3,d=4]let ret={};paramsArr.forEach((item)=>{let key=item.split('=')[0];let val=item.split('=')[1];ret[key]=val;})return ret
}var result = query('=3&d=4')console.log(result); //{ c: '3', d: '4' }
复制代码

8. js面试题 a为何值时 输出为1

var a; //?
if(a==1&&a==2&&a==3){console.log(1);
}
// 剖析 只要a是对象就行 对象每进行一次比较或者拼接都会执行toString()方法
var a={i:1,toString:function(){return this.i++}
}
if (a == 1 && a == 2 && a == 3) {console.log(1);
}var num=1;
var b = {toString: function () {return ++num}
}
console.log(b+'');//2 string
console.log(b+'');//3 string
console.log(b+1);//5 number
console.log(b==5);//true复制代码

9. bind 原生

// f.bind(obj1,2,3)(2)验证
Function.prototype.bindq=function(){let self = this;let con=[...arguments].shift();let args = [...arguments];return function(){return self.apply(con, at([...arguments]))}
}Function.prototype.bind = function () {let self = this,args = Array.from(arguments),context = args.shift();console.log(args,context);return function () {return self.apply(context, at(...arguments))}
}
// 实现bind() new 
复制代码

10. 手写promise

// 手写一个promise 面试够用function myPromise(constructor){let self=this;self.status='pending';self.value=ason=undefined;function resolve(value) {if (self.status === 'pending'){self.status = 'resolved';self.value = value;}};function reject(value) {if (self.status === 'pending'){self.status = 'rejected';ason = value;}};try{// 调用构造函数constructor(resolve, reject)}catch(e){reject(e);}
}
myPromise.prototype.then = function (onFullfilled, onRejected) {switch (this.status) {case 'resolved':onFullfilled(this.value)break;case 'rejected':ason)break;default:break;}
}var p=new myPromise(function(resolve,reject){resolve(9)});
p.then(function (x) {console.log(x);//9
})复制代码

10. 手写防抖(Debouncing)和节流(Throttling)

scroll 事件本身会触发页面的重新渲染,同时 scroll 事件的 handler 又会被高频度的触发, 因此事件的 handler 内部不应该有复杂操作,例如 DOM 操作就不应该放在事件处理中。 针对此类高频度触发事件问题(例如页面 scroll ,屏幕 resize,监听用户输入等),有两种常用的解决方法,防抖和节流。

防抖

当一次事件发生后,事件处理器要等一定阈值的时间,如果这段时间过去后 再也没有 事件发生,就处理最后一次发生的事件。假设还差 0.01 秒就到达指定时间,这时又来了一个事件,那么之前的等待作废,需要重新再等待指定时间。最后一次触发事件

// 防抖动函数
function debounce(fn,wait=50,immediate) {let timer;return function() {if(immediate) {fn.apply(this,arguments)}if(timer) clearTimeout(timer)timer = setTimeout(()=> {fn.apply(this,arguments)},wait)}
}<!--验证-->
// 简单的防抖动函数
// 实际想绑定在 scroll 事件上的 handler
function realFunc(){console.log("Success");
}// 采用了防抖动
window.addEventListener('scroll',debounce(realFunc,500));
// 没采用防抖动
window.addEventListener('scroll',realFunc);复制代码

节流

固定频率调用,间隔相同

//时间间隔
function throttle(fn,wait=50){// 节流let prev=new Date();return function(){let now=new Date();if(now-prev > wait){fn.apply(this,arguments);prev = new Date();}}
}
function throttle1(fn,wait=50){// 定时器let canRun=true;return function(){if (!canRun) return;canRun = false;setTimeout(() => {fn.apply(this, arguments);canRun = true;}, wait);}
}
// 简单的防节流函数
// 实际想绑定在 scroll 事件上的 handler
function realFunc() {console.log("Success");
}
// 采用了防节流
window.addEventListener('scroll', throttle(realFunc, 500));
// 没采用防节流
window.addEventListener('scroll', realFunc);复制代码

参考: 前端劝退师

转载于:

本文发布于:2024-01-31 02:51:48,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170664071124805.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23