当前位置:   article > 正文

daily-question-02(前端每日一题02)

daily-questio前端

在这里记录着每天自己遇到的一道印象深刻的前端问题,以及一道生活中随处可见的小问题。

强迫自己形成积累的习惯,鞭挞自己不断前行,共同学习。

Github 地址

2019/04/15 - 2019/04/21

1. 写一个乱序函数 ?

遍历数组元素,然后将当前元素与以后随机位置的元素进行交换。

  1. function shuffle(a) {
  2. for (let i = a.length; i; i--) {
  3. let j = Math.floor(Math.random() * i);
  4. // es6语法
  5. [a[i - 1], a[j]] = [a[j], a[i - 1]];
  6. }
  7. return a;
  8. }
  9. 复制代码
2. 什么是惰性函数?

惰性函数就是返回一个重写函数。For example:

  1. var foo = function() {
  2. var t = new Date();
  3. foo = function() {
  4. return t;
  5. };
  6. return foo();
  7. };
  8. foo();
  9. 复制代码
3. 静态作用域与动态作用域 ?

静态作用域 —— 函数的作用域基于函数创建的位置。

动态作用域 —— 函数的作用域基于函数的使用位置。

  1. var value = 1;
  2. function foo() {
  3. console.log(value);
  4. }
  5. function bar() {
  6. var value = 2;
  7. foo();
  8. }
  9. bar(); // 输出 1 。JavaScript 采用的是词法作用域,也称为静态作用域。相同的,动态作用域此代码应该输出 2
  10. 复制代码
4. 手写一个 function call()函数 ?
  1. Function.prototype.call2 = function(context, ...args) {
  2. // 因为传进来的 context 有可能是 null
  3. context = context || window;
  4. // Function.prototype this 为当前运行的函数
  5. // 让 fn 的上下文为 context
  6. context.fn = this;
  7. const result = context.fn(...args);
  8. delete context.fn;
  9. return result;
  10. };
  11. 复制代码
5. Vue 组件中的 name 属性的作用 ?

组件在全局用 Vue.component() 注册时,全局 ID 自动作为组件的 name。

指定 name 选项的另一个好处是便于调试。有名字的组件有更友好的警告信息。另外,当在有 vue-devtools,未命名组件将显示成 <AnonymousComponent>,这很没有语义。通过提供 name 选项,可以获得更有语义信息的组件树。

6. Hash 路由和 History 路由的区别 ?
  1. hash 路由

hash 路由一个明显的标志是带有#,我们主要是通过监听 url 中的 hash 变化来进行路由跳转。(window.addEventListener('hashchange', this.refresh, false);)

hash 的优势就是兼容性更好,在老版 IE 中都有运行,问题在于 url 中一直存在#不够美观,而且 hash 路由更像是 Hack 而非标准,相信随着发展更加标准化的 History API 会逐步蚕食掉 hash 路由的市场。

  1. history 路由

history 路由使用 History API 来实现,具体有:

  1. window.history.back(); // 后退
  2. window.history.forward(); // 前进
  3. window.history.go(-3); // 后退三个页面
  4. 复制代码

history.pushState用于在浏览历史中添加历史记录, history.replaceState方法的参数与pushState方法一模一样,区别是它修改浏览历史中当前纪录,而非添加记录,同样不触发跳转。

7. Vue 的响应式原理中 Object.defineProperty 有什么缺陷?为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty
  1. Object.defineProperty 无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;

  2. Object.defineProperty 只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。Proxy 可以劫持整个对象,并返回一个新的对象。

  3. Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。

2019/04/08 - 2019/04/14

4. 写一个“终极类型”判断函数?
  1. function type(obj) {
  2. var toString = Object.prototype.toString;
  3. var toType = {};
  4. var typeArr = [
  5. "Undefined",
  6. "Null",
  7. "Boolean",
  8. "Number",
  9. "String",
  10. "Object",
  11. "Array",
  12. "Function",
  13. "Date",
  14. "RegExp",
  15. "Error",
  16. "Arguments"
  17. ];
  18. // 这里利用了object 对象toString() 后 值为 '[object Array]' 等情况进行判断
  19. typeArr.map(function(item, index) {
  20. toType["[object " + item + "]"] = item.toLowerCase();
  21. });
  22. return typeof obj !== "object" ? typeof obj : toType[toString.call(obj)];
  23. }
  24. 复制代码
2. 写一个函数,判断各种类型的不同变量是否相等,即“终极等于”函数?
  1. const equals = (a, b) => {
  2. if (a === b) return true;
  3. // 时间的判断
  4. if (a instanceof Date && b instanceof Date)
  5. return a.getTime() === b.getTime();
  6. // 非 object 类型的判断
  7. if (!a || !b || (typeof a !== "object" && typeof b !== "object"))
  8. return a === b;
  9. if (a.prototype !== b.prototype) return false;
  10. if (Array.isArray(a) && Array.isArray(b)) a.sort(), b.sort();
  11. let keys = Object.keys(a);
  12. if (keys.length !== Object.keys(b).length) return false;
  13. return keys.every(k => equals(a[k], b[k]));
  14. };
  15. 复制代码
3. mouseover 和 mouseenter 的区别 ?

mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是 mouseout

mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是 mouseleave

4. 一句话形容闭包?

闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用,子函数所在的父函数的作用域不会被释放。

一个闭包小栗子:

  1. function f1(){
  2. &emsp;&emsp;n = 999;
  3. &emsp;&emsp;function f2(){
  4. &emsp;&emsp;&emsp;&emsp;console.log(n);
  5. &emsp;&emsp;}
  6. &emsp;&emsp;return f2;
  7. }
  8. var result = f1();&emsp;&emsp;//返回的是f2函数
  9. result();&emsp;&emsp;//999,读取内部变量
  10. 复制代码
5. js 的 new 操作符做了哪些事情 ?

new 操作符新建了一个空对象,这个对象原型指向构造函数的 prototype,执行构造函数后返回这个对象。

6. 实现一个深拷贝 ?
  1. //所谓深度克隆,就是当对象的某个属性值为object或array的时候,要获得一份copy,而不是直接拿到引用值
  2. function deepClone1(origin, target) {
  3. //origin是被克隆对象,target是我们获得copy
  4. var target = target || {}; //定义target
  5. for (var key in origin) {
  6. //遍历原对象
  7. if (origin.hasOwnProperty(key)) {
  8. if (Array.isArray(origin[key])) {
  9. //如果是数组
  10. target[key] = [];
  11. deepClone1(origin[key], target[key]); //递归
  12. } else if (typeof origin[key] === "object" && origin[key] !== null) {
  13. target[key] = {};
  14. deepClone1(origin[key], target[key]); //递归
  15. } else {
  16. target[key] = origin[key];
  17. }
  18. }
  19. }
  20. return target;
  21. }
  22. // 第二个function
  23. function deepClone2(data) {
  24. if (!data || !(data instanceof Object) || typeof data === "function") {
  25. return data;
  26. }
  27. var constructor = data.constructor;
  28. var result = new constructor();
  29. for (var key in data) {
  30. if (data.hasOwnProperty(key)) {
  31. result[key] = deepClone2(data[key]);
  32. }
  33. }
  34. return result;
  35. }
  36. // 第三个fuction
  37. function deepClone3(origin, target) {
  38. var target = target || {},
  39. toStr = Object.prototype.toString;
  40. for (var prop in origin) {
  41. if (origin.hasOwnProperty(prop)) {
  42. //不能把原型链上的一起拷贝了
  43. //判断是元素类型还是引用类型
  44. if (typeof origin[prop] == "object" && typeof origin[prop] !== "null") {
  45. target[prop] = toStr.call(prop) == "[object Array]" ? [] : {};
  46. arguments.callee(origin[prop], target[prop]); //递归调用
  47. } else {
  48. target[prop] = origin[prop]; //原始类型直接复制
  49. }
  50. }
  51. }
  52. return target;
  53. }
  54. // 第四个function
  55. function deepClone4(obj) {
  56. //判断是否是简单数据类型,
  57. if (typeof obj == "object") {
  58. //复杂数据类型
  59. var result = obj.constructor == Array ? [] : {};
  60. for (let i in obj) {
  61. result[i] =
  62. typeof obj[i] == "object" && obj[i] !== null
  63. ? deepClone4(obj[i])
  64. : obj[i];
  65. }
  66. } else {
  67. //简单数据类型 直接 == 赋值
  68. var result = obj;
  69. }
  70. return result;
  71. }
  72. 复制代码

推荐使用 deepClone2()

7. 函数的防抖与节流 ?

防抖

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。(防误触)

  1. // 延缓执行
  2. function debounce(func, wait) {
  3. var timeout;
  4. return function() {
  5. var context = this;
  6. var args = arguments;
  7. console.log(args);
  8. console.log(func);
  9. if (timeout) clearTimeout(timeout);
  10. timeout = setTimeout(function() {
  11. func.apply(context, args);
  12. }, wait);
  13. };
  14. }
  15. // 立即执行
  16. function debounce(func, wait) {
  17. var timeout;
  18. return function() {
  19. var context = this;
  20. var args = arguments;
  21. if (timeout) clearTimeout(timeout);
  22. var callNow = !timeout;
  23. timeout = setTimeout(function() {
  24. timeout = null;
  25. }, wait);
  26. if (callNow) func.apply(context, args);
  27. };
  28. }
  29. 复制代码

节流

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。(限制流量)

  1. // 时间戳
  2. function throttle(func, wait) {
  3. var previous = 0;
  4. return function() {
  5. var now = Date.now();
  6. var context = this;
  7. var args = arguments;
  8. if (now - previous > wait) {
  9. func.apply(context, args);
  10. previous = now;
  11. }
  12. };
  13. }
  14. // 定时器
  15. function throttle(func, wait) {
  16. var timeout;
  17. return function() {
  18. var context = this;
  19. var args = arguments;
  20. if (!timeout) {
  21. timeout = setTimeout(function() {
  22. timeout = null;
  23. func.apply(context, args);
  24. }, wait);
  25. }
  26. };
  27. }
  28. 复制代码

转载于:https://juejin.im/post/5cbe8429f265da03a33c3737

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码优化者/article/detail/62475
推荐阅读
  

闽ICP备14008679号