❝漫漫编程路,总有一些坑让你泪流满面。前端
❞
不写回调函数的话,是按照什么排序呢?git
JavaScript默认使用字典序(alphanumeric)来排序。所以结果是[1,10,2,5]github
正确排序的话,应该[1,2,5,10].sort( (a,b) => a-b )web
你认为输出是什么?面试
上面的表达式至关于'b'+'a'+ (+'a')+'a',由于(+'a')是NaN,因此:编程
'b'+'a'+ (+'a')+'a' = 'b'+'a'+ "NaN"+'a'='baNaNa'数组
这是一个经典JavaScript面试题浏览器
let res = new Array()
for(var i = 0; i < 10; i++){ res.push(function(){ return console.log(i) }) } res[0]() res[1]() res[2]() 复制代码
指望输出的是0,1,2,实际上却不会。缘由就是涉及「做用域」,怎么解决呢?安全
res.push(console.log.bind(null, i))
复制代码
解法还有其余的,好比使用IIFE,造成私有做用域等等作法。闭包
function fun(n,o) {
console.log(o) return { fun:function(m){ return fun(m,n); } }; } var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined,?,?,? var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,? var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined,?,?,? 复制代码
「留给大家思考」
var a = [0];
if (a) { console.log(a == true); } else { console.log("wut"); } 复制代码
大家以为答案是多少呢?这题涉及到隐式转换了,这个坑我本身的好好补一补
// 答案:false
「再来一道?」
function fn() {
return 20; } console.log(fn + 10); // 输出结果是多少 复制代码
function fn() {
return 20; } fn.toString = function() { return 10; } console.log(fn + 10); // 输出结果是多少? 复制代码
function fn() {
return 20; } fn.toString = function() { return 10; } fn.valueOf = function() { return 5; } console.log(fn + 10); // 输出结果是多少? 复制代码
「说到底JS类型转换的好好补一补了」
[1<2<3,3<2<1]
//[false,false] //[true,true] //[false,true] //[true,false] 复制代码
选一个吧,比较操做符,赋值运算符优先级哪一个更高呢?
面试的时候,问你这个问题,要是回答错误的话,估计面试官对基础非常怀疑!!!
问你这个题目的时候,你能够牵扯出不少问题,好比JS如何存储小数的呢?好比聊一聊二进制,好比实际开发中,遇到精度的问题,你是怎么解决的,你有什么好办法。
聊完这个,你能够牵扯出最大安全数,好比JavaScript的最大安全整数是多少,超出这个范围的话,怎么解决精度问题呢?
ES规范中新提出的BigInt解决了什么问题呢,你又发现了BigInt中哪些坑呢?
如何解决精度问题呢?
这里推荐Number-Precision库,不到1K的体积。
function sidEffecting(ary) {
ary[0] = ary[2]; } function bar(a, b, c) { c = 10 sidEffecting(arguments); return a + b + c; } function demo (arg) { arg.name = 'new Name' } console.log(bar(2, 2, 2)) 复制代码
涉及到ES6语法,这题答案确定都会作是22,可是呢,稍微改变一下题目,就比较坑了….
function sidEffecting(ary) {
ary[0] = ary[2]; } function bar(a, b, c = 4) { c = 10 sidEffecting(arguments); return a + b + c; } function demo (arg) { arg.name = 'new Name' } console.log(bar(2, 2, 2)) 复制代码
这个答案是多少呢?根据MDN上对argument有更加准确的定义,看argument
❝当非严格模式中的函数「有」包含剩余参数、默认参数和解构赋值,那么
❞arguments
对象中的值「不会」跟踪参数的值(反之亦然)。
找到这句话,bar函数存在默认参数,而且在非严格模式下,因此不会跟踪参数的值,天然结果就14
「请读者细细体会」
let demo1 = {class: "Animal", name: 'sheet'};
console.log(demo1.class) 复制代码
比较流氓,这个跟浏览器相关,class是保留字(如今的话,class是关键字),答案并没关系,重要的是本身在取属性名称的时候尽可能避免保留字. 若是使用的话请加引号 a['class']。
「保留字vs关键字」
我的理解的话,关键字就是有特殊含义的,不用用做变量名。好比
let class = 123;
复制代码
如今看来确定报错,那有什么须要咱们注意的呢?
let undefined = 123;
复制代码
这样子并不会报错,这个跟浏览器有点关系,这样子看来undefined不是关键字。因此为了保险起见,「建议你们在判断一个变量是否是未定义的话,尽可能使用void 0 === undefined」 颇有可能undefined会被看成是变量来赋值
「void 0 值就是undefined」
这个应该是常常碰见的题了,搞明白很简单,map函数怎么使用,parseInt函数怎么使用
关于Array数组的话,我以前写了一篇文章,从「源码角度解析大部分方法」
点进去重温一遍:[干货👍]从详细操做js数组到浅析v8中array.js
map接受两个参数,一个callback,一个this,即调用函数时this指向,其中callback回调函数是三个参数,一个currentValue,index,array;
parseInt接受两个参数:string,radix(基数)
返回NaN有两种状况
radix
小于
2
或大于
36
,或
parseInt('1', 0);
parseInt('2', 1); parseInt('3', 2); 复制代码
二者结合的话,结果天然很明显,[1,NaN,NaN]
Math.min() < Math.max() // false
复制代码
按照常规思路的话,应该是true,毕竟最小值应该小于最大值,可是实际状况是false
缘由:
要是面试官问这个问题,额。。。。
输出是什么?注意不是[].concat([1,2,3])
// [1,2,3] // Uncaught SyntaxError: .... // undefined 复制代码
答案是undefined,缘由是什么呢?
第一步计算[].concat,结果是Array.prototype.concat
第二步执行一个逗号操做符,逗号操做符对它的每一个操做对象求值(从左至右),而后返回最后一个操做对象的值。
>1,2,3 返回3 复制代码
第三步执行一个数组访问运算或属性访问运算
因此上面[].concat[1,2,3] 等价于Array.prototype.concat[3]
那么结果天然就是 undefined
。
//2 or -1
怎么办呢?
let realIsNaN = value => typeof value === 'number' && isNaN(value);
复制代码
先要判断类型,是由于字符串转换会先转换成数字,转换失败为 NaN。因此和 NaN 相等。
isNaN('jjjj') —> true
复制代码
第二种方法
let realIsNaN = value => value !== value;
复制代码
Number.isFinite('0') === isFinite('0')
Number.isFinite(0) === isFinite('0') 复制代码
打印结果是什么,能不能具体说一说?
❝Number.isFinite()检测有穷性的值,惟一和全局isFinite()函数相比,这个方法不会强制将一个非数值的参数转换成数值,这就意味着,只有数值类型的值,且是有穷的(finite),才返回
❞true
。
天然答案就是 false,true
function Foo() {
getName = function () { alert (1); }; return this; } Foo.getName = function () { alert (2);}; Foo.prototype.getName = function () { alert (3);}; var getName = function () { alert (4);}; function getName() { alert (5);} //请写出如下输出结果: Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName(); 复制代码
let newList = [1,2,3].push(4)
console.log(newList.push(4)) 复制代码
认为输出什么?
// Error
缘由在于Array.prototype.pu sh()返回的是新数组的长度,因此呢4.push(5)天然Error
function foo1() { return { bar: "hello" }; } function foo2() { return { bar: "hello" }; } var a=foo1(); var b=foo2(); console.log(a) //Object {bar: "hello"} console.log(b) //underfind //仔细看就知道了 // 会在第10行加入一个`;` 复制代码
会在第10行自动加一个分号; 因此返回的就是undefined
function foo() {
let a = b = 0; a++; return a; } foo(); typeof a; // => ??? typeof b; // => ??? 复制代码
上面的let a = b = 0; 等价于 window.b = 0, let a = b;
const length = 4;
const numbers = []; for (var i = 0; i < length; i++);{ numbers.push(i + 1); } numbers; // => ??? 复制代码
惟一须要注意的就是for语句
后面带了;
沙雕题
加了;
,会认为for执行完,因此指定的都是空语句,最后numbers为[5]
console.log('Hello World'[4])
复制代码
使用的就是方括号表示法获取字符串特定索引的字符,值得注意的是,IE7低版本使用的是charAt()
因此这题输出o
const name = 'TianTianUp'
console.log(!typeof name === 'string') console.log(!typeof name === 'object') 复制代码
typeof name 返回的是 ’string‘, 字符串’string‘是一个truthy值。所以!typeof name 返回一个布尔值false。因此
false === ’string'
和 false === ’object‘返回false
(检测一个类型的值话,咱们应该使用 !==而不是!typeof)
const nums = [1, 2, 3, 4, 5, 6];
let firstEven; nums.forEach(n => { if (n % 2 ===0 ) { firstEven = n; return n; } }); console.log(firstEven); 复制代码
惟一须要注意的就是forEach源码是怎么写的,看过源码的都知道,forEach使用return是不能停止循环的,或者说每一次调用callback函数,终止的是当前的一次,而不是整个循环。
结果天然就是6
有不错的题目,或者是JS中容易出错的坑,掘金网友能够提出来❤️,我会更新的啦🆗
若是你以为这篇内容对你挺有有帮助的话:
点赞支持下吧,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)
欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。
以为不错的话,也能够看看往期文章:
[诚意满满👍]Chrome DevTools调试小技巧,效率➡️🚀🚀🚀
[1.1W字]写给女朋友的秘籍-浏览器工做原理(渲染流程)篇