工作中积累的问题、知识点总结100题(21-40)
21.非匿名自执行函数
1.函数名只读
// b 打印的值是什么 var b = 10; (function b(){ b = 20; console.log(b) })()
解析:
- 如标题一样,非匿名自执行函数,函数名不可以修改,严格模式下会TypeError, - 非严格模式下,不报错,修改也没有用。 - 查找变量b时,立即执行函数会有内部作用域,会先去查找是否有b变量的声明,有的话,直接复制 - 确实发现具名函数Function b(){} 所以就拿来做b的值 - IIFE的函数内部无法进行复制(类似于const)
打印结果为:Function b
2.
// 打印的值 var b = 10; (function b(){ var b = 20; console.log(window.b) console.log(b) })()
输出:
10
20
3.
var b = 10; (function b(){ console.log(b) b = 5 console.log(window.b) var b = 20 console.log(b) })()
22.变量提升(21.10.22 更新)
var name = 'World!'; (function () { if (typeof name === 'undefined') { var name = 'Jack'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); } })();
上面得代码相当于
var name = 'World!'; (function () { var name; if (typeof name === 'undefined') { name = 'Jack'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); } })();
2.看下第二个示例
var str = 'World!'; (function (name) { if (typeof name === 'undefined') { var name = 'Jack'; console.log('Goodbye ' + name); } else { console.log('Hello ' + name); } })(str); //Hello World 因为name已经变成函数内局部变量
23.Switch (2021/10/27)
// 写一个方法 function showCase(value) { switch(value) { case 'A': console.log('Case A'); break; case 'B': console.log('Case B'); break; case undefined: console.log('undefined'); break; default: console.log('Do not know!'); } }
1.
showCase(new String('A')) // 答案是 'Do not know' 解析: switch 是严格比较,String 实例 和 字符串不一样 所以一般情况下,写switch语句的时候,都建议写 default
2.
showCase(String('A')) 答案: Case A String('A') 就是返回一个字符串
24, %运算符
function isOdd(num) { return num % 2 == 1; } function isEven(num) { return num % 2 == 0; } function isSane(num) { return isEven(num) || isOdd(num); } var values = [7, 4, '13', -9, Infinity]; values.map(isSane);
答案:
[true, true, true, false, false] 解析: % 如果不是数值会调用 Number() 去转化 '13'%2 // 1 Infinity%2 // NaN,Infinity 是无穷大 -9%2 // -1 9%-2 // 1,余数的正负号随第一个操作数
余数和被除数同号
14 ÷ -3 = -4 ··· 2
-14 ÷ -3 = 4 ··· -2
-14 ÷ 3 = -4 ··· -2
-14 ÷ 3 = -4...-2 (余数符号和被除数符号必须相同)
详情解析查看:https://blog.csdn.net/qq_34115899/article/details/79683041
25.运算
1.数组的原型
Array.isArray(Array.prototype);
答案:true
Array。prototype是一个数组,数组的原型是数组,对象的原型是对象,函数的原型是函数
2.==
[] == []
答案:false
两个引用类型,== 比较的是引用地址
3. == 和 ! 优先级
[] == ![]
答案:true
! 优先级高于 == ,右边Boolean([])是true,取返等于false
一个引用类型和一个值去比较,把引用类型转化成值类型,左边为0
所以是在比较 0 == false 答案 true
4.加减运算符,字符串与数字
'5' + 3 '5' - 3
答案: 53 2
加号有拼接功能,减号是逻辑运算
巩固: typeof(+'1') // ’number' , 对非数值+-常被用来做类型转换,相当于Number()
1 + - + + + + - + 1 // 2 , + - 又是一元加减操作符号,数学中的正负号,负负得正。
5.
var ary = Array(4); ary[0] = 22;
ary[3] = 2323; ary.map(i=>'1')
答案:['1', empty * 2, '1']
虽然ary的长度为3,但是存在两个没有内容的,array 上的操作会跳过这些
6.数组比较大小
var a = [1, 2, 3]; var b = [1, 2, 3]; var c = [1, 2, 3]; a == b; a === b; a > c; a < c;
答案:false false false true
相等(==)和全等(===)比较的是引用地址,引用间的大小比较是按照字典序比较,先比较第一项,再比第二项...
7.三元运算符的优先级
// 计算打印结果
var val = 'zhangning';
console.log('Value is ' + (val === 'zhangning') ? 'aaaaa' : 'bbbbb');
答案:aaaaa
字符串拼接比三目运算有更高的优先级
题意为:'Value is true' ? 'aaaaa' : 'bbbbb'
而不是:'Value is' + (true ? 'aaaaa' : 'bbbbb')
26.querySelectorAll 和 getElementsByClassName哪个性能好
返回的都是nodeList集合
1.getElementsByClassName 兼容IE9以上,是动态查询的过程,会随着dom结构的变化,得到的节点列表也会发生变化
<div class="wrap"> <div class="block"></div> <div class="block"></div> <div class="block"></div> </div> <script> var block=document.getElementsByClassName("block"); var wrap=document.getElementsByClassName("wrap")[0]; for(var i=0;i<block.length;i++){ block[i].style.backgroundColor="red"; } </script>
得到三个红色div;
当改变第二个div的类名时
<div class="wrap"> <div class="block"></div> <div class="block"></div> <div class="block"></div> </div> <script> var block=document.getElementsByClassName("block"); var wrap=document.getElementsByClassName("wrap")[0]; block[1].className="b"; for(var i=0;i<block.length;i++){ block[i].style.backgroundColor="red"; } </script>
得到两个红色div,如图
结论:随着dom结构改变,getElementsByClassName 可以动态获取节点列表
2.querySelectorAll 时css3、h5中新增的选择器,兼容IE8及以上,得到的是静态列表,他不会对dom结构进行动态查询,也就是说不是实时的
<div class="wrap"> <div class="block"></div> <div class="block"></div> <div class="block"></div> </div> <script> var block=document.querySelectorAll(".block"); var wrap=document.getElementsByClassName("wrap")[0]; for(var i=0;i<block.length;i++){ block[i].style.backgroundColor="red"; } </script>
得到三个红色div
<div class="wrap"> <div class="block"></div> <div class="block"></div> <div class="block"></div> </div> <script> var block=document.querySelectorAll(".block"); var wrap=document.getElementsByClassName("wrap")[0]; block[1].className="b"; for(var i=0;i<block.length;i++){ block[i].style.backgroundColor="red"; } </script>
虽然改变了第二个div的class,但是得到的依然是三个红色的div
区别:就是querySelectorAll的实现类似于一组元素的快照,而并非对文档结构进行搜索的动态查询,所谓快照就是把某个时刻dom中的结构记录下来,而不是通过查询dom结构动态获取,这样实现可以避免使用NodeList对象通常会引起的大多数性能问题。但是也有弊端,如果dom结构发生变化,选择器可能获取不到正确的nodeList。
27.Object.create(null) 创建对象没有原型
1.先看下 {}与Object.create(null)的区别
通过{} 创建的对象如下
通过Object.create(null)创建如下
1.通过字面量的方式定义对象原型指向Object.prototype,也就是obj._proto_ === Object.prototype,同时包含了toString,hasOwnProperty等方法
2.通过Object.create(null)创建出来的对象是一个干净对象,除自身属性外,没有附加其他属性
注:在Vue框架源码中,作者使用大量的Object.create(null) 来创建空对象。
1.通过Object.create(null) 创建出来的对象,没有任何属性,显示 No properties 。我们可以将其当成一个干净的 map 来使用,自主定义 toString, hasOwnProperty等方法
2.{...} 创建的对象,使用 for in 遍历对象的时候,会遍历原型链上的属性,带来性能上的损耗。
28.对数值和布尔类型结构
1.数值结构:等号左边的变量放在大括号中进行结构,可以获取到数组包装器结构函数原型中指定的方法。
let {valueOf} = 12; // [Function: valueOf]
2.布尔类型解构:等号左边的变量放在大括号中进行解构,可以获取到布尔包装器构造函数原型中指定的方法
let {valueOf} = false;// [Function: valueOf]