持续更新一些有趣的js题

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

猜你喜欢

转载自blog.csdn.net/THINK_OF_/article/details/79523874