在网上看到一波笔试题。感觉好几个都不会,特拿来研究一下。
题目一
(function(){
return typeof arguments;
})();
结果:“object”
arguments是伪数组对象。虽然不是数组,但是可以使用方括号或数组索引来获取元素。
//可以转换成数组。
Array.prototype.slice.call(arguments);
其实数组使用typeof返回的也是object
关于typeof:参见MDN typeof
另附instanceof:MDN instanceof
题目二
var f = function g(){ return 23; };
typeof g();
结果:报错
这叫函数表达式:
var f = function (){ return 23; };
这叫函数声明:
function g(){ return 23; };
那这个是什么?函数表达式还是函数声明??
var f = function g(){ return 23; };
这里有一个外国小牛牛的文章:http://kangax.github.io/nfe/
里面是这么说的:
We can see that when identifier is omitted, that “something” can only
be an expression. But what if identifier is present? How can one tell
whether it is a function declaration or a function expression — they
look identical after all? It appears that ECMAScript differentiates
between two based on a context. If a function foo(){} is part of, say,
assignment expression, it is considered a function expression. If, on
the other hand, function foo(){} is contained in a function body or in
a (top level of) program itself — it is parsed as a function
declaration.
如何界定它是函数表达式还是函数声明呢?ECMAScript界定它们使用的是上下文。
- 如果 function foo(){}是一个赋值表达式的一部分,它就被认为是函数表达式。
- 如果function foo(){}包含在一个函数体内或者在一个(最高等级的)程序里,就被解释为一个函数声明。
//函数声明 因为它是整个程序的一部分
function foo(){} // declaration, since it's part of a <em>Program</em>
//函数表达式 因为它是赋值表达式的一部分
var bar = function foo(){}; // expression, since it's part of an <em>AssignmentExpression</em>
//函数表达式 因为它是new表达式的一部分
new function bar(){}; // expression, since it's part of a <em>NewExpression</em>
//函数声明 因为它是一个函数体的一部分
(function(){
function bar(){} // declaration, since it's part of a <em>FunctionBody</em>
})();
现在明白了
var f = function g(){ return 23; };
这个表达式是一个函数表达式。没有函数提升,而且把函数的指针赋值给f。
更重要的是,函数的名字(g)只在函数内部有意义
var f = function g(){ console.log(typeof g); };
console.log(typeof f);
//下面这句话报错,g在函数外部没有意义
// console.log(typeof g);
f();
运行结果:function function
详细讨论见:汤姆大叔的深入理解javascript
函数名称在函数外面没有意义。
第三题
(function(x){
delete x;
return x;
})(1);
运行结果:1
这里有一篇很不错的文章:delete的内部原理
我们知道,定义的函数和变量不能被delete删除,传入函数的arguments也不能被delete删除,而变量的属性可以被删除。
实际上,通过变量声明创建的全局对象,就会被解析成一个全局变量的属性,这个属性拥有一个特殊的属性DontDelete属性,是DontDelete这个属性让delete函数不能正确执行。
而,通过变量赋值没有变量声明的对象,会被解析成一个全局变量的属性,这个属性没有DontDelete属性,delete函数可以正确执行。
var GLOBAL_OBJECT = this;
var foo = 1;
GLOBAL_OBJECT.foo; // 1
function bar() {};
typeof GLOBAL_OBJECT.bar; // "function"
GLOBAL_OBJECT.bar === bar; // true
var GLOBAL_OBJECT = this;
/* 通过变量声明生成全局对象的属性,拥有DontDelete */
var foo = 1;
/* 通过未声明的变量赋值生成全局对象的属性,没有DontDelete */
bar = 2;
delete foo; // false
delete bar; // true
//注意:内部属性是在属性生成时确定的,之后的赋值过程不会改变已有的属性的内部属性。 理解这一区别是重要的。
/* 'foo'创建的同时生成DontDelete */
function foo() {};
/* 之后的赋值过程不改变已有属性的内部属性,DontDelete仍然存在 */
foo = 1;
delete foo; // false;
typeof foo; // "number"
/* 但赋值一个不存在的属性时,创建了一个没有内部属性的属性,因此没有DontDelete */
this.bar = 1;
delete bar; // true;
typeof bar; // "undefined"
属性的一个特殊的内部属性控制着该属性是否可以被删除。 注意:内建对象的一些属性拥有内部属性 DontDelete,因此不能被删除; 特殊的
arguments 变量(如我们所知的,活化对象的属性)拥有 DontDelete; 任何函数实例的 length
(返回形参长度)属性也拥有 DontDelete:
(function() {
//不能删除'arguments',因为有DontDelete
delete arguments; // false;
typeof arguments; // "object"
//也不能删除函数的length,因为有DontDelete
function f() {};
delete f.length; // false;
typeof f.length; // "number"
}) ();
这就是为什么delete删除不了arguments啦。
第四题
var y = 1, x = y = typeof x;
x;
结果:”undefined”
把上面的代码重写一下就是
var y=1;
y=typeof x;//x未定义 y是undefined
x=y
x
第五题
(function f(f){
return typeof f();
})(function(){ return 1; });
结果:”number”
代码重写一下:
var a=function(){ return 1; }
(function f(f){
//a()返回1,即 return typeof 1;
return typeof a();
})(a);
注意:()里的函数都看作函数表达式而不是函数声明哦
第六题
var foo = {
bar: function() { return this.baz; },
baz: 1
};
(function(){
return typeof arguments[0]();
})(foo.bar);
结果:”undefined”
让我们重写一下:
(function(){
return typeof arguments[0]();
})(function() { return this.baz; });
再重写一下:
var a=function() { return this.baz; }
(function(){
return typeof arguments[0]();
})(a);
再写一下
return typeof a();
a函数里return this.baz;的this是谁?
我们知道是arguments调用的a函数,上文我们也知道arguments在函数内部,作为函数内部一个变量的属性,那么是arguments调用了a,arguments没有属性baz,所以返回undefined。
那我测一下是不是真的是arguments喽
var foo = {
bar: function ss() { return this;},
baz: 1
};
var a=function s(){
console.log(arguments);
console.log(arguments[0]()) ;
}
a(foo.bar);
结果:
哈哈 console.log(arguments);console.log(arguments0) ;两只结果一模一样。