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);
}
複製代碼