前端知识点备忘录

183 阅读6分钟

1、 clientX: clientX 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(或客户区)的水平坐标。客户区指的是当前窗口。但是不包含窗口滑动条的滑动距离,包含margin的宽度。

2、call,apply, bind的区别

    1. call()、apply()、bind() 都是用来重定义 this 的指向,指向()中的对象
    1. bind 返回的是一个新的函数,你必须调用它才会被执行,call, apply则立即执行
    1. 传参的格式不一样,call(db, 参数1, 参数2...), apply(db, [参数1,参数2...]), bind(db, 参数1, 参数2...),call和bind若传数组作为参数,则整个数组会被认为是一个参数,apply传列表参数则报错
    1. 详细解析
    var obj={
      name: 'xiaozhan', 
      age: 17,
      myFun: function(f, t) {
        console.log(this.name + '年龄'+this.age,'来自' + f + '去往' + t)
      }
    }
    obj.myFun.call({name: 'xiaoli', age:18}, ['上海', '北京']) // xiaoli年龄18 来自上海,北京去往undefined
    obj.myFun.bind({name: 'xiaoli', age:18}, ['上海', '北京'])() // xiaoli年龄18 来自上海,北京去往undefined
    // obj.myFun.apply({name: 'xiaoli', age:18}, '上海', '北京') // 报错

3、箭头函数

  • 箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。代码示例
  • 因为箭头函数没有 this,所以也不能用 call()、apply()、bind() 这些方法改变 this 的指向
   var value = 1;
   var result = (() => this.value).bind({value: 2})();
   console.log(result); // 1
var adder = {
 base : 1,
   
 add : function(a) {
   var f = v => v + this.base; // this.base === 1
   return f(a);
 },

 addThruCall: function(a) {
   var f = v => v + this.base;  
   // this.base === 1 
   // 因为箭头函数没有this,call,apply不能改箭头函数this的指向,所以this还是原来的对象adder
   // 所以这里this.base === 1
   var b = {
     base : 2
   };
           
   return f.call(b, a);
 },

 addThruCall2: function(a) {
   function f(v){
   	return v += this.base; // 普通函数谁调用函数 this就指向谁 call 将this指向了b
   }
   var b = {
     base : 2
   };
           
   return f.call(b, a);
 }

};

console.log(adder.add(1));         // 输出 2
console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3)
console.log(adder.addThruCall2(1)); // 输出 3
  • 没有 arguments, 但是可以访问外围函数的arguments

    function constant() {
    return () => arguments[0]
    }
    var result = constant(1);
    console.log(result()); // 1
    

    那如果我们就是要访问箭头函数的参数呢? 你可以通过命名参数或者 rest 参数的形式访问参数:

    let nums = (...nums) => nums;

  • 不能通过 new 关键字调用

  • 没有原型

4、vue中watch和change事件有什么相同和不同

  • change可以传入参数,watch只能监听到特定属性变化
  • watch可以获取nv,ov;change只能获取nv

5、vue中watch和computed有什么区别

  • computed 计算属性 : 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。
  • watch 侦听器 : 更多的是「观察」的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。

6、 从浏览器输入url到页面显示经历了哪些?

7、 Object.assign

  • 语法 Object.assign(target,params1,params2)
  • 方法实行的是浅拷贝
    const obj1 = {a: {b: 1}};
    const obj2 = Object.assign({}, obj1);
    obj1.a.b = 2;
    obj2.a.b // 2
  • 同名属性的替换
    const target = { a: { b: 'c', d: 'e' } }
    const source = { a: { b: 'hello' } }
    Object.assign(target, source)
    // { a: { b: 'hello' } }
  • 数组的处理

    Object.assign可以用来处理数组,但是会把数组视为对象

    Object.assign([1, 2, 3], [4, 5])
    // [4, 5, 3] 替代下标0,1的值
  • 取值函数的处理

    Object.assign只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。

    const source = {
      get foo() { return 1 }
    };
    const target = {};
    
    Object.assign(target, source)
    // { foo: 1 }
  • 处理字符串
    Object.assign({},'abc')
    // {0: "a", 1: "b", 2: "c"}
  • 数值和布尔值都会被忽略

8、 Set和Map结构

  • Set

    Set本身是一个构造函数,用来生成 Set 数据结构.它类似于数组,但是成员的值都是唯一的,没有重复的值。

    const s = new Set();
    [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
    for (let i of s) {
      console.log(i);
    }
    // 2 3 5 4
  • 数组去重
    // 去除数组的重复成员
    [...new Set([1,2,1,3,4])]
    // [1, 2, 3, 4]
  • Map

为了解决object只能用字符串作为键的问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

    const m = new Map();
    const o = {p: 'Hello World'};
    
    m.set(o, 'content')
    m.get(o) // "content"
    
    m.has(o) // true
    m.delete(o) // true
    m.has(o) // false

注意,只有对同一个对象的引用,Map 结构才将其视为同一个键。这一点要非常小心。

    const map = new Map();
    map.set(['a'], 555);
    map.get(['a']) // undefined

上面代码的set和get方法,表面是针对同一个键,但实际上这是两个不同的数组实例,内存地址是不一样的,因此get方法无法读取该键,返回undefined。

9、扩展运算符

扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。

  • 复制数组(浅拷贝)

    const a1 = [1, 2];
    // 写法一
    const a2 = [...a1];
    // 写法二
    const [...a2] = a1;
    
  • 合并数组

    const arr1 = ['a', 'b'];
    const arr2 = ['c'];
    const arr3 = ['d', 'e'];
    
    // ES5 的合并数组
    arr1.concat(arr2, arr3);
    // [ 'a', 'b', 'c', 'd', 'e' ]
    
    // ES6 的合并数组
    [...arr1, ...arr2, ...arr3]
    // [ 'a', 'b', 'c', 'd', 'e' ]
    
  • 与解构赋值结合

    const [first, ...rest] = [1, 2, 3, 4, 5];
    first // 1
    rest  // [2, 3, 4, 5]
    

    如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。

  • 字符串

    [...'hello']
    // [ "h", "e", "l", "l", "o" ]
    

10、for for...in for...of

* for循环,遍历数组 i值可以改变
* for...in 循环 i值不能改变
* for...of循环值

11 、工作中遇到的问题

  • Q:使用vue-router的addRoutes做权限管理,发现addRoutes后在this.$router.options.routes中获取不到动态添加的routes,无法显示菜单

分析原因:因为vue-router的设计是静态路由,虽然提供了addRoutes api,但是并没有添加到 this.$router.options.routes。

解决方案: 1、推荐: 维护一个vuex routes的数组,添加后放进去
2、不推荐: this.$router.options.routes.push(newRoutes) 改变了原有的设计,存在未知风险

  • Q:使用html2canvas生成图片,对于有滚动条的数据,生成的图片只有可视区域的数据,导致显示不完整

分析原因:html2canvas根据body中显示的元素生成图片,获取不到table中overflow为sroll的隐藏元素

解决方案:目前解决方案:去除table中的滚动条,使table的父级出现滚动条,这样就可以获取到整个table,感觉方案不怎么完美,探索其他方案中...

  • Q:v-for 如果使用index作为key,在数组变化时,当有checkbox勾选且第一项勾选第二项没有勾选时, 删除第一项数据后,第一项的checkbox勾选状态不对

分析原因:vue中的vdom是根据key复用的,若key相同,则当前节点被复用

解决方案:key 使用数据的唯一id,不实用index作为key