1.var a=function a(){
a=1;
return a;
}
console.log(a())//返回function a(){a=1;return a;}
稍微看了一下资料,这种函数表达式和函数声明同时存在的时候,这个函数a是immutable型的,即不可改变的。故设置a=1无效;有兴趣可以试试只用一种方式定义函数,我试了,结果都是返回1
2.function a(){}()报错,unexpected token'(' 大概是这种错误
这里会把function a(){}当作函数声明来对待,转化就成了
function a(){};
();
这种语法是不合js规范的,空括号就报错了
3.function a(){}(1,2)
同上面一样,这时候就会解析成
function a(){};
(1,2);其中(1,2)是函数表达式,又是运用了“,”运算符,返回最后一个逗号后面的,即返回2了
4.var num=1;
if(function f(){}){
num+=typeof f;
}
console.log(num)//1undefined
其中function f(){}是函数声明,但是(function f(){})是表达式了,function f(){}是个对象,对象转化就为true,
所以会走到num+=typeof f;其中因为函数f是以表达式的形式,故下面f访问不到,typeof f==='undefined';
最后就是1+‘undefined’=1undefined;
5.
'use strict';
var a = 20;
function foo () {
var a = 1;
var obj = {
a: 10,
c: this.a + 20,
fn: function () {
return this.a;
}
}
return obj.c;
}
console.log(foo()); // ?
console.log(window.foo()); // ?
猜猜这段代码输出什么?
解析:这个题目很容易犯错,知识点:{}不产生新的作用域,它里面的this是指向全局的,严格模式下为undefined,非严格模式为window。再来看这个题目,就会发现,foo()执行完返回this.a+20,其中obj.c不产生新的作用域,这里的this还是全局的,又是use strict模式下,故就是undefined.a+20,所以程序报错退出。如果注释第一个输出,第二个输出40,这个很好理解就不解释了。
此文章纯属原创,后续会继续更新。有问题欢迎指出,谢谢大家!!!
6.一道比较经典的连等赋值题
var a={c:1};
var b=a;
a.x=a={c:2};
console.log(a);
console.log(b);
注:连等赋值从右往左计算;
解析:js的基础类型变量和值会保存到变量对象中,引用类型的值会放入堆中,在变量对象中保存着对堆中值的内存地址。
第一行和第二行为指的是a,b都指向堆中中的{c:1}对象,第三行a.x是为a添加属性,这时候的a还是{c:1};根据从右往左计算,
首先知道堆中创建了一个新的对象为{c:2};并且将a的引用指向了它,故此时a就为{c:2},得到第一个输出;而a.x的a还是保持着{c:1}的引用(为什么呢?因为点运算符运算等级比=高,所以先给a.x赋值为undefined,这时的a还是{c:1}),a.x=a就将原来a的引用变成了{c:1,x:a},其中现在的a指向了{c:2},故原来a的引用(即b的指向)就变成了{c:1,x:{x:2}},这样就得到了第二个输出。
7.
var a={},
b={key:'b'},
c={key:'c'};
a[b]=123;
a[c]=456;
console.log(a[b]);
这段代码将输出 456
(而不是 123
)。
原因为:当设置对象属性时,JavaScript会暗中字符串化参数值。在这种情况下,由于 b
和 c
都是对象,因此它们都将被转换为"[object Object]"
。结果就是, a[b]
和a[c]
均相当于a["[object Object]"]
,并可以互换使用。因此,设置或引用 a[c]
和设置或引用 a[b]
完全相同。
8.
function Foo() { getName = function () { alert (1); }; return this; } Foo.getName = function () { alert (2);}; Foo.prototype.getName = function () { alert (3);}; var getName = function () { alert (4);}; function getName() { alert (5);} //请写出以下输出结果: Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName();
new new Foo().getName();
//答案: Foo.getName();//2 getName();//4 Foo().getName();//1 getName();//1 new Foo.getName();//2 new Foo().getName();//3 new new Foo().getName();//3分析:1.Foo.getName()这个不用说,直接就是第五行,返回2
2.getName()这个就看最后两行,一个函数声明,一个函数表达式,函数声明提前,表达式覆盖声明,故输出4,也没问题
3.Foo().getName()这里Foo()返回this,没有实例化,这个this指window,然后再调用getName();就是前面刚被赋值的getName(),故返回1
4.getName()在调用Foo().getName()时做了覆盖,毕竟Foo函数内定义的全局getName,故还是输出1
5.new Foo.getName();首先提一下:点操作符优先于new操作符;故Foo.getName()跟第一个一样,再经过new实例化,返回2
6.new Foo().getName() 这里注意括号优先级比new和点都高,故实际执行为(new Foo()).getName(),因为构造函数上没有getName方法,就去原型上找,所有输出3
7.new new Foo().getName()同上,实际执行为new (new Foo()).getName(),因为new Foo()返回this,故new Foo()还是指向Foo,这时候返回的对象接getName()还是去Foo的原型对象上去查找,还是3