1、下面的代码的输出是什么?
function sayHi() {
console.log(name); //undefined
console.log(age);
var name = "JiaoMaiQi"; //ReferenceError
let age = 23;
}
sayHi();
解析:在函数中,我们首先使用了var关键字声明了name变量。这意味着变量在创建阶段会被提升,即var name会被分配内存空间,而赋值是在执行阶段进行。因此name变量提升之后,默认值为undefined。而let关键字声明变量也会存在变量提升,但是与var不同,初始化没有被提升。在我们声明(初始化)他们之前,他们是不可访问的。这被称之为“暂时性死区”。因此,当我们访问未声明的变量时,JavaScript就会抛出一个ReferenceError。
关于let是否存在变量提升,我们先看一个例子:
let name = 'JiaoMaiQi';
{
console.log(name);
let name = 'YangNan';
}
倘若let变量不存在变量提升,console.log(name)就会输出‘JiaoMaiQi’,结果却抛出了异常。因此,这很好的说明了,let也存在变量提升,但是它存在一个暂时性死区,在变量未初始化或赋值之前不允许访问。
变量的赋值可以分为三个阶段:
- 创建变量,在内存中开辟空间
- 初始化变量,将变量初始化为undefined
- 真正赋值
关于let、var和function:
- let的【创建】过程被提升了,但是【初始化】没有提升
- var 的【创建】和【初始化】都被提升了
- function 的【创建】和【初始化】和【赋值】都被提升了
2、下面代码输出什么?
for(var i = 0; i<3;i++){
setTimeout(() => console.log(i),1); //3,3,3
}
for(let i = 0; i < 3; i++){
setTimeout(() => console.log(i),1) //0,1,2
}
解析:由于JavaScript中的事件执行机制,setTimeout()函数被真正执行的时候,循环已经走完。由于第一个循环变量i是用var关键字声明的,因此该值是全局的。因此在第一个循环例子中当调用setTimeout函数时,i已经被赋值为3。
在第二个循环中,i是let关键字声明的:使用let和const关键字声明是具有块级作用域的。因此,在每次迭代期间,i将被创建为一个新的值,并且每个值都会存在于循环内的块级作用域。
3、下面的代码输出是什么?
const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2*Math.PI*this.radius
};
console.log(shape.diameter());
console.log(shape.perimeter());
解析:diameter是普通函数而perimeter是箭头函数。对于箭头函数,this关键字指向的是他的上下文(定义时的环境),与普通函数不同。这意味着当我们调用perimeter时,它不是指向shape对象,而是指向其定义时的环境(window)。因window并没有radius属性,因此返回undefined。
4、下面代码输出什么?
console.log(+true);
console.log(!"Lucy");
解析:一元加号会尝试将boolean类型转换为数字类型。true转换为1,false转换为0。字符串'Lucy'是一个真值。我们实际上要问的是“这个真值是假的吗?”。这会返回false。
5、下面代码输出什么?
let a = { hello: "word"};
let b;
b = a;
a.hello = "China";
console.log(b.hello);
解析:在JS中,当设置他们彼此相等时,所有对象都通过引用进行交互。首先变量a为对象保存一个值,之后,我们将b指定为a与对象相同的引用。更改一个对象时,可以更改所有对象。
6、下面代码的输出是什么?
let a = 4;
let b = new Number(4);
let c = 4;
console.log(a==b); //true
console.log(b===c); //false
console.log(a===c); //true
解析:new Number()是一个内置的函数构造函数。虽然它看起来像一个数字,但它并不是一个真正的数字:它有一对额外的功能,是一个对象。当我们使用“==”运算符时,它只检查它是否具有相同的值。他们都有4这个值,所以它返回true。当使用“===”操作符时,类型和值都需要相等,new number()不是一个数字,是一个对象类型。两者都返回false。
7、下面代码的输出是什么?
let greeting;
greetign = {};
console.log(greetign);
解析:控制台如上图所示会输出空对象,因为我们在全局对象上创建了一个空对象!当我们错误的将greeting输入为greetign时,js解释器实际上在浏览器中将其视为global.greetign = {}(或window.greetign = {})。因此,为了避免这种情况出现,我们可以使用“use strict”。这可以确保在变量赋值之前必须先声明变量。
8、当我们这样做的时候会发生什么?
function bark() {
console.log("woof");
}
bark.animal = "dog";
解析:此函数所含有的属性可以调用,不过该段代码不会输出什么,但也不会报错。
9、下面代码会输出什么?
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);
解析:对于sarah,我们没有使用new关键字。使用new时,它指的是我们创建的新空对象。但是,如果你不添加new它指的是全局对象。因此,我们指定的this.firstName等于'Sarah'和this.lastName等于'Smith'。实际上定义的是global.firstName = 'Sarah'和global.lastName = 'Smith'。sarah本身的返回值是undefined。
10、下面代码的输出是什么?
let number = 0;
console.log(number++);
console.log(++number);
console.log(number);
解析:后缀一元运算符++:
1、返回值(返回0)
2、增加值(数字现在是1)
前缀一元运算符++:
1、增加值(数字现在是2)
2、返回值(返回2)
11、下面代码输出什么?
function getAge(...args) {
console.log(typeof args);
}
getAge(22);
解析:扩展运算符(...args)返回一个带参数的数组。数组是一个对象,因此typeof args返回object。
12、下面代码输出什么?
function getAge( ) {
"use strict";
age = 21;
console.log(age);
}
解析:会报错ReferenceError。使用"use strict",可以确保不会意外的声明全局变量。我们从未声明变量age,因此我们使用"use strict",它会引发一个ReferenceError。