这是我在Javascript微信公众号上看到的一篇文章,以为挺有意思的,因此转载过来跟你们分享一下,同时,对这些题目也加上了一些我我的的理解,若是有不对的地方,请你们指正。面试
题目一数组
(function(){ return typeof arguments; })();
答案:Object浏览器
typeof
所返回的可能值为:number
、string
、boolean
、undefined
、object
、function
。而咱们知道arguments
是一个伪数组,而伪数组也是一个对象,因此答案应该是Object
。那么,若是把typeof arguments
改为arguments instanceof Array
呢?微信
能够看到,返回的是false
。所以,伪数组不是一个数组,只有在使用了Array.prototype.slice.call()
进行了转换后,才能转化成一个真数组。函数
题目二this
var f = function g(){ return 23; }; typeof g();
答案:会报错(g()未定义)spa
这段代码中混合了函数声明和函数表达式的形式,而函数其实是绑定到了f上而不是g。可是这么写是否符合Javascript的要求呢?在《Javascript高级程序设计》中:prototype
也能够同时使用函数声明和函数表达式,例如:
var sum = function sum(){}
。不过,这种语法在safari中会致使错误。设计
既然在除了safari之外的浏览器能够同时使用函数声明和函数表达式来声明函数,那么为何题目中的代码会报错呢?个人理解是,这样写的结果是致使了函数名g被包装进了f中,变成了f的一个局部变量,只能在f函数内部访问到g,我把代码修改了一下:code
var f = function g(){ alert(g); return 23; }; f();
我在f函数内部访问g,弹框弹出的内容为function g(){ alert(g);return 23; }
,没有报错而且访问成功,g的函数体内容与f是同样的,只是函数名不同。
————————我是一条分割线——————————
咱们再来回顾一下函数声明与函数表达式吧(由于在以前的一次面试中被问到了它们的区别,我一下没打上来……因此仍是加强一下记忆)
函数声明的形式:
function funcName(){ /*some code*/}
函数表达式的形式:
var funcName = function(){/*some code*/}
在《Javascript高级程序设计》中有一段话:
解析器在向执行环境中加载数据时,对函数声明和函数表达式并不是一视同仁的。解析器会率先读取函数声明,并使其在执行任何代码以前可用(能够访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。
也就是说,在函数声明的代码段以前访问函数,是可以访问到的(函数声明提高)。而在函数表达式的代码段以前访问函数,则会发生错误,由于在执行到函数所在语句以前,函数表达式声明的变量名中不会保存对函数的的引用。
除此以外函数声明与函数表达式的语法实际上是等价的。
题目三:
(function(x){ delete x; return x; })(1);
答案:1
注意:delete是用来删除对象的属性,没法删除普通变量。
题目四
var y = 1, x = y = typeof x; x;
答案:undefined
由于赋值运算是从右往左的,所以题目中的代码展开来等价于:
var y = 1; y = typeof x; var x = y; x;
第二行代码在访问x时,x并无声明,值为undefined,因此typeof x
也就是undefined
了。
题目五
(function f(f){ return typeof f(); })(function(){ return 1; });
答案:number
把代码分开来看会比较清楚:
var baz = function(){ return 1; }; (function f(f){ return typeof f(); })(baz);
先将function(){ return 1; }
赋值给baz
,则baz()
应该是1。再把baz
当成参数传入到当即执行函数中,当即执行函数返回的是传入的参数的类型,即baz()
的类型,baz()
返回1类型为number
。
题目六
var foo = { bar: function() { return this.baz; }, baz: 1 }; (function(){ return typeof arguments[0](); })(foo.bar);
答案:undefined
这里关键要理解this
的所指。arguments[0]
即foo.bar
,而函数中的this
指的就是调用arguments[0]()
这个函数的对象,即window
对象。可是window
对象并无baz这个属性,所以,返回的是undefined
。
题目七
var foo = { bar: function(){ return this.baz; }, baz: 1 } typeof (f = foo.bar)();
答案:undefined
将代码改写一些变成:
var foo = { bar: function(){ return this.baz; }, baz: 1 } var f = foo.bar; typeof f();
foo.bar
是一个函数,将foo.bar
赋值给了f
,那么f
变成了一个函数名。直接调用f()
时,调用它的对象为window
,而window
中并无baz
属性,因此输出的是undefined
。
题目八
var f = (function f(){ return "1"; }, function g(){ return 2; })(); typeof f;
答案:number
在这里,咱们须要了解一下逗号操做符的做用:
在用于赋值时,逗号操做符总会返回表达式中的最后一项。
因此,这个当即执行函数返回的应该是后面那个函数的返回值,返回值为2,类型为number
。
题目九
var x = 1; if (function f(){}) { x += typeof f; } x;
答案:1undefined
首先,第一个问题是:函数在判断语句中判断的结果是true仍是false?,咱们能够运行一下如下代码:
Boolean(function f(){});//true
将一个空函数转换为布尔型,结果为true,因此题中的代码是可以进入if语句的。那么第二个问题是:为何typeof f
会是undefined
?由于if
判断条件中并不能真正的声明一个函数,所以,f
是一个没有被声明过的函数名,它的类型为undefined
。
题目十
(function f(){ function f(){ return 1; } return f(); function f(){ return 2; } })();
答案:2
咱们在题目四里说过:Javascript解析器会率先读取函数声明,使它在任何代码之间可用。所以,在外层函数f
函数体内的两个函数声明,都会提高到return f()
以前执行。而又由于Javascript没有重载,所以以最后执行的同名函数输出结果为准。
题目十一
function f(){ return f; } new f() instanceof f;
答案:false
一、首先咱们要了解instanceof
的做用:instanceof
是用来检测变量是不是给定引用类型的实例。
二、而后再看f()
函数体中return f
,返回了本身。
三、经过new
来调用构造函数生成实例的过程为:1)建立一个空对象;2)将类的prototype中的属性和方法复制到实例中;3)将第一步建立的空对象作为类的参数调用类的构造函数;4)返回一个新的实例对象。
然而,在以new
形式调用构造函数f()
时,f()
返回了自身,将new
返回的实例对象覆盖掉了,所以,new
以后的结果不是f
的一个引用了。
题目十二
var x = [typeof x, typeof y][1]; typeof typeof x;
答案:string
很明显的能够看出typeof x = undefined
和typeof y = undefined
,那么x
是undefined
。其实其余的都不看,光看typeof typeof
就能肯定输出的是string
了。
题目十三
(function(foo){ return typeof foo.bar; })({ foo: { bar: 1 } });
答案:undefined
这道题目有一个小陷阱,一不注意还真被忽悠进去了。咱们仔细看一个参数传入的内容最外面有一对{}
,那么咱们把题目修改一下就一目了然了:
var temp = { foo: { bar: 1 } }; (function(foo){ return typeof foo.bar; })(temp);
传入的参数为temp这个对象,所以函数中的foo.bar
实际上为temp.bar
,可是temp
里只有foo一个属性,没有bar,因此应该是undefined
。