1、写出程序运行的结果()
var k = 0;
for(var i=0,j=0;i<10,j<6;i++,j++){
k += i + j;
}
console.log(k)
答案:30,解析:
考察知识点:逗号表达式只有最后一项是有效的,即对于i<10,j<6
; 来说,判断循环是否结束的是j < 6
;而对于 j<6,i<10
; 来说,判断循环是否结束的是 i < 10
。
k = 0+0=0 1+1+0=2 2+2+2=6 3+3+6=12 4+4+12=20 5+5+20=30 下一步j=6循环结束
2、在JavaScript中,调用对象属性的描述中,以下代码错误的是( )例如:调用对象obj的arr属性。
obj["arr"]
obj["a"+"r"+"r"]
obj{"arr"}
obj.arr
答案:C,解析:
AB本质是一致的,B多做了一步就是字符串拼接。
访问obj的方式有两种 :
- 点的方式
obj.arr
; - 中括号的方式
obj["arr"]
;
3、问:控制台打印的结果是?
for(let i=0;i<2;i++){
setTimeout(function(){
console.log(i)
},100);
}
for(var i=0;i<2;i++){
setTimeout(function(){
console.log(i)
},100);
}
答案:0122,解析:
①Js是单线程的,setTimeout
是异步宏任务,所以代码执行遇到异步的,就放在事件队列中的,等线程中的任务执行完后才会执行事件队列中的任务。
②let
是 es6 中声明变量的方式,有自己的作用域块,可以放变量,所以let
绑定for 循环
时,每个i都有自己的值. 在这个for循环
中就是满足一次条件向事件队列中添加一个打印i
的事件,且每个事件中的i
有自己的值
③ Var 没有作用域块,for循环 的变量就会后一个覆盖前一个,当循环完毕时i就只有一个值,又因为 for循环 的判断条件是不满足跳出,所以i最后是2而不是1
④这些完了后执行事件队列中的任务,就打印了 0122
4、运行以下程序,y和z的最终结果为:
<script>
var m= 1, j = k = 0;
function add(n) {
return n = n+1;
}
y = add(m);
function add(n) {
return n = n + 3;
}
z = add(m);
</script>
答案:4,4 解析:
js里面没有函数重载的概念,在其他语言中(如java)java中,可以存在同名函数,只要传入的参数数量或者类型不同即可。
在js中,定义了两个同名函数后,后面的函数会覆盖前面定义的函数。
结合这道题来说,由于函数声明提升,所以函数声明会提前,由于存在同名函数,后面的add函数将覆盖第一个 add 函数,所以两次调用 add() 返回的值是相同的。也就是 y,z 都为4.
5、以下代码执行后,a.x 和 b.x 的结果分别是?
function A(x){
this.x = x;
}
A.prototype.x = 1;
function B(x){
this.x = x;
}
B.prototype = new A();
var a = new A(2), b = new B(3);
delete b.x;
答案:2, undefined 解析:
知识点梳理
如果有x
但是没有赋值,则是 undefined
,相当于 x=undefined
. 就不会进入原型链
答案解析
function A(x){
this.x = x;
}
A.prototype.x = 1; //将A原型上的x设置为1
function B(x){
this.x = x;
}
B.prototype = new A(); //将B原型上的x设置为 A的一种object. 所以B实例出来object的prototype就是{x:undefined}
var a = new A(2),//a.x首先要在自己的构造函数中查找,没有采取原型上找,这里有this.x = x.所以a.x = 2;
b = new B(3);//此时 b.x = 3 ;但是因为上面[B.prototype = new A()],所以形成原型链,其父级prototype={x:undefined}
delete b.x; //删除实例b上的[x]属性,但是delete只能删除自己的x不能删除父级的x.
console.log(a.x,b.x)
var a = new A(2) 很容易理解,就是 a.x==2
看上面代码可以得知, 在进行到b = new B(3)
这步的时候 b 的原型 prototype={x:undefined}
delete b.x
; 删除实例 b上的[x]
属性, 但是 delete 只能删除自己的 x 不能删除父级的 x . 所以我们查看b.x
时会走到 b 的原型上就是 {x:undefined}
这里也是很容易踩到的陷阱,只要有这个属性,即便是undefined
也不会在原型上再往上找了
陷阱:
B的prototype=new A()
, 想错的可能都认为构造函数的 [ x ]
没有传值进去,this.x
赋值为undefined
, 所以还会去A的prototype
原型上找,找到 x = 1 -->错误
实际上是:如果构造函数 没有x
才会去原型下找
如果有x
但是没有赋值,则是undefined
,相当于x=undefined
. 就不会进入原型链了
6、假设 output 是一个函数,输出一行文本。下面的语句输出结果是什么?
output(typeof (function() {output(“Hello World!”)})());
undefined Hello World!
Object
string
function
Hello World! undefined
答案:E 解析:
1.先立即执行匿名函数,输出 Hello World!
2.函数执行后无返回值,则输出未定义
任何函数执行完一次,如果没有 return 返回值和声明变量接受返回值,都会立即消失,永远找不到值!
7、执行下面的代码,将会输出什么?
(function() {
var x=foo();
var foo=function foo() {
return "foobar"
};
return x;
})();
foo()
类型错误
undefined
foobar
答案:B 解析:
foo变量“被提前”了,但是他的赋值(也就是函数)并没有被提前,从这一点上来说,和前面我们所讲的变量“被提前”是完全一致的,并且,由于“被提前”的变量的默认值是 undefined
。
函数声明可以被提前,但函数表达式不能被提前
var x = foo();
var foo=function foo() {...}
语句中变量的声明会提升,但是定义不会提升。以上代码等同于:
var foo;
var x = foo();
foo = function foo() {...}
当执行到 x = foo() 时,由于foo未被定义为函数,所以会返回
TypeError: foo is not a function
8、下面的输出结果:
(function() {
var a = b = 5;
})();
console.log(b);
console.log(a);
答案:5,Uncaught ReferenceError: a is not defined
解析:
第一个考点在于var a=b=5
相当于拆解成var a=b; b=5
; 然后,b=5 前面没有 var,相当于声明为全局变量(这种方式在严格模式下会报错,此题不考虑)。
所以就相当于:
var b;
(fun…{ var a=b; b=5; })();
console.log(b); //5
console.log(a); //报错
此处报错也就是另一个考点,a 声明的是函数的局部变量,在函数结束是就销毁了,所以在全局下找不到 a ,于是报错。
9、以下哪个语句打印出来的结果时false?
alert(3==true)
alert(2=="2")
alert(null == undefined)
alert(isNaN("true"))
答案:A 解析:
// A:
1 == true // 布尔值会转成number true即为1 所以结果是true
2 == true // 布尔值会转成number true即为1 所以结果是false
3 == true // 布尔值会转成number true即为1 所以结果是false
1 == false // 布尔值会转成number false即为0 所以结果是false
0 == false // 布尔值会转成number false即为0 所以结果是true
B、数字字符串 2 会转换成数字 2 在和数字 2 进行比较 。==
js会优先选择将字符串转成数字==
C、Javascript规范中提到, 要比较相等性之前,不能将null
和undefined
转换成其他任何值,并且规定null == undefined
是相等的。
D、isNaN()
函数用于检查其参数是否是非数字值。
如果参数值为 NaN
或字符串、对象、undefined
等非数字值则返回 true
, 否则返回 false
。
10、以下哪些事件支持冒泡?
mouseenter
scroll
focus
keypress
答案:BD 解析:
不能被冒泡的9个事件:
① load 和 unload
② mouseenter 和 mouseleave
③ blur 和 focus
④ error
⑤ resize 和 abort
从3个角度说可分为 ui事件、鼠标移入移出事件、聚焦和失焦件,
11、以下关于Histroy对象的属性或方法描述正确的是()
back回到浏览器载入历史URL地址列表的当前URL的前一个URL
go表示刷新当前页面
length保存历史URL地址列表的长度信息
forward转到浏览器载入历史URL地址列表的当前URL的下一个URL
答案:AD 解析:
考察的是浏览器的内置对象管理模型,简称BOM(Browser Object Model)
中的Histroy
属性和方法。
History 对象
History 对象包含用户(在浏览器窗口中)访问过的 URL。
History 对象是 window 对象的一部分,可通过 window.history
属性对其进行访问。
注意: 没有应用于 History 对象的公开标准,不过所有浏览器都支持该对象。
History 对象属性
属性 | 说明 |
---|---|
length | 返回历史列表中的网址数 |
History 对象方法
方法 | 说明 |
---|---|
back() | 加载 history 列表中的前一个 URL |
forward() | 加载 history 列表中的下一个 URL |
go() | 加载 history 列表中的某个具体页面 |
12、下列代码存在几个变量没有被回收?( )
var i = 1;
var i = 2;
var add = function() {
var i = 0;
return function()
{
i++;
console.log(i);
}
}();
add();
答案:3个 解析:
全局变量 i = 1,赋值被替换为 2。
全局变量 add 返回值为一个函数
add() 执行内部函数后,产生闭包,函数内部变量 i 无法被回收。
代码回收规则如下:
1.全局变量不会被回收。
2.局部变量会被回收,也就是函数一旦运行完以后,函数内部的东西都会被销毁。
3.只要被另外一个作用域所引用就不会被回收(闭包)
13、现有如下html结构,依次点击4个li标签,正确的运行结果是()?
<body>
<ul>
<li>click me</li>
<li>click me</li>
<li>click me</li>
<li>click me</li>
</ul>
<script>
var elements = document.getElementsByTagName('li');
var length = elements.length;
for (var i = 0; i < length; i++) {
elements[i].onclick = function () {
console.log(i);
}
}
</script>
</body>
答案:4444 解析:
简单分析:
页面加载后会自动把脚本部分执行,执行完脚本,i=4。部分执行指的是,需要用户主动触发才能执行的点击事件没有被执行。当点击 click me 时 触发 onclick
事件 此时的i
早已是 4。
for循环 当中使用 var 定义的 i
变量作用域是在全局作用域。所以当脚本执行完毕全局环境中的 i = 4,每个li标签的 onclick 事件执行时,本身onclick
绑定的function的作用域中没有变量 i
,解析引擎会寻找父级作用域,发现父级作用域中有 i = 4。这是作用域的问题。
权威解答——来自javascript语言精粹
var elements=document.getElementsByTagName('li');
var length=elements.length;
for(var i=0;i<length;i++){
elements[i].onclick=function(){
alert(i);
}
}
解答:这里的事件,绑定的并非是i的值,而是i
本身(alert里的 i ),所以当程序执行完,i的值变为 4,去执行onclick
事件时,执行 alert(i) ,自动查找i
,值为 4,所以依次弹出 4。
改正:
var elements=document.getElementsByTagName('li');
var length=elements.length;
var handler = function(i){
return fucntion(){
alert(i);
}
}
for(var i=0;i<length;i++){
elements[i].onclick= handler(i);
}
避免在循环中创建函数,可以在循环之外创建一个辅助函数,让这个辅助函数返回一个绑定了当前i值得函数,避免混淆
一个相关的类似问题,有代码如下:
for(var i=0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
可以猜到代码执行1s后,依次打印10个"10".
几个有效的解决办法
1、利用块级作用域(最简单,推荐)
for(let i=0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
// 依次打印0 - 9
2、利用自执行函数,将 i 作为参数传入
for(var i=0; i < 10; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 1000);
})(i);
}
3、利用setTimeout的第三个参数,将i作为参数传入function
for(var i=0; i < 10; i++) {
setTimeout(function(j) {
console.log(j);
}, 1000, i);
}
4、利用promise(使用promise的办法,是为了更好地理解promise)
for(var i=0; i < 10; i++) {
new Promise((resolve, reject) => {
var j = i;
setTimeout(function() {
console.log(j)
}, 1000);
})
}
5、利用async函数(为了理解async函数)
async function foo() {
for(var i=0; i < 10; i++) {
let result = await new Promise((resolve, reject) => {
setTimeout(function() {
resolve(i);
}, 1000);
});
console.log(result);
}
}
foo();
// 每隔1s打印数字 0 - 9
14、如下代码输出的结果是什么:
console.log(1+ "2"+"2");
console.log(1+ +"2"+"2");
console.log("A"- "B"+"2");
console.log("A"- "B"+2);
答案:122,32,NaN2,NaN
解析
console.log(1+ "2"+"2");
A:对于加法来说,如果只有一个操作数是字符串,则将另一个操作数也转换为字符串,然后将两者拼接,为122
console.log(1+ +"2"+"2");
B:(+“2”)应用了一元加操作符,一元加操作符相当于Number()函数,会将 (+“2”)转换为2,1+2+“2”=32
console.log("A"- "B"+"2");
C:在减法中遇到字符串和加法相反,调用Number()函数将字符串转换为数字,不能转换则返回NaN,此时运用加法规则,NaN+“2”,"2"是字符串,则将两者拼接。
console.log("A"- "B"+2);
D:这个与上面的不太相同,减法运算后依然为NaN,但是加号后面的为数字2,加法规则中,如果有一个操作数是NaN,则结果为NaN
15、与其他 IEEE 754 表示浮点数的编程语言一样,JavaScript 的 number 存在精度问题,比如 0.2 + 0.4 的结果是 0.6000000000000001。以下选项中,能得到 0.6 的是?
parseFloat(0.2 + 0.4)
parseFloat((0.2 + 0.4).toFixed(1))
Math.round(0.2 + 0.4)
parseFloat((0.2 + 0.6).toPrecision(1))
答案:B ,解析:
parseFloat
解析一个字符串,并返回一个浮点数
toFixed
把数字转换为字符串,结果的小数点后有指定位数的数字
Math.round
把一个数字舍入为最接近的整数
toPrecision
把数字格式化为指定的长度
16、现有一组人员年龄的数据,要求将这些人员的年龄按照从小到大的顺序进行排列起来,要怎样来实现( )
// A
function numberSort(a, b) {
return a - b;
}
var arr = new Array("23", "6", "12", "35", "76");
document.write(arr.push(numberSort));
// B
function numberSort(a, b) {
return b - a;
}
var arr = new Array("23", "6", "12", "35", "76");
document.write(arr.push(numberSort));
// C
function numberSort(a, b) {
return b - a;
}
var arr = new Array("23", "6", "12", "35", "76");
document.write(arr.sort(numberSort));
// D
function numberSort(a, b) {
return a - b;
}
var arr = new Array("23", "6", "12", "35", "76");
document.write(arr.sort(numberSort));
答案:D 解析:
arr.sort([compareFunction])
一、sort() 方法参数为空(即没有指明 compareFunction) ,元素按照转换为的字符串的诸个字符的 Unicode 位点进行排序,
本题不涉及,不详说。
二、sort() 方法参数指明 compareFunction ,数组会按照调用函数的返回值排序(这句不懂没关系)。
如:
[3, 2, 1].sort(function (a, b) {
return a - b;
});
它会将数字数组 [3, 2, 1] 按 小到大 排序后返回 更新后的数组 [1, 2, 3]。
执行的机制(两数比较,小的排在大的前面):
a - b < 0
,那么 a 会被排列到 b 之前;a - b = 0
,a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);a - b > 0
,那么 b 排列到 a 之前。
三、如何快速掌握呢?
升序排序 return a - b; 降序排序 return b - a。
学习传送门:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort