fn()
输出什么?,若是咱们使用 let
会发生什么,为何?function fn() {
console.log('a', a);
var a = 1; // let a = 1;
function a () {
console.log('I am a function');
}
}
fn()
// ƒ a () {console.log('I am a function');}
复制代码
keywords: 变量提高函数提高 && let const 和 var 的区别 && 箭头函数和普通函数的区别javascript
for(var i=0;i<10;i++){
setTimeout(function(){
console.log(i)//10个10
},1000)
}
// 输出的什么?Q&A 10 个 10
复制代码
若是想输出 0-9 能够怎么作?html
for(var i=0;i<10;i++){
((j)=>{
setTimeout(function(){
console.log(j)//10个10
},1000)
})(i)
}
复制代码
function filterMap(arr: any[],value:string){
return arr.filter(item => String(item).includes(value))
}
复制代码
原理是利用闭包,外部使用内部的值。 防抖就是限制必定的时间才触发的函数,好比搜索框input,用户输入的时候不能一输入就触发函数,等必定的时间(好比 1s)才触发相关的函数。前端
原理同上,利用闭包。 节流就是在规定时间内只执行一次,好比页面 scrolljava
// 设置一个 timer = null, 传入 time 为
// setTimeout的函数的时间,返回一个函数,当 timer 存在的时候clearTimeout
// 防抖
function debounce(fn,time){
let timer = null;
return function(){
if(timer){
clearTimeout(timer)
}
timer = setTimeout(()=>{
fn.apply(this,arguments)
},time)
}
}
// 设置一个 canRun = true,传入 fn 和 time
// 一个闭包的函数,先设置 canRun = false,直接执行setTimeout在其中把 canRun 置为 true,如今又能够执行了
function throttle(fn,time){
let canRun = true;
return function(){
if(!canRun){
return
}
canRun = false;
setTimeout(() => {
fn.apply(this,arguments);
canRun = true;
},time)
}
}
复制代码
typeof
类型检测,instanceof
原型检测,constructor
构造函数检测, Object.prototype.toString.call([])
)?//call 重写
Function.prototype.MyCall = function(context, ...args){
context = context || window; // 由于传递过来的context有多是null
context.fn = this; // 让fn的上下文为context
const result = context.fn(...args);
delete context.fn;
return result; // 由于有可能this函数会有返回值return
}
//apply 重写
Function.prototype.MyApply = function(context, arr: any[]){
context = context || window;
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
}
// bind 重写
Function.prototype.MyBind = function(context, ...args){
var fn = this;
return function () {
fn.call(context, ...args, ...arguments);
}
}
复制代码
context
对象一个新属性 fn
, 我称呼其为实际执行函数 context.fn
;让 this
关键字(仅仅是关键字,而不是this对象)指向这个属性 ,即 context.fn = this
; 注意 : 在这里的 this 对象指向的是调用call()函数的函数对象。args
而后执行 context.fn
,返回的结果保存在 result
中。context.fn
删除。返回执行 result
。先讲讲平时设计开发中经常使用的设计模式?react
function SetManager(name) {
this.manager = name;
}
SetManager.prototype.getName = function() {
console.log(this.manager);
};
var SingletonSetManager = (function() {
var manager = null;
return function(name) {
if (!manager) {
manager = new SetManager(name);
}
return manager;
}
})();
SingletonSetManager('a').getName(); // a
SingletonSetManager('b').getName(); // a
SingletonSetManager('c').getName(); // a
复制代码
// 观察者
var observer = {
// 订阅集合
subscribes: [],
// 订阅
subscribe: function(type, fn) {
if (!this.subscribes[type]) {
this.subscribes[type] = [];
}
// 收集订阅者的处理
typeof fn === 'function' && this.subscribes[type].push(fn);
},
// 发布 可能会携带一些信息发布出去
publish: function() {
var type = [].shift.call(arguments),
fns = this.subscribes[type];
// 不存在的订阅类型,以及订阅时未传入处理回调的
if (!fns || !fns.length) {
return;
}
// 挨个处理调用
for (var i = 0; i < fns.length; ++i) {
fns[i].apply(this, arguments);
}
},
// 删除订阅
remove: function(type, fn) {
// 删除所有
if (typeof type === 'undefined') {
this.subscribes = [];
return;
}
var fns = this.subscribes[type];
// 不存在的订阅类型,以及订阅时未传入处理回调的
if (!fns || !fns.length) {
return;
}
if (typeof fn === 'undefined') {
fns.length = 0;
return;
}
// 挨个处理删除
for (var i = 0; i < fns.length; ++i) {
if (fns[i] === fn) {
fns.splice(i, 1);
}
}
}
};
复制代码
使用 emit,on 来现实这个类面试
class Event {
constructor() {
this.eventTypeObj = {}
this.cacheObj = {}
}
on(eventType, fn) {
if (!this.eventTypeObj[eventType]) {
// 按照不一样的订阅事件类型,存储不一样的订阅回调
this.eventTypeObj[eventType] = []
}
this.eventTypeObj[eventType].push(fn)
// 若是是先发布,则在订阅者订阅后,则根据发布后缓存的事件类型和参数,执行订阅者的回调
if (this.cacheObj[eventType]) {
var cacheList = this.cacheObj[eventType]
for (var i = 0; i < cacheList.length; i++) {
cacheList[i]()
}
}
}
emit() {
// 能够理解为arguments借用shift方法
var eventType = Array.prototype.shift.call(arguments)
var args = arguments
var that = this
function cache() {
if (that.eventTypeObj[eventType]) {
var eventList = that.eventTypeObj[eventType]
for (var i = 0; i < eventList.length; i++) {
eventList[i].apply(eventList[i], args)
}
}
}
if (!this.cacheObj[eventType]) {
this.cacheObj[eventType] = []
}
// 若是先订阅,则直接订阅后发布
cache(args)
// 若是先发布后订阅,则把发布的事件类型与参数保存起来,等到有订阅后执行订阅
this.cacheObj[eventType].push(cache)
}
}
复制代码
// Hank
// ...(延迟5s)
// dinner
// ... (延迟2s)
// supper
复制代码
》 实现如上函数算法
function _LazyMan(name){
this.nama = name;
this.queue = [];
this.queue.push(() => {
console.log("Hi! This is " + name + "!");
this.next();
})
setTimeout(()=>{
this.next()
},0)
}
_LazyMan.prototype.eat = function(name){
this.queue.push(() =>{
console.log("Eat " + name + "~");
this.next()
})
return this;
}
_LazyMan.prototype.next = function(){
var fn = this.queue.shift();
fn && fn();
}
_LazyMan.prototype.sleep = function(time){
this.queue.push(() =>{
setTimeout(() => {
console.log("Wake up after " + time + "s!");
this.next()
},time * 1000)
})
return this;
}
_LazyMan.prototype.sleepFirst = function(time){
this.queue.unshift(() =>{
setTimeout(() => {
console.log("Wake up after " + time + "s!");
this.next()
},time * 1000)
})
return this;
}
function LazyMan(name){
return new _LazyMan(name)
}
复制代码
补充: 若是咱们使用 promise 怎么实现如上的 lazyMan?设计模式
var cache = { };
var count = 0;
function fib(n){
count++;
if(n === 1 || n === 2){
return 1;
}
if(cache[n]){
return cache[n];
}else{
var ret = fib(n - 1) + fib(n - 2);
cache[n] = ret;
return ret;
}
}
复制代码
function fibonacci(n) {
var one = 1;
var two = 1;
for(var i = 3; i <= n; i++) {
var three = one + two;
one = two;
two = three;
}
if (n==1||n==2) {
return one;
}
return three;
}
复制代码
二、棋盘问题(一个机器人位于一个 m x n 网格的左上角 (起始点在图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角.跨域
递归的思想数组
function robotPath(m,n) {
if(m == 1 && n == 1) return 1;
if(m == 1) return robotPath(m, n - 1);
if(n == 1) return robotPath(m - 1, n);
return robotPath(m-1, n) + robotPath(m, n - 1);
}
复制代码