JS一些做题的零散知识点

5/12/2022

# js的正负值

  • 自动转换 2=="2" true 隐式转换number
  • null == undefined true
  • isNaN("true") true。 isNaN用于检查参数是否是非数字值。
  • 1 == true 布尔值会转换成number true即为1,0即为false。
  • {} == {} false 不同对象,引用值的地址都不同。
  • ‘’ == false true
  • null == true|false都是错的
  • null || undefined undefined
  • null && undefined null

# js放在head标签,和放在body底部,有什么区别?

  • 放head中的情况:脚本会优先加载,但加载过程中,<body>还没加载完,会使脚本访问不到<body>中的元素。
  • <body>底部:脚本在<body>加载后加载,能够保证脚本有效地访问<body>的元素。
  • 例外情况:脚本中没有访问<body>元素的情况下,两种加载方式效果一致。

# 喜闻乐见之 - 为什么0.1+0.2!==0.3 ?

  • 其实就是在相加的时候发生了两次精读丢失。
  • 相加的过程是这样的:先把数字从十进制转二进制,二进制转浮点数,浮点数相加,再转回十进制。 精读丢失的第一次是在数字转成双精度二进制浮点数时,第二次是在二进制浮点数相加的过程中,小数位相加多了一位, 所以又丢失一次 XD
  • 解决:ES6中有个属性Number.EPSILON,无限接近于0但不等于0。只要判断(0.1+0.2)-0.3小于 Number.EPSILON,在这个误差的范围内就可以判定0.1+0.2===0.3为true。

# 判断数据类型的方法

  • typeof: 用来判断基本数据类型的。引用类型和null都是返回Object(它是傻傻分不清obj的)
  • xxx instanceof 类型:只能判断两个对象是否属于实例关系,但是对于没有用new声明的数据类型它也是傻傻分不清的, 比如 let i=1,他是不知道是Number的。(所以在继承里用它判断的比较多)
  • xxx.constructor:constructor是原型对象的属性指向构造函数。对于上面的弊端,可以用这个处理。
  • Object.prototype.toString.call(xxx):某种意义上是最准确的判断类型方式。

# 判断数组的方法(数组是arr)

  • Array.isArray(arr) // ES6
  • xxx instanceof arr
  • Object.prototype.toString.call(arr)
  • arr.proto.constructor === Array

# 冒泡事件

# 不支持冒泡的事件(ui事件、鼠标移入移出事件、聚焦失焦事件)

  1. load, unload
  2. mouseenter, mouseleave
  3. blur, focus
  4. error
  5. resize, abort

# 支持冒泡的事件

  1. scroll, select, whell
  2. mousedown, mousemove, mouseout, mouseover, mouseup
  3. beforeinput, inputkeydown
  4. focusin, focusout
  5. click, dbclick

# 数组方法

# 改变原数组的数组方法

  • pop,push,reverse,shift,unshift,sort,splice

# 不改变原数组的方法(返回一个新数组)

  • concat,join,slice

# 代码回收

# 规则

  1. 全局变量不会被回收
  2. 局部变量会被回收,一旦函数执行完立即销毁
  3. 有一种例外,闭包里的变量不会被回收。(闭包缺点:内存泄露)

# 例子(有几个变量没有被回收?)

var i=1;
var i=2;
var add = function () {
    var i=0;
    return function () {
        i++;
        console.log(i);     // 1,这里是局部i
        console.log(this.i);     // 2,这里是全局i
    }
}();
add();
1
2
3
4
5
6
7
8
9
10
11
  • 有几个变量没有被回收:3个。分别是全局的i,局部的i,和全局的add()。
  • 这里有几个坑,下面来一一说明一下
  1. 全局存在两个同名变量,第一个会被第二个覆盖,所以全局的i=2。根据上面规则1,全局变量i不会被回收。
  2. add(),是一个函数表达式,它不会立即执行。但它也是一个全局变量,根据规则1,add不会被回收。
  3. add()同时也是一个闭包,局部变量i=1,同时因为是闭包,规则3,闭包里的局部变量i不会被回收。
  4. 因为最后调用add()的环境是window,所以this.i打印的是全局的i。

# 解决var变量问题(变量作用域考察)

  • 箭头函数的this是函数定义的对象,而不是使用函数的对象

# 经典试题

for(var i=0; i<5; i++){
 setTimeOut(function(){
  console.log(i);       // 5,5,5,5,5
 },1000)
}
1
2
3
4
5
  • 由于setTimeout是微任务,所以for执行完了之后才会执行setTimeout,此时的i已经是5。怎么让它能够输出想要的结果呢?
// 闭包
for(var i=0; i<5; i++){
    (function (j) {
        setTimeout(function () {
            console.log(j);
        }, 1000);
    })(i);  //把i传入作为里面的j参数
}

// setTimeout
for(var i=0; i<5; i++){
    setTimeout(function (param) {
        console.log(param);
    }, 1000, i);    //在这里把i传入
}

//let 这个不多说
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# a+'1' 和 'a'+1区别

  • 前一个会报错,后一个会隐式转换。至于为什么会报错,因为前者的a识别成了变量。。

# less sass

# 混入mixin 和 继承

  • 混入
    • 解释
      • 将多个vue文件内重复使用的功能代码,提取成单个js文件,在需要使用的地方进行调用即可。
      • 在一个js文件内定义一个对象, 在对象中可以写 vue文件内的 data 、methods、components等所有<script>中可以定义的代码。
    • 注意事项
      • 组件中的 data变量名 和 混入中的 data变量 名, 发生重名时, 以组件为准;
      • 组件中的 methods,computed,wath名称 和 混入中的 methods,computed,wath名称 名, 发生重名时, 以组件为准;
      • 组件中的 生命钩子函数 和 混入中的 生命钩子函数 名, 发生重名时, 都会执行, 但是组件中的钩子函数优先执行 ;
  • 继承
    • 注意:这里是不适合多继承的,多继承问题出现会多。
    • extends除了可以继承 .vue 文件,而且可以和 mixin一样使用 js文件内的对象。
    • extends继承 .vue 文件内的 template内的html是无法继承的
  • 区别
    • 先看看官方文档的定义, 其实两个都可以理解为继承;
    • mixins接收对象数组(可理解为多继承);
    • extends接收的是对象或函数(可理解为单继承)。
    • 注意: 如果一个组件, 既使用 继承, 又使用 混入, 它们二者中如果有重名, 则混入会覆盖继承