1.以下代码的输出是:
(function() {
var x=foo();
var foo=function foo() {
return "foobar"
};
return x;
})();
A. foo()
B. 类型错误
C. undefined
D. foobar
答案:B
JS中变量声明、函数声明会提升,而函数表达式不会提升。上面的代码执行顺序是:var x; var foo; x=foo(); 执行到这里会因为foo为undefined而报错(foo is not a function)。如果是下面的代码就不会报错:
(function() {
var x=foo();
function foo() {
return "foobar"
};
return x;
})();
2.下面哪些语句可以 在JS里判断一个对象oStringObject是否为String:
A. oStringObject instanceof String
B. typeof oStringObject == ‘string’
C. oStringObject is String
D. 以上答案都不正确
答案:A
var str1 = new String('js');
var str2 = 'js';
typeof str1; //object
typeof str2; //string
str1 instanceof String; //true
str2 instanceof String; //false
判断一个变量是否是字符串的周全的办法:
function isString(str){
return (typeof str == 'string')||(str instanceof String)
}
因为本题中说的是一个对象oStringObject,那它一定是用String构造函数创建的对象,只能用instanceof。
需要注意的是用到instanceof时,关键字的左边一定是对象,如果是基本类型的话那么返回一定是false,因为基本类型的变量不可能属于任何类,例如上面代码中的str2。关键字的右边一定是类名,例如Object、String、Array、Date等等或是用户通过构造函数自定义的类,例如:
function Person(name){
this.name = name;
}
var p = new Person();
p instanceof Person; //true
typeof运算符判断的是变量的数据类型。Js中的的数据类型有:undefined、null、string、number、boolean、object、(function)。使用typeof运算符返回的结果只有以上7中。function被作为一种特殊的object,会返回function。通过对象字面量、内建对象的构造函数、用户自定义的构造函数创建的对象都会返回object。
关于typeof和instanceof还有一个需要注意的是null,这是Javascript的历史遗留问题
typeof null; //object
null instanceof Object; //false
3.假设 output 是一个函数,输出一行文本。下面的语句输出结果是什么?
output(typeof (function() {
output('Hello World!')
})()
);
答案:Hello World undefined
typeof 立即执行函数 返回undefined哟
4.以下代码的运行结果:
var obj ={a:1,b:function () {alert(this.a)}};
var fun =obj.b;
fun();
答案:undefined
以上代码这样看比较清晰:
var foo = function(){
alert(this.a);
}
var obj ={a:1,b:foo};
var fun =obj.b;
fun();
foo是一个独立的函数,fun和obj.b都是对foo的引用。在函数中调用this时要根据具体的上下文来输出,下面讨论几种上下文情况:
- 全局调用,默认情况下执行foo(),此时的上下文是window。也就是代码中通过fun()调用。
- 对象的属性方法调用,上下文是对象本身。也就是代码中通过obj.b()调用的情况。
- call、apply调用,上下文是指定的对象。
- 构造函数中调用,上下文是被创建的对象。
5.关于javascript的原始类型(primitive type),错误的是
A. 有5种primitive type,分别是Undefined、Null、Boolean、Number 和 String
B. var sTemp = “test string”; alert (typeof sTemp);结果为string
C. var oTemp;alert(oTemp == undefined)为true
D. alert(null == undefined);结果为false
答案:D
null == undefined; //true
null === undefined; //false
==和===的区别简单的总结以下:
基本类型之间的比较
- 不同类型之间的比较:==会转化为相同类型后比较值是否相等,===因类型不同直接返回false
- 相同类型的比较:直接比较值是否相等,两者结果相同
引用类型之间的比较
- 两者都比较地址是否相等
基本类型与引用类型的比较
- ==将引用类型转化为基本类型后比较值是否相等,===因类型不同直接返回false
6.以下程序的运行结果:
function Foo(){
var i=0;
return function(){
document.write(i++);
}
}
var f1=Foo(),
f2=Foo();
f1();
f1();
f2();
答案:010
关于闭包的概念和作用就不解释了,这里想分析以下这两段代码(来自阮一峰博客):
代码1:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());
代码2:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());
代码中object.getNameFunc()()取到的是getNameFunc的闭包。有一点需要明确:闭包中this的上下文是全局作用域,而不是object;object.getNameFunc()中的this的上下文才是object。
第一段代码中this.name取到的是window下的name,”This Window”。第二段代码中由于在getNameFunc中将this存储在that中,在闭包中就能访问到this.name。
7.下列描述中,关于 js 函数定义方式,正确的是:
A. function add(a,b){return a+b;} 函数表达式
B. var add = new Function(‘a’,’b’,’return a+b’) 函数表达式
C. function add(a,b){return a+b;} 函数声明
D. var add = function(a,b){return a+b;} 函数声明
E. var add = new Function(‘a’,’b’,’return a+b’) 函数声明
答案:C
//函数声明
function add(a,b){return a+b;}
//函数表达式或函数字面量(函数本身为匿名函数,即使这里给了函数名的话也只能在函数内部通过函数名调用)
var add = function(a,b){return a+b;}
//构造函数或函数对象(可以接受任意数量的参数,但最后一个始终被作为函数体)
var add = new Function('a','b','return a+b');
8.以下代码的输出结果是:
var f = function g() {
return 23;
};
typeof g();
A. number
B. undefined
C. function
D. 报错
答案:D
函数表达式中的函数名是可选的。如果具有函数名的话,那它相当于函数内部的一个变量,在函数外部是无法调用的,所以报错会提示ReferenceError:g is not a function
。
在函数表达式中使用命名函数的一个情况是函数递归,这样也可以避免使用非标准的arguments.callee
属性。
被函数表达式赋值的变量一定会有name属性。name属性可以看作函数的名字,如果赋值的是匿名函数表达式时,name就是变量名;如果赋值的是命名函数表达式时,name就是函数名。
9.下列描述错误的是:
A. 在原型上扩展的可枚举方法,会被for in循环出来
B. 使用object.defineProperty可向对象添加或者修改属性
C. 每个对象都有prototype属性,返回对象类型原型的引用
D. 通过hasOwnProperty可判断一个对象以及其原型链上是否具有指定名称的属性
E. 原型链是JS实现继承的一种模型
F. For循环是按顺序的,for in循环是不一定按顺序的
答案:
关于for in和for of:
我们知道for in和for of最大的区别是:for in遍历的到的是key,for of遍历的到的是value,因此更合理的做法是使用for in遍历对象,使用for of遍历数组。ES6中的for of功能很强大,能够遍历数组、字符串、Set、Map、NodeList和生成器。
除此之外,用for in遍历数字还有很多弊端:
- for in能够遍历包括原型上的所有可遍历的属性。
- 遍历不一定按照数组的内部顺序
ES6中提供了一种新的方法,可以轻松的获取对象的自有键:
var obj = {a:'a',b:'b'};
Object.keys(obj); //['a','b']
hasOwnProperty
用于判断对象自身是否具有某属性
definePeoperty
用于为对象添加或修改属性,这里可以对属性进行更多的配置。在大部分的mvvm框架中会使用这个方法来实现数据绑定。
10.如何判断一个js对象是否是Array。arr为要判断的对象,其中最准确的方法是?
A.typeof(arr)
B. arr instanceof Array
C. arr.toString==='[object Array]'
D. Object.prototype.toString.call(arr) === '[object Array]'
答案:D
arr instanceof Array
返回true,但在跨frame对象构建的场景下会失效。
arr.toString
是一个函数,调用toString将数组转换为字符串:
var arr = [1,2,3];
arr.toString() //"1,2,3"
Object.prototype.toString.call()
可用于精确判断对象的类型,它会返回object和对象类型的组合:
Object.prototype.toString.call(123); //[object Number]
Object.prototype.toString.call('123'); //[object String]
Object.prototype.toString.call([1,2,3]); //[object Array]
Object.prototype.toString.call({}); //[object Object]
Object.prototype.toString.call(new Date()); //[object Date]
Object.prototype.toString.call(new Function()); //[object Function]
但无法判断用户自定义的对象类型,会统一判断为Object:
function Person(){}
Object.prototype.toString.call(new Person()); //[object Object]