一、概念篇
ES5、ES6是什么,有什么区别?
参考答案
ES5泛指上一代语言标准。ES6泛指下一代JS语言标准,包含ES2015、ES2016、ES2017、ES2018等。ES5、ES6时间分界线是那一年?
参考答案
2015年babel是什么,有什么作用,在webpack中怎么使用?
参考答案
Babel是一个JavaScript编译器,可以将ES6代码转为ES5代码,使在目前不支持ES6浏览器上执行ES6代码。二、变量篇
var、let、const有什么区别?
参考答案
- var作用域是函数作用域,let、const作用域是块级作用域。
- var存在变量提升,let、const不存在变量提升,换句话来说let、const必须声明后才能使用。
- let、const在同个作用域中不能重复定义。
- const一般来声明常量,声明后不可以更改。
- const声明后必须马上赋值。
const声明的变量一定不能修改吗?
参考答案
const实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
对于基本类型的数据(Undefined、Null、Boolean、Number、String和Symbol〉而言,值就保存在变量指向的内存地址中,因 此等同于常量。
但对于引用类型的数据(主要是对象和数组)而言,变量指向的内存地址,其保存的只是个指针,指针指向堆内存中的数据。
const只能保证这个指针是固定的,至于它指向的数据是可以被修改的。
const foo = {};
//为foo加一个属性,可以成功
foo.prop = 123;
//将foo指向另一个对象,就会报错
foo = { prop : 123 }; //TypeError fo is read-only
a[6]()
的结果是什么,为什么?
var a=[];
for(var i= 0; i<10; i++){
a[i]= () =>{
console.log(i)
}
}
参考答案
结果是10。因为上面的代码中,变量`i`是var声明的,在全局范围内都有效,所以全局只有`i`个变量,每一次循环,变量`i`的值都会发生改变,而循环内,被赋给数组`a`的函数内部的`console.log(i)`中的`i`指向全局的`i`。也就是说,所有数组`a`的成员中的`i`指向的都是同一个`i`,导致运行时输出的是最后一轮的`i`值,也就是10。a[6]()
的结果是什么,为什么?
var a=[];
for(let i= 0; i<10; i++){
a[i]= () =>{
console.log(i)
}
}
参考答案
结果是6。因为上面的代码中,变量`i`是let声明的,当前的`i`只在本轮循环有效。所以每一次循环的 其实都是`i`个新的变量,另外JavaScript引擎内部会记住上一轮循环的值,初始化本轮的变量`i`时,就在上一轮循环的基础上进行计算。于是最后输出的是6。下面代码输出是什么,为什么?
for (let i = O; i < 3; i++){
let i='abc';
console.log(i);
}
参考答案
结果是打印三次abc
。因为for循环有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
下面代码各输出什么,为什么?
console.log(a);
console.log(b);
var a = 1;
let b = 1;
参考答案
结果是undefined
和VM30:2 Uncaught ReferenceError: b is not defined
。因为在以上代码中,变量a
使用var命令声明会发生变量提升,即脚本开始运行时,变量a
便己经存在,但是没有值,所以会输出undefined
。变量b
使用let命令令声明则不会发生变量提升。这表示在声明它之前,变量b
是不存在的,这时如果用到它,就会抛出一个错误。
什么是块级作用域
参考答案
是一个语句,将多个操作封装在一起,通常是放在一个大括号里,没有返回值。
执行函数f输出什么,为什么?
function f () {
let n = 5;
if (true) {
let n = 10;
}
console.log(n);
}
参考答案
输出5,因为if (true) { let n = 10;}
中变量n
,是处于块级作用域中,影响不到外面的变量n
。
在ES6环境中执行函数f输出什么,为什么?
function f(x = y,y = 2){
return {x,y}
}
参考答案
报错。因为let声明的变量有暂时性死区,在参数y
没声明前调用,即赋值给x
,就会报错。
什么是解构赋值?
参考答案
按照一定模式从数组和对象中提取值,然后对变量进行赋值。
在解构赋值时指定默认值,什么时候才能生效?
参考答案
当等号右边数组中对应的值严格等于undefined
在对数组解构赋值时,等号右边必须满足什么条件?
参考答案
必须满足其值或是转为对象后,要有Iterator接口。
下面代码执行结果是?
let [a, [, , [b]], d] = [1, [2, 3, [34]], 4];
console.log(b)
参考答案
34对数组的解构赋值和对对象的解构赋值有什么区别?
参考答案
数组的元素是按次序排列的,变量的取值是由它的位置决定的。而对象的属性没有次序,变量必须与属性同名才能取到正确的值。怎么用解构赋值的方法获取对象obj中的a,然后赋值给变量c,let obj = {a: 'a元素',b: 'b元素'}
?
参考答案
let obj = { a: 'a元素', b: 'b元素' }
let { a: c } = obj;
对象的解构赋值的内部机制是咋样的?
参考答案
let { a: a, b: b } = { a: 'a元素', b: 'b元素' }
按以上代码,是先找到同名属性a,然后再赋值给对应的变量a。真正被赋值的是后者,而不是前者。
下面代码执行结果是?
let obj = {
loc: {
start: {
line: 1,
column: 5
}
}
}
let {loc: { start: { line } } } = obj;
console.log(loc)
console.log(start)
console.log(line)
参考答案
因为以上只有line是变量,loc、start都是模式。故输出ReferenceError: loc is not defined
、ReferenceError: start is not defined
和1
。
如果要将一个已经声明的变量用于解构赋值,要怎么写?
参考答案
let x;
({ x } = { x: 1 })
因为JavaScript引擎会将{x}
理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免JavaScript将其解释为代码块才能解决这个问题。
字符串可以解构赋值吗?
参考答案
可以
let [a, b, c, d] = 'test';
console.log(a)//t
console.log(b)//e
console.log(c)//s
console.log(d)//t
let { length } = 'test';
console.log(length)//4
解构赋值的规则是什么?
参考答案
只要等号右边的值不是对象或数组,就先将其转为对象。
解构赋值的用途有哪些?
参考答案
- 交换变量的值
let x = 1; let y = 2; [x, y] = [y, x];
- 函数参数的默认值
- 提取JSON数据
三、字符串篇
字符串str是'XMS00087672542-YD',怎么判断str中有'876'? 怎么判断str头部有'XM'? 怎么判断str倒数第二个字符是'Y'? 怎么判断str中第三个字符是'S'?
参考答案
const str = 'XMS00087672542-YD';
console.log(str.includes('876'))//如果str中有'876',则是true,没有为false
console.log(str.startsWith('XM'))//如果str头部有'XM',则是true,没有为false
console.log(str.endsWith('Y',str.length-1))//如果str倒数第二个字符是'Y',则是true,没有为false
console.log(str.startsWith('S', 2))//如果str中第三个字符是'S',则是true,没有为false
String.includes()、String.startsWith()、String.endsWith(),这三个方法是做什么的,第二参数分别代表什么含义?
参考答案
- String.includes(str,n)表示是否找到了字符串str,找到返回true,找不到返回false。其中n表示第 n个位置到字符串结束位置之间的字符。
- String.startsWith(str,n)表示在字符串头部是否找到了str,找到返回true,找不到返回false。其中n表示第 n个位置到字符串结束位置之间的字符串头部。
- String.endsWith(str,n)表示在字符串尾部是否找到了str,找到返回true,找不到返回false。其中n表示字符串开始位置到第n-1个位置之间的字符串尾部。
在ES6中怎么补全字符串
参考答案
- String.padStart(n,str)用于字符串头部补全,其中n表示str补全后的字符串的最大长度,str表示用来补全的字符串。
- 如果将str填充到字符串头部后,字符串长度还达不到n,则会复制str填充到字符串头部,直到字符串长度达到n。
'x'.padStart(4,'ab')//abax
- 如果将str填充到字符串头部后,字符串长度超过n,则会先把str从头部开始截取长度为n减去要补全字符串长度,再填充到字符串头部。
'12'.padStart(10,'YYYY-MM-DD')//YYYY-MM-12
- 如果字符串长度已经大于n,则不补全直接返回字符串。
- 如果str不传,则会以空格来填充补全。
- 如果将str填充到字符串头部后,字符串长度还达不到n,则会复制str填充到字符串头部,直到字符串长度达到n。
- String.padEnd(n,str)用于字符串尾部补全,其中n表示str补全后的字符串的最大长度,str表示用来补全的字符串。
- 如果将str填充到字符串尾部后,字符串长度还达不到n,则会复制str填充到字符串尾部,直到字符串长度达到n。
'x'.padEnd(4,'ab')//xaba
- 如果将str填充到字符串尾部后,字符串长度超过n,则会先把str从头部开始截取长度为n减去要补全字符串长度,再填充到字符串尾部。
'x'.padEnd(4,'abcde')//xabc
- 如果字符串长度已经大于n,则不补全直接返回字符串。
- 如果str不传,则会以空格来填充补全。
- 如果将str填充到字符串尾部后,字符串长度还达不到n,则会复制str填充到字符串尾部,直到字符串长度达到n。
模板字符串是什么,举个例子来说。
参考答案
const a = '我是变量';
let str = `${a},我是常量`;
console.log(str)//我是变量,我是常量
四、数值篇
Number.isFinite()有什么作用?
参考答案
用来检查这个数值是否为有限的,例子:
Number.isFinite(15);//true
Number.isFinite(NaN);//false
Number.isFinite('a');//false
Number.isFinite(true);//false
Number.isFinite(Infinity);//false
Number.isNaN()有什么作用?
参考答案
用来检查一个值是否为NaN,例子:
Number.isNaN(NaN);//true
Number.isNaN(true);//false
Number.isNaN('a');//false
Number.isNaN(58/NaN);//true
Number.isNaN('a'/NaN);//true
Number.isNaN('a'/0);//true
Number.isInteger()有什么作用?
参考答案
用来判断一个值是否为整数,值不会自动转换成Number类型。例子:
Number.isInteger('255')//false
Number.isInteger(3)//true
Number.isInteger(3.0)//true
Number.parseInt()有什么作用?
参考答案
解析一个字符串直到达小数点或者数字的末端为止,并返回一个整数,如果字符串的第一个字符不能被转换为数字,那么会返回 NaN。例子:
Number.parseInt('0225D2.25')//225
Number.parseInt('0225.25')//225
Number.parseInt('D225.25')//NaN
Number.parseFloat()有什么作用?
参考答案
解析一个字符串直到达数字的末端或第二个小数点为止,并返回一个浮点数,如果字符串的第一个字符不能被转换为数字,那么会返回 NaN。例子:
Number.parseFloat('0225.25D25')//225.25
Number.parseFloat('0225.2.25')//225.2
Number.parseFloat('D225.25')//NaN
Math.trunc()有什么作用?
参考答案
用于去除一个值的小数部分,返回整数部分,会将不是Number类型的值先转成Number类型,对于空值和无法截取整数的值将返回 NaN。
Math.trunc(4.1);//4
Math.trunc('4.9');//4
Math.trunc(-4.1);//-4
Math.trunc('-4.9');//-4
Math.trunc('-0.9');//-0
Math.trunc('as');//NaN
Math.trunc(true);//1
Math.trunc(false);//0
Math.trunc();//NaN
Math.trunc('');//0
用ES5怎么实现Math.trunc()的功能?
参考答案
Math.trunc = function(x) {
return x < 0 ? Math.ceil(x) : Math.floor(x);
}
Math.sign()有什么作用?
参考答案
用来判断一个数到底是正数、负数、零和其它,对于非数值,会先将其转换为数值。
若是正数返回+1,若是负数返回-1,若是0返回0,若是-0返回-0,其他返回NaN。
Math.sign('2');//1
Math.sign(-2);//-1
Math.sign(0);//0
Math.sign(-0);//-0
Math.sign('a');//NaN
Math.sign();//NaN
Math.sign(NaN);//NaN
用ES5怎么实现Math.sign()的功能?
参考答案
Math.sign = function(x) {
x = +x;
if (x === 0 || isNaN(x)) {
return x
}
return x > 0 ? 1 : -1;
}
五、函数篇
下面代码执行结果是?
function foo(x,y='World'){
console.log(x,y)
}
foo('Hello');
foo('Hello','');
foo('Hello',null)
foo('Hello','China');
参考答案
'Hello World'
'Hello'
'Hello null'
'Hello China'
下面代码执行结果是?
function foo({x,y = 'World'}) {
console.log(x, y)
}
foo({x: 'Hello'});
foo({x: 'Hello',y: ''});
foo({x: 'Hello',y: 'China'});
foo()
参考答案
'Hello World'
'Hello'
'Hello China'
'Cannot destructure property `x` of 'undefined' or 'null'.'
上题代码中foo()
为什么报错,怎么解决该报错
参考答案
因为`foo()`参数不是对象,所以解构时候,取null的x属性肯定会报错。可以按下面代码改写 ``` function foo({x,y = 'World'}={}) { console.log(x, y) } foo()//undefined "World" ```下面代码执行结果是?
function foo(x,y){
console.log(x,y)
}
console.log(foo.length)
参考答案
2,函数的length属性将返回参数个数
下面代码执行结果是?
function foo(x,y=1){
console.log(x,y)
}
console.log(foo.length)
参考答案
1,函数的length属性将返回没有指定默认值的参数个数
下面代码执行结果是?
let x = 1;
function foo(x, y = x) {
console.log(y)
}
foo(2)
参考答案
2。
因为函数参数一旦设置默认值,函数进行声明初始化时,参数会形成一个单独的作用域,直到初始化结束后才会消失。且函数调用时,函数体内的局部变量影响不到默认变量。
所以在这个作用域内,默认变量值x指向第一个参数x,而不是指向全局变量x。
下面代码执行结果是?
let x = 1;
function foo(y = x) {
let x = 2 ;
console.log(y)
}
foo()
参考答案
1。
因为函数参数一旦设置默认值,函数进行声明初始化时,参数会形成一个单独的作用域,直到初始化结束后才会消失。且函数调用时,函数体内的局部变量影响不到默认变量。
所以在这个作用域内,默认变量值x没有定义,所以指向了全局变量x。
下面代码执行结果是?
function foo(y = x) {
let x = 2 ;
console.log(y)
}
foo()
参考答案
x is not defined
。
因为函数参数一旦设置默认值,函数进行声明初始化时,参数会形成一个单独的作用域,直到初始化结束后才会消失,且函数调用时,函数体内的局部变量影响不到默认变量。
所以在这个作用域内,默认变量值x没有定义,去全局也没找到变量x,所以报错。
下面代码执行结果是?
let x=1;
function foo(y = () => x) {
let x = 2 ;
console.log(y())
}
foo()
参考答案
1
。
因为函数参数一旦设置默认值,函数进行声明初始化时,参数会形成一个单独的作用域,直到初始化结束后才会消失,且函数调用时,函数体内的局部变量影响不到默认变量。
所以即使默认变量是个函数也遵循这个规则。
下面三段代码执行结果是?
var x = 1;
function foo(x,y = () => {x = 2;}) {
var x = 3;
y();
console.log(x)
}
foo()
var x = 1;
function foo(x,y = () => {x = 2;}) {
let x = 3;
y();
console.log(x)
}
foo()
var x = 1;
function foo(x,y = () => {x = 2;}) {
x = 3;
y();
console.log(x)
}
foo()
参考答案
3
、'已声明标识符“x”'、2
。
因为foo函数的参数形成了一个单独的作用域,在这个作用域内先声明了变量x,然后声明了变量y,变量y是个匿名函数,其内部的变量x指向用一个作用域的第一个参数x。在foo函数内部又声明了一个变量x。该变量x与第一参数x不是属于同一作用域,故它们不是同一个变量。在执行y()
后,不会对foo函数内部变量x造成影响,所以console.log(x)
会打印出来3。
如果把var x = 3
改成let x = 3
,因为let不能重复声明变量。所有就会报错。
如果把var x = 3
改成x = 3
,这是foo函数内部变量x也指向第一参数x。所有执行y()
,x会被改成2,所以console.log(x)
会打印出来2。
函数的rest参数是什么,使用时候要注意什么?
参考答案
可以用获取函数的多余参数,rest 参数搭配的变量是一个数组,该变量将多余的参数放入其中。
function add(x, ...params) {
let sum = x;
for (val in params) {
sum += params[val];
}
return sum
}
console.log(add(1, 2, 3, 4, 5)); //15
使用时,rest参数后不能再有参数了,同时函数的 length 属性不包括 rest 参数。
当函数参数使用默认值或解构赋值或扩展运算符时,函数内部能不能使用严格模式?为什么
参考答案
不能,这样规定的原因是,函数内部的严格模式同时适用于函数体和函数参数。但是,函数执行时,先执行函数参数,然后再执行函数体。这样就有一个不合理的地方:只有从函数体之中才能知道参数是否应该以严格模式执行,但是参数却应该先于函数体执行。
怎么获取一个具名函数的名称
参考答案
function foo(){}
console.log(foo.name)//foo
箭头函数的this是指向哪里
参考答案
函数体内的 this 对象就是定义时所在的对象,而不是使用时所在的对象。
箭头函数的this是指向哪里
参考答案
函数体内的 this 对象就是定义时所在的对象,而不是使用时所在的对象。
箭头函数可以作为构造函数吗
参考答案
不能
箭头函数可以使用arguments 对象吗
参考答案
不能,该对象在函数体内不存在。如果要用,可以用rest参数代替。
箭头函数可不可以使用 yield 命令
参考答案
不可以,箭头函数不能用作 Generator 函数
六、数组篇
怎么用数组扩展运算符合并数组
参考答案
let arr1 = [1,2,3];
let arr2 = [4,5,6];
let arr = [...arr1,...arr2];
console.log(arr)
怎么用数组扩展运算符求数组中最大值
参考答案
console.log(Math.max(...[1,2,3]))
为什么数组扩展运算符能把字符串转成真正的数组
参考答案
console.log([...'hello'])//["h", "e", "l", "l", "o"]
因为任何Iterator 接口的对象都可以用扩展运算符转为真正的数组。
Array.from()有什么作用,和数组扩展运算符有什么区别。
参考答案
Array.from()方法用于将两类对象转为真正的数组,第一类是类数组,第二类是可遍历(Iterator)对象。
而数组扩展运算符只能将可遍历(Iterator)对像,转成真正的数组。
//类数组一般含有length属性
let obj={
'0':'a',
'1':'b',
length:3,
}
console.log(Array.from(obj))//["a", "b", undefined]
console.log(...obj)//Found non-callable @@iterator
Array.of()有什么作用,和Array()有什么区别。
参考答案
Array.of()方法用于将一组值转换为数组。比Array()稳定,不会因参数个数的不同会导致结果有差异。
Array.of(1,2,3); //[1,2,3]
Array(1,2,3); //[1,2,3]
Array.of(3); //[3]
Array(3); //[ , , ]
Array.of(); //[]
Array(); //[]
说说copyWithin()的用法
参考答案
在当前数组内部将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。
copyWithin(target,start,end)
,有三个参数
- target(必选):从该位置开始替换数据。
- start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。
说说find()和findIndex的用法
参考答案
数组实例的find方法用于找出第一个符合条件的数组成员。其参数是一个回调函数,所有数组成员依次执行该回调函数。直到找出第一个返回值为 true 的成员,然后返回该成员,如果没有符合条件的成员,则返回 undefined。
回调函数有三个参数,分别是当前值、当前的位置、原数组。
数组实例的findIndex方法用于找出第一个符合条件的数组成员的位置。其参数是一个回调函数,所有数组成员依次执行该回调函数。直到找出第一个返回值为 true 的成员,然后返回该成员的位置,如果没有符合条件的成员,则返回 -1。
回调函数有三个参数,分别是当前值、当前的位置、原数组。