带你填一些JS容易出错的坑|博客系列
# . VS = 操作符优先级
let a = {n : 1};
let b = a;
a.x = a = {n: 2};
console.log(a.x)
console.log(b.x)
@前端进阶之旅: 代码已经复制到剪贴板
输出是什么呢?
真的想明白了吗?
<details><summary><b>答案</b></summary> <p>undefined
{ n : 2}
</p> </details># 你真的了解作用域吗
var a = 0,
b = 0;
function A(a) {
A = function (b) {
console.log(a + b++)
}
console.log(a++)
}
A(1)
A(2)
@前端进阶之旅: 代码已经复制到剪贴板
留给你们思考,我可是第一遍就做错了(;′⌒`)
答案 1 4
可以好好想一想,你会茅塞顿开的。
# 类数组的length
var obj = {
"2" : 3,
"3" : 4,
"length" : 2,
"splice" : Array.prototype.splice,
"push" : Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj)
@前端进阶之旅: 代码已经复制到剪贴板
这段代码的执行结果?
答案:Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ]
@前端进阶之旅: 代码已经复制到剪贴板
解释就是第一次使用push,obj对象的push方法设置obj[2] = 1,obj.length++
解释就是第一次使用push,obj对象的push方法设置obj[3] = 2,obj.length++
使用console.log()方法输出的时候,因为obj上有length属性和splice方法,故将其作为数组输出打印
打印时因为数组未设置下标为0和1的值,故打印的结果就是empty,主动获取obj[0] = undefined
@前端进阶之旅: 代码已经复制到剪贴板
# 非匿名自执行函数,函数名只读
var b = 10;
(function b(){
// 'use strict'
b = 20
console.log(b)
})()
@前端进阶之旅: 代码已经复制到剪贴板
输出的结果是什么?
Function b
@前端进阶之旅: 代码已经复制到剪贴板
- 如标题一样,非匿名自执行函数,函数名不可以修改,严格模式下会TypeError,
- 非严格模式下,不报错,修改也没有用。
- 查找变量b时,立即执行函数会有内部作用域,会先去查找是否有b变量的声明,有的话,直接复制
- 确实发现具名函数Function b(){} 所以就拿来做b的值
- IIFE的函数内部无法进行复制(类似于const)
@前端进阶之旅: 代码已经复制到剪贴板
# 非匿名自执行函数 II
var b = 10;
(function b(){
// 'use strict'
var b = 20
console.log(window.b)
console.log(b)
})()
@前端进阶之旅: 代码已经复制到剪贴板
输出是多少呢?
10
20
// 访问b变量的时候,发现var b = 20;在当前作用域中找到了b变量,于是把b的值作为20
@前端进阶之旅: 代码已经复制到剪贴板
# 非匿名自执行函数 III
var b = 10;
(function b(){
console.log(b)
b = 5
console.log(window.b)
var b = 20
console.log(b)
})()
@前端进阶之旅: 代码已经复制到剪贴板
输出的结果是多少呢?
这个问题应该不难,就留给你们思考吧
# 变量提升
var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
@前端进阶之旅: 代码已经复制到剪贴板
在 JavaScript中, Fun 和 var 会被提升
相当于
var name = 'World!';
(function () {
var name;
if (typeof name === 'undefined') {
name = 'Jack';
console.log('Goodbye ' + name);
} else {
console.log('Hello ' + name);
}
})();
@前端进阶之旅: 代码已经复制到剪贴板
巩固一下:
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已经变成函数内局部变量
@前端进阶之旅: 代码已经复制到剪贴板
# 稀疏数组与密数组
var ary = [0,1,2];
ary[10] = 10;
ary.filter(function(x) { return x === undefined;});
@前端进阶之旅: 代码已经复制到剪贴板
执行结果如何呢?
做这个题目,你需要了解稀疏数组和密集数组
看过源码的同学应该知道,filter源码中,会去判断数组的这个索引值是不是数组的一个属性,有兴趣的同学可以看看我写的这篇关于数组的:[干货👍]从详细操作js数组到浅析v8中array.js
0 in ary; => true
3 in ary; => false
10 in ary; => true
也就是说 从 3 - 9 都是没有初始化的'坑'!, 这些索引并不存在与数组中. 在 array 的函数调用的时候是会跳过这些'坑'的.
@前端进阶之旅: 代码已经复制到剪贴板
所以答案就是[]
# 浮点运算
var two = 0.2
var one = 0.1
var eight = 0.8
var six = 0.6
[two - one == one, eight - six == two]
@前端进阶之旅: 代码已经复制到剪贴板
你认为结果是多少呢?面试遇到这个问题,应该怎么回答呢?
[true,false]
@前端进阶之旅: 代码已经复制到剪贴板
可以看看这些文章:
# Switch
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!');
}
}
showCase(new String('A'));
@前端进阶之旅: 代码已经复制到剪贴板
运行结果如何呢?
switch 是严格比较, String 实例和 字符串不一样.
答案自然是'Do not know'
所以一般情况下,写switch语句,也建议写default
@前端进阶之旅: 代码已经复制到剪贴板
String(“A”)
function showCase2(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!');
}
}
showCase2(String('A'));
@前端进阶之旅: 代码已经复制到剪贴板
运行结果呢?
答案:Case A
解析:String('A')就是返回一个字符串
@前端进阶之旅: 代码已经复制到剪贴板
# %运算符
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 余数的正负号随第一个操作数
@前端进阶之旅: 代码已经复制到剪贴板
# 数组的原型是什么
Array.isArray( Array.prototype )
@前端进阶之旅: 代码已经复制到剪贴板
这段代码的执行结果?
答案:true
解析:Array.prototype是一个数组
数组的原型是数组,对象的原型是对象,函数的原型是函数
@前端进阶之旅: 代码已经复制到剪贴板
# == 和 !优先级
[]== ![]
@前端进阶之旅: 代码已经复制到剪贴板
结果是什么呢?
(1)! 的优先级高于== ,右边Boolean([])是true,取返等于 false
(2)一个引用类型和一个值去比较 把引用类型转化成值类型,左边0
(3)所以 0 == false 答案是true
@前端进阶之旅: 代码已经复制到剪贴板
# 数字与字符串相加减
'5' + 3
'5' - 3
@前端进阶之旅: 代码已经复制到剪贴板
结果是多少呢?
答案:53 2
解析:加号有拼接功能,减号就是逻辑运算
巩固:typeof (+"1") // "number" 对非数值+—常被用来做类型转换相当于Number()
@前端进阶之旅: 代码已经复制到剪贴板
