摘要:静态作用域与动态作用域静态作用域函数的作用域基于函数创建的位置。采用的是词法作用域,也称为静态作用域。可以劫持整个对象,并返回一个新的对象。防误触延缓执行立即执行节流所谓节流,就是指连续触发事件但是在秒中只执行一次函数。
在这里记录着每天自己遇到的一道印象深刻的前端问题,以及一道生活中随处可见的小问题。
强迫自己形成积累的习惯,鞭挞自己不断前行,共同学习。
Github 地址
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 采用的是词法作用域,也称为静态作用域。相同的,动态作用域此代码应该输出 24. 手写一个 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,未命名组件将显示成
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. 函数的防抖与节流 ?防抖
所谓防抖,就是指触发事件后在 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); } }; }
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/103781.html
摘要:静态作用域与动态作用域静态作用域函数的作用域基于函数创建的位置。采用的是词法作用域,也称为静态作用域。可以劫持整个对象,并返回一个新的对象。防误触延缓执行立即执行节流所谓节流,就是指连续触发事件但是在秒中只执行一次函数。 在这里记录着每天自己遇到的一道印象深刻的前端问题,以及一道生活中随处可见的小问题。 强迫自己形成积累的习惯,鞭挞自己不断前行,共同学习。 Github 地址 2019...
摘要:问前端的缓存有哪些都适用什么场景区别是什么参考回答前端缓存分为两部分缓存浏览器缓存缓存强缓存强缓存主要是采用响应头中的和两个字段进行控制的值理解指定设置缓存最大的有效时间单位为指定响应会被缓存,并且在多用户间共享响应只作为私有的缓存, 20190116问: 前端的缓存有哪些?都适用什么场景?区别是什么? 参考回答 前端缓存分为两部分: http 缓存 浏览器缓存 http 缓存 强...
摘要:问前端的缓存有哪些都适用什么场景区别是什么参考回答前端缓存分为两部分缓存浏览器缓存缓存强缓存强缓存主要是采用响应头中的和两个字段进行控制的值理解指定设置缓存最大的有效时间单位为指定响应会被缓存,并且在多用户间共享响应只作为私有的缓存, 20190116问: 前端的缓存有哪些?都适用什么场景?区别是什么? 参考回答 前端缓存分为两部分: http 缓存 浏览器缓存 http 缓存 强...
20190124问: 如何理解es6中的Proxy? 试题解析:对proxy的理解,可能会延伸到vue的双向绑定 Proxy(代理) 定义 可以理解为为目标对象架设一层拦截,外界对该对象的访问,都必须通过这层拦截 简单示例: const obj = new Proxy({}, { get: (target, key, receiver) => { return JS ...
阅读 1237·2021-11-15 18:14
阅读 3064·2021-08-25 09:38
阅读 2644·2019-08-30 10:55
阅读 2624·2019-08-29 16:39
阅读 1278·2019-08-29 15:07
阅读 2418·2019-08-29 14:14
阅读 793·2019-08-29 12:36
阅读 897·2019-08-29 11:21