内容简介:在这里记录着每天自己遇到的一道印象深刻的前端问题,以及一道生活中随处可见的小问题。强迫自己形成积累的习惯,鞭挞自己不断前行,共同学习。
在这里记录着每天自己遇到的一道印象深刻的前端问题,以及一道生活中随处可见的小问题。
强迫自己形成积累的习惯,鞭挞自己不断前行,共同学习。
2019/04/15 - 2019/04/21
1. 写一个乱序函数 ?
遍历数组元素,然后将当前元素与以后随机位置的元素进行交换。
function shuffle(a) { for (let i = a.length; i; i--) { let j = Math.floor(Math.random() * i); // es6语法 [a[i - 1], a[j]] = [a[j], a[i - 1]]; } return a; }
2. 什么是惰性函数?
惰性函数就是返回一个重写函数。For example:
var foo = function() { var t = new Date(); foo = function() { return t; }; return foo(); }; foo();
3. 静态作用域与动态作用域 ?
静态作用域 —— 函数的作用域基于函数创建的位置。
动态作用域 —— 函数的作用域基于函数的使用位置。
var value = 1; function foo() { console.log(value); } function bar() { var value = 2; foo(); } bar(); // 输出 1 。JavaScript 采用的是词法作用域,也称为静态作用域。相同的,动态作用域此代码应该输出 2
4. 手写一个 function call()函数 ?
Function.prototype.call2 = function(context, ...args) { // 因为传进来的 context 有可能是 null context = context || window; // Function.prototype this 为当前运行的函数 // 让 fn 的上下文为 context context.fn = this; const result = context.fn(...args); delete context.fn; return result; };
5. Vue 组件中的 name 属性的作用 ?
组件在全局用 Vue.component()
注册时,全局 ID 自动作为组件的 name。
指定 name 选项的另一个好处是便于调试。有名字的组件有更友好的警告信息。另外,当在有 vue-devtools,未命名组件将显示成 <AnonymousComponent>
,这很没有语义。通过提供 name 选项,可以获得更有语义信息的组件树。
6. Hash 路由和 History 路由的区别 ?
- hash 路由
hash 路由一个明显的标志是带有#,我们主要是通过监听 url 中的 hash 变化来进行路由跳转。( window.addEventListener('hashchange', this.refresh, false);
)
hash 的优势就是兼容性更好,在老版 IE 中都有运行,问题在于 url 中一直存在#不够美观,而且 hash 路由更像是 Hack 而非标准,相信随着发展更加标准化的 History API 会逐步蚕食掉 hash 路由的市场。
- history 路由
history 路由使用 History API 来实现,具体有:
window.history.back(); // 后退 window.history.forward(); // 前进 window.history.go(-3); // 后退三个页面
history.pushState
用于在浏览历史中添加历史记录, history.replaceState
方法的参数与 pushState
方法一模一样,区别是它修改浏览历史中当前纪录,而非添加记录,同样不触发跳转。
7. Vue 的响应式原理中 Object.defineProperty
有什么缺陷?为什么在 Vue3.0 采用了 Proxy
,抛弃了 Object.defineProperty
?
- Object.defineProperty 无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;
- Object.defineProperty 只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy 可以劫持整个对象,并返回一个新的对象。
- Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。
2019/04/08 - 2019/04/14
4. 写一个“终极类型”判断函数?
function type(obj) { var toString = Object.prototype.toString; var toType = {}; var typeArr = [ "Undefined", "Null", "Boolean", "Number", "String", "Object", "Array", "Function", "Date", "RegExp", "Error", "Arguments" ]; // 这里利用了object 对象toString() 后 值为 '[object Array]' 等情况进行判断 typeArr.map(function(item, index) { toType["[object " + item + "]"] = item.toLowerCase(); }); return typeof obj !== "object" ? typeof obj : toType[toString.call(obj)]; }
2. 写一个函数,判断各种类型的不同变量是否相等,即“终极等于”函数?
const equals = (a, b) => { if (a === b) return true; // 时间的判断 if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime(); // 非 object 类型的判断 if (!a || !b || (typeof a !== "object" && typeof b !== "object")) return a === b; if (a.prototype !== b.prototype) return false; if (Array.isArray(a) && Array.isArray(b)) a.sort(), b.sort(); let keys = Object.keys(a); if (keys.length !== Object.keys(b).length) return false; return keys.every(k => equals(a[k], b[k])); };
3. mouseover 和 mouseenter 的区别 ?
mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是 mouseout
mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是 mouseleave
4. 一句话形容闭包?
闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用,子函数所在的父函数的作用域不会被释放。
一个闭包小栗子:
function f1(){ n = 999; function f2(){ console.log(n); } return f2; } var result = f1(); //返回的是f2函数 result(); //999,读取内部变量
5. js 的 new 操作符做了哪些事情 ?
new 操作符新建了一个空对象,这个对象原型指向构造函数的 prototype,执行构造函数后返回这个对象。
6. 实现一个深拷贝 ?
//所谓深度克隆,就是当对象的某个属性值为object或array的时候,要获得一份copy,而不是直接拿到引用值 function deepClone1(origin, target) { //origin是被克隆对象,target是我们获得copy var target = target || {}; //定义target for (var key in origin) { //遍历原对象 if (origin.hasOwnProperty(key)) { if (Array.isArray(origin[key])) { //如果是数组 target[key] = []; deepClone1(origin[key], target[key]); //递归 } else if (typeof origin[key] === "object" && origin[key] !== null) { target[key] = {}; deepClone1(origin[key], target[key]); //递归 } else { target[key] = origin[key]; } } } return target; } // 第二个function function deepClone2(data) { if (!data || !(data instanceof Object) || typeof data === "function") { return data; } var constructor = data.constructor; var result = new constructor(); for (var key in data) { if (data.hasOwnProperty(key)) { result[key] = deepClone2(data[key]); } } return result; } // 第三个fuction function deepClone3(origin, target) { var target = target || {}, toStr = Object.prototype.toString; for (var prop in origin) { if (origin.hasOwnProperty(prop)) { //不能把原型链上的一起拷贝了 //判断是元素类型还是引用类型 if (typeof origin[prop] == "object" && typeof origin[prop] !== "null") { target[prop] = toStr.call(prop) == "[object Array]" ? [] : {}; arguments.callee(origin[prop], target[prop]); //递归调用 } else { target[prop] = origin[prop]; //原始类型直接复制 } } } return target; } // 第四个function function deepClone4(obj) { //判断是否是简单数据类型, if (typeof obj == "object") { //复杂数据类型 var result = obj.constructor == Array ? [] : {}; for (let i in obj) { result[i] = typeof obj[i] == "object" && obj[i] !== null ? deepClone4(obj[i]) : obj[i]; } } else { //简单数据类型 直接 == 赋值 var result = obj; } return result; }
推荐使用 deepClone2()
7. 函数的防抖与节流 ?
<details>
<summary>点击</summary>
防抖
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。(防误触)
// 延缓执行 function debounce(func, wait) { var timeout; return function() { var context = this; var args = arguments; console.log(args); console.log(func); if (timeout) clearTimeout(timeout); timeout = setTimeout(function() { func.apply(context, args); }, wait); }; } // 立即执行 function debounce(func, wait) { var timeout; return function() { var context = this; var args = arguments; if (timeout) clearTimeout(timeout); var callNow = !timeout; timeout = setTimeout(function() { timeout = null; }, wait); if (callNow) func.apply(context, args); }; }
节流
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。(限制流量)
// 时间戳 function throttle(func, wait) { var previous = 0; return function() { var now = Date.now(); var context = this; var args = arguments; if (now - previous > wait) { func.apply(context, args); previous = now; } }; } // 定时器 function throttle(func, wait) { var timeout; return function() { var context = this; var args = arguments; if (!timeout) { timeout = setTimeout(function() { timeout = null; func.apply(context, args); }, wait); } }; }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 前端科普系列(三):CommonJS 不是前端却革命了前端
- 前端科普系列(三):CommonJS 不是前端却革命了前端
- 前端技术演进(三):前端安全
- 【前端优化】前端常见性能优化
- 【前端学习笔记】前端安全详解
- 前端监控和前端埋点
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JSON 在线解析
在线 JSON 格式化工具
HTML 编码/解码
HTML 编码/解码