43 道检验基础的 JavaScript 面试题(1)

题目来源于 https://zhuanlan.zhihu.com/p/75359676 ,觉得不错。一边做一边记录。

————CafuChino

1. 下面代码的输出是什么?

function sayHi() {
console.log(name);
console.log(age);
var name = "Lydia";
let age = 21;
}

这道题的考点无非就是考察let的特性和var的变量提升,因为众所周知var存在变量提升。考虑不周的话可能会认为第一行会输出“Lydia”,我第一反应的时候就犯了这个错误。实则不然,即使存在变量提升,调用的时候依然没有为name赋值,所以应该返回 undefined,而age因为let声明导致死区,变量不提升,会报错 ReferenceError

2. 下面代码的输出是什么?

for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}

for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}

这道题的考点是ES6中let的块级作用域和js的事件执行机制。答案是333和012

由于JavaScript中的事件执行机制,setTimeout函数真正被执行时,循环已经走完。 由于第一个循环中的变量i是使用var关键字声明的,因此该值是全局的。 在循环期间,我们每次使用一元运算符++都会将i的值增加1。 因此在第一个例子中,当调用setTimeout函数时,i已经被赋值为3

在第二个循环中,使用let关键字声明变量i:使用let(和const)关键字声明的变量是具有块作用域的(块是{}之间的任何东西)。 在每次迭代期间,i将被创建为一个新值,并且每个值都会存在于循环内的块级作用域。

3. 下面代码的输出是什么?

const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius
};

shape.diameter();
shape.perimeter();

这道题的考点是箭头函数的this指代问题。与普通函数不同,箭头函数的this指代 它所在上下文(定义时的位置)的环境 。也就是说实际使用的时候,perimeter中的this指的不是shape,而是window(全局定义的变量和函数归属于window),所以会返回undefined。这里答案是20和NaN(NOT a NUMBER)

4. 下面代码的输出是什么?

+true;
!"Lydia";

答案是1和false,涉及到两个特性:

  • 一元加号会把Boolean转换成数字,true为1,false为0。
  • 字符串是真值,!为非,非真为false。

5. 哪个选项是不正确的?

const bird = {
size: "small"
};

const mouse = {
name: "Mickey",
small: true
};
  • A:mouse.bird.size
  • B:mouse[bird.size]
  • C:mouse[bird["size"]]
  • D: All of them are valid

选A(仔细分析过后居然选对了),开发经验!

这道题其实考察的是JavaScript的对象键值,对象键值本质上依然是字符串,方括号里的值会被有限计算。了解这个规律之后其实很好解。A选项mouse对象没有bird键值,会返回undefined,undefined.size自然会报错 Cannot read property "size" of undefined剩下两个方括号里的值都可以计算出mouse对象有的键值。

6. 下面代码的输出是什么?

let c = { greeting: "Hey!" };
let d;

d = c;
c.greeting = "Hello";
console.log(d.greeting);

答案是"Hello",这道题真的是个大坑,不过有开发经验的话应该会有所体会。如果单纯按照赋值思想考虑的很容易得出,d被赋值的时候依然是{ greeting: "Hey!" }。所以答案是"Hey"(这是错误的!)原文作者已经写得很好了,所以直接贴上引用:

JavaScript中,当设置它们彼此相等时,所有对象都通过引用进行交互。首先,变量c为对象保存一个值。 之后,我们将d指定为c与对象相同的引用。** 更改一个对象时,可以更改所有对象。 **

————引自原文

7. 下面代码的输出是什么?

let a = 3;
let b = new Number(3);
let c = 3;

console.log(a == b);
console.log(a === b);
console.log(b === c);

答案是true,false,false,难度不大,就是==只比较值,===不仅比较值还比较类型,对象和整数肯定不会相等。

8. 下面代码的输出是什么?

class Chameleon {
static colorChange(newColor) {
this.newColor = newColor;
}

constructor({ newColor = "green" } = {}) {
this.newColor = newColor;
}
}

const freddie = new Chameleon({ newColor: "purple" });
freddie.colorChange("orange");

此题考点为static,static声明的方法为静态方法,只在构造函数中存在,在子对象中不存在。freddie对象中实际没有colorChange方法,会报错TypeError

9. 下面代码的输出是什么?

let greeting;
greetign = {}; // Typo!
console.log(greetign);

(送分题?)变量不经声明直接使用归属于global或者window,为全局变量。这个打错了的案例只是声明了个空对象而已。输出也是空对象{}

10. 当我们这样做时会发生什么?

function bark() {
console.log("Woof!");
}

bark.animal = "dog";

这道题很有趣,正解是没什么问题,正常执行。因为js中的函数也是一种特殊的对象,加一个属性也没什么问题。而我的思路比较特殊,考虑到如果没有赋值单独读取的话应该会返回undefined,对undefined进行赋值应该不会出问题。不过还是领会函数的正确本质比较重要。

11. 下面代码的输出是什么?

function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

const member = new Person("Lydia", "Hallie");
Person.getFullName = () => this.firstName + this.lastName;

console.log(member.getFullName());

这道题没做出来,以为还是箭头函数this指代的问题。但实际上答案应该是 TypeError 。原因引用原作者:

您不能像使用常规对象那样向构造函数添加属性。 如果要一次向所有对象添加功能,则必须使用原型。 所以在这种情况下应该这样写:Person.prototype.getFullName = function () { return${this.firstName} ${this.lastName}; }这样会使member.getFullName()是可用的,为什么样做是对的? 假设我们将此方法添加到构造函数本身。 也许不是每个Person实例都需要这种方法。这会浪费大量内存空间,因为它们仍然具有该属性,这占用了每个实例的内存空间。 相反,如果我们只将它添加到原型中,我们只需将它放在内存中的一个位置,但它们都可以访问它!

————引自原文

P.S.: javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用。 也就是说通过protocol属性,我们可以对函数原型的属性和方法进行操作。这道题和上一题的区别是:上一道题是常规对象(一个普通的函数),而这个是个构造函数。

12. 下面代码的输出是什么?

function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

const lydia = new Person("Lydia", "Hallie");
const sarah = Person("Sarah", "Smith");

console.log(lydia);
console.log(sarah);

答案是 Person {firstName: "Lydia", lastName: "Hallie"}undefined

第一个可以正常输出没有任何疑问,第二个的声明问题在于没有用new,(this真的是高频考点啊)如果没有用new,这个对象就归属于全局,此时的this是global或者window,sarah根本没有被赋值,自然是undefined。

12. 事件传播的三个阶段是什么??

答案: 在捕获阶段,事件通过父元素向下传递到目标元素。 然后它到达目标元素,冒泡开始。

案例:假设一个弹出登录窗口的页面,父元素为一个半透明遮罩,绑定点击事件为隐藏自身。子元素为登录窗口本身,上面有提交按钮。实际上当提交按钮被点击的时候,提交后父元素点击事件也被触发,这个过程叫做冒泡。 事件的对象有一个stopPropagation()方法可以阻止事件冒泡 。事件捕获是指不太具体的节点应该更早的接收到事件,而最具体的节点应该最后接收到事件 , stopPropagation()方法既可以阻止事件冒泡,也可以阻止事件捕获,也可以阻止处于目标阶段。 有点迷惑的话,有一张图解:

pic/201909092047432.png

感觉比较有趣,有空单开一篇文章分析其机制好了。

13. 所有对象都有原型

答: 除基础对象外,所有对象都有原型。 基础对象的原型是null

14. 下面代码的输出是什么?

function sum(a, b) {
return a + b;
}

sum(1, "2");

答案为"12",因为在这里发生了 隐式类型转换,1被隐式转换成了字符串。js中加号可以用来连接字符串,所以输出了"12"

15. 下面代码的输出是什么?

let number = 0;
console.log(number++);
console.log(++number);
console.log(number);

答案为:0,2,2,这道题感觉是C语言考试的相似题啊,自增放在前面是先自增再返回,放在后面是先返回再自增。所以过程是“返回=>自增=>自增=>返回=>返回”

16. 下面代码的输出是什么?

function getPersonInfo(one, two, three) {
console.log(one);
console.log(two);
console.log(three);
}

const person = "Lydia";
const age = 21;

getPersonInfo`${person} is ${age} years old`;

答案: ["", "is", "years old"] Lydia 21 因为如果使用标记的模板字符串,则第一个参数的值始终是字符串值的数组。 其余参数获取传递到模板字符串中的表达式的值。(这样做的目的是什么???)

17. 下面代码的输出是什么?

function checkAge(data) {
if (data === { age: 18 }) {
console.log("You are an adult!");
} else if (data == { age: 18 }) {
console.log("You are still an adult.");
} else {
console.log(`Hmm.. You don't have an age I guess`);
}
}

checkAge({ age: 18 });

这道题很有趣,因为对于对象来说,比较的不是他们的值,而是引用的地址hhhh,所以无论是相等还是严格相等都会判断false。(天坑啊)答案为:Hmm.. You don't have an age I guess,如果想比较值的话大概只能把值读取出来进行比较了。

18. 下面代码的输出是什么?

function getAge(...args) {
console.log(typeof args);
}

getAge(21);

答案为: "object",扩展运算符(... args)返回一个带参数的数组。 数组是一个对象,因此typeof args返回object

P.S.:** 对象中的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象**之中 (是对象啊!)

20. 下面代码的输出是什么?

function getAge() {
"use strict";
age = 21;
console.log(age);
}

getAge();

答案为: ReferenceError,是"use strict";的锅,严格模式下不可以不经声明就使用变量,age属性不会自动变成全局变量的。

21. 下面代码的输出是什么?

const sum = eval("10*10+5");

答案为:105——即使是是字符串eval也会对表达式进行求值的。(当然需要是个表达式)

22. cool_secret可以访问多长时间?

sessionStorage.setItem("cool_secret", 123);

其实就是在问sessionStorage的存储时间,事实上,sessionStorage中的数据关闭选项卡就没有了, localStorage 中的数据将会永远存在。(TODO:写篇这个的笔记吧。)

23. 下面代码的输出是什么?

var num = 8;
var num = 10;

console.log(num);

答案:10,var重复声明变量会直接覆盖。

24. 下面代码的输出是什么?

const obj = { 1: "a", 2: "b", 3: "c" };
const set = new Set([1, 2, 3, 4, 5]);

obj.hasOwnProperty("1");
obj.hasOwnProperty(1);
set.has("1");
set.has(1);

答案:true,true,false,true,对象的键值不指定字符串也是字符串,所以可以都返回true,而set不行。

25. 下面代码的输出是什么?

const obj = { a: "one", b: "two", a: "three" };
console.log(obj);

答案: { a: "three", b: "two" } 对象中相同的键的值会被替换,但是会保留第一次出现的位置。(想的简单点不就好了吗… :-))

(——未完待续)

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值