文章目录
- 1. 👩🏻💻下面的两个哪个是无限循环的??(答案:第二个无限循环)
- 2. 【原型链方法】👩💻下面的题输出结果是什么??
- 3. 【['1', '2', '3'].map(parseInt)】👩🏼💻下面输出结果是什么??
- 4. 【[1,5,20,10].sort(function(a, b){return a - b})】👩🏽💻以下的执行结果是什么??
- 5. 【原型链】👩🏾💻以下关于原型链的问题
- 6. 【变量提升】👩🏿💻以下输出什么?
- 7. 【变量赋值】🍩判断下面输出是什么?
- 8. 【闭包】 🥟判断以下代码的输入输出?
- 9.🙆🏿♀️实现一个二进制加法,输入输出均为二进制字符串
- 10. 【变量提升/静态方法/实例方法/原型方法调用】
- 11. 将对象当数组使用,调用push()
- 12. 【递归/微任务/宏任务】
- 13. 【eventloop】promise常见执行顺序题
前言:这些都是自己日常收藏的觉得比较复杂一点、题目挺绕的、大家日常容易忽略的小知识点的题目。🥺
1. 👩🏻💻下面的两个哪个是无限循环的??(答案:第二个无限循环)
//第一个:
function ball(i) {
i=3;
return i+2
}
for (var i =0; i < 10; i++){
console.log(ball(i))
}
//第二个:
function bar(a) {
i = 3;
console.log( a + i );
}
for (var i=0; i<10; i++) {
bar( i * 2 );
}
第一个、?
解析:var
定义的变量会存在变量提升,则会提升到最前端。function()
函数定义并不会执行,当执行for
循环后;
i
= 0 执行ball(i)
,将i作为形参传入ball
函数,此时由于i
= 3,会先在该运算环境中寻找i
,在arguments
中找到i
,则将3赋值给i
,return 3+2 = 5
,则console.log(5)
;我在可以看到下图中我将arguments
打印出来的结果。
i
= 1,解析过程与i=0过程一样。
…后面的都一样。
第二个、?
解析:var
变量提升,提升到最代码前面;
此时执行第一次循环,i
= 0,然后执行bar
循环,i
* 2 = 0传入函数中,由于实参是a
,此时a
= 0,执行i
= 3,此时在改作用域并没有找到i
,就会往外找一层,此时找到i
,改变值,全局的i
变为了3,return 0 + 3 =3
;
第二次循环,此时的i
= 3,先执行i++
,i
= 4满足条件,再执行ball
函数,与第一次相同操作,i
= 3会将全居i变为3,此时a
= 4*2 = 8,return 8+4 = 11
;
第三次循环,此时的i
= 3,执行i++
,i=4满足条件,…(与第二步一样的操作)
2. 【原型链方法】👩💻下面的题输出结果是什么??
function Foo() {
Foo.a = function() {
console.log(1)
}
this.a = function() {
console.log(2)
}
}
Foo.prototype.a = function() {
console.log(3)
}
Foo.a = function() {
console.log(4)
}
Foo.a();
let obj = new Foo();
obj.a();
Foo.a();
执行结果:?
3. 【[‘1’, ‘2’, ‘3’].map(parseInt)】👩🏼💻下面输出结果是什么??
console.log(['1', '2', '3'].map(parseInt));
执行结果:?
解析:map
函数的回调函数会自动传入三个参数,数组元素,元素索引,数组本身,此时parseInt
需要两个参数,一个作为字符串,第二个参数会作为基数;
所以第一次,parseInt
函数会接受两个参数,(1, 0),此时1作为字符串,0作为基数,根据下图MDN的解释,当0作为基数,则1会按照10进制解析,返回1;
第二次循环,传入参数(2, 1),基数为1(1进制)表示的数中,最大值小于2,所以无法解析,返回NaN;
第三次循环,传入参数(3, 2),基数是2(2进制)表示的数应该要小于2,所以无法解析,返回NaN。
戳这里,map函数详解 | 戳这里,parseInt函数详解
4. 【[1,5,20,10].sort(function(a, b){return a - b})】👩🏽💻以下的执行结果是什么??
[1,5,20,10].sort(function(a, b){return a - b}); //[1, 5, 10, 20]
解析:一下是MDN关于sort(compareFunction(a,b))
的详解;
5. 【原型链】👩🏾💻以下关于原型链的问题
var a = new String('hah');
var b = new String('hah');
var c = 'hah'
console.log(a == b); //false
console.log(a == c); //true
console.log(a === c);//false
解析:
- 两个对象是不相等的
- 等于只会判断值是否相等,此时a和c的值是相等的
- 三等需判断值和类型都是否相等
6. 【变量提升】👩🏿💻以下输出什么?
<script>
console.log(fun)
console.log(person)
</script>
<script>
console.log(person)
console.log(fun)
var person = "Eric";
console.log(person)
function fun() {
console.log(person)
var person = "Tom";
console.log(person)
}
fun()
console.log(person)
</script>
- 报错 :由于fun没有定义,则会报错,且会阻断执行,所以第二个console.log不会输出
console.log(person); console.log(fun)
的输出:到第二个script,是一个执行域,所以进行变量提升,将func和person提升到最前面,变量不会赋值,但是函数声明式会将其函数体一同提升(函数表达式不会提升函数体),则输出undefined
和一个函数体。console.log(person)
此时已经赋值,则输出Eric
- 执行func(),此时发现又是一个执行域,则进行变量提升,将var person,提升至前面,则console.log(person)输出
undefined
,赋值后会输出Tom
- 当函数执行结束后,则该函数体的person变量被回收,则console.log(person)会找到该执行域的person,此时为
Eric
7. 【变量赋值】🍩判断下面输出是什么?
- 例子1
var a = {n: 1};
var b = a;
a.x = a = {n: 2};
console.log(a.x);
console.log(b);
- 例子2
let a = 12,
b = 12;
function fn() {
// console.log(a, b); // Uncaught ReferenceError: Cannot access 'a' before initialization at fn
console.log(b); // 12 获取的全局变量的b
let a = (b = 13); // 将13赋值给全局变量b,且定义了一个fn的局部变量a,赋值给13
console.log(a, b); // 13 13
}
fn();
console.log(a, b); // 12 13 // 全局变量a,b
- 例子3
let i = 1;
let fn = (i) => (n) => console.log(n + ++i);
let f = fn(1);
f(2); // 4 fn的i为1,n为2,函数先执行i+1,再输出2+2=4
fn(3)(4); // 8 fn的i为3,n为4,函数先执行i+1,再输出4+4=8
f(5); // 8 fn的i受f(2)的影响已经为2,n为5,函数先执行i+1,再输出5+3=8
console.log(i); // 1
- 例子4
var n = 0;
function a() {
var n = 10;
function b() {
n++;
console.log(n);
}
b();
return b;
}
var c = a(); // 11 b函数中的n为局部变量10
c(); // 12 b函数中的n形成闭包,n为11
console.log(n); // 全局变量n不变,为0
8. 【闭包】 🥟判断以下代码的输入输出?
借鉴有关闭包的文章
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);
var b = fun(0).fun(1).fun(2).fun(3);
var c = fun(0).fun(1); c.fun(2); c.fun(3);
解析:
- 第一个比较好理解就是返回fun(0)之后a的值就是
fun: function(){...}
函数,该函数内部m是后续传入的值,n是利用闭包,实现父函数的值n为第一次传入的值0; - 第二个链式调用,首先是未定义返回undefined,返回的是
func function(){...}; n = 0
,fun(1)调用之后,m=1; n=0;
,fun(2)返回的是函数中m=2, n=1
,fun(3)调用之后m=3, n=2
- 按照上面的推论
其实不难,就是需要注意m,n值的变化以及理解闭包。
9.🙆🏿♀️实现一个二进制加法,输入输出均为二进制字符串
binaryAdd('1010', '111') // '10001'
function binaryAdd(num1, num2) {
// 两个字符创最大的长度
let maxLen = Math.max(num1.length, num2.length)
// 字符串补位并转为数组
let arr1 = num1.padStart(maxLen, '0').split('')
let arr2 = num2.padStart(maxLen, '0').split('')
// 记录是否有进位
let tmp = 0
// 存储结果
let res = []
while(arr1.length) {
// 从末位往前逐位相加
let sum = +arr1.pop() + +arr2.pop() + tmp
// 如果和大于1,则需要往前进一位
if (sum > 1) {
tmp = 1
res.unshift(sum % 2)
} else {
tmp = 0
res.unshift(sum)
}
}
// 如果还存在进位,则需要往前补一位
if (tmp > 0) res.unshift(tmp)
return res.join('')
}
10. 【变量提升/静态方法/实例方法/原型方法调用】
function Foo() {
getName = function () {
console.log(1);
};
return this;
}
Foo.getName = function () {
console.log(2);
};
Foo.prototype.getName = function () {
console.log(3);
};
var getName = function () {
console.log(4);
};
function getName() {
console.log(5);
}
Foo.getName(); // 2 解析:调用函数的静态方法
getName(); // 4 解析:函数表达式会覆盖函数声明式方法
Foo().getName(); // 1 解析:调用函数自身的方法
getName(); // 1 解析: 受前一行代码执行影响相当于调用this.getName(), 其中this指向window,因为Foo方法里面定义getName的时候没有声明, 所以变成了全局变量
new Foo.getName(); // 2 解析:相当于执行new (Foo.getName)()
new Foo().getName(); // 3 解析:调用函数的实例方法, 相当于执行(new Foo()).getName()
new new Foo().getName(); // 3 解析:相当于执行new (new Foo()).getName)()
// 操作运算符的优先级: () > new > .
11. 将对象当数组使用,调用push()
var obj = {
2: 3,
3: 4,
length: 2,
push: Array.prototype.push,
};
obj.push(1);
obj.push(2);
console.log(obj);
// {2: 1, 3: 2, length: 4, push: ƒ} 解析:因为对象的length为2,所以push 1 2 会覆盖2 3 的值
// 对比
var obj = {
length: 2,
push: Array.prototype.push,
};
obj.push(1);
obj.push(2);
obj.push(3);
console.log(obj);
// {2: 1, 3: 2, 4: 3, length: 5, push: ƒ}
12. 【递归/微任务/宏任务】
function fn() {
fn();
}
fn(); // Uncaught RangeError: Maximum call stack size exceeded
var num = 0;
function fn() {
console.log(num++);
setTimeout(fn, 1000);
}
fn(); // 1 2 3 ...可以正常执行,为什么?
// 解析:原因是因为setTImeout属于异步宏任务,不在主线程栈内存中