• javascript疑难习题


    题目1

    var length = 10;
    function fn(){
        console.log(this.length);
    };
    var obj = {
        length: 5,
        method: function(fn) {
            fn(); // ?
            arguments[0](); // ?
        }
    };
    obj.method(fn);

      考察this,这里的坑主要是arguments,我们知道取对象属于除了点操作符还可以用中括号,这里fn的作用域(scope)是arguments,即fn内的this===arguments,调用时仅传了一个参数fn,因此length为1。

    题目2

    2,函数表达式具名(函数声明同时赋值给另一个变量)或函数声明立即执行时,名仅在该函数内可访问

    ~function() {
        alert(typeof next) // ?
        ~function next() {
            alert(typeof next) // ?
        }()
    }()

    外层匿名函数自执行,打印next,接着内层具名函数自执行。会发现具名的next仅在其自身函数体内可访问,即输出为function。外面是不可见的,typeof就为undefined了。(注:此题IE6/7/8中输出为function function, 标准浏览器为undefined function

    同样的情况也发生在将具名函数赋值给一个变量时,如下

    var func = function a() {
        alert(typeof a)
    }
    func() // ?
    alert(typeof a) // ?

    题目3

    3,给基本类型数据添加属性,不报错,但取值时是undefined

    a = 3
    a.prop = 4
    alert(a + a.prop) // ?

    变量a为数字3,给其添加prop属性,值为4(奇怪吧在JS中这是允许的,且不会有语法错误)。然后alert出a+a.prop的结果。结果是NaN。a.prop为undefined,3+undefined为NAN。

    举一反三,给字符串添加属性

    str = 'a'
    str.prop = 'b'
    alert(str + str.prop) // ?

    结果呢?

    题目4

    4,隐式的全局变量

    var a = 1
    function func() {
        a = b = 2
    }
    func()
    alert(a)
    alert(b) // ?

    JS中不用var声明的变量默认是全局变量,而这里的连等使的情况更加隐蔽。这里的b是全局的,因此func外可以访问。

    题目5

    5,变量声明早于代码运行(Scoping and Hoisting

    var uname = 'jack'
    function change() {
        alert(uname) // ?
        var uname = 'lily'
        alert(uname)
    }
    change()

    这里容易犯迷糊的是第一个alert,如果认为函数change外已经声明赋值了,此时应该是jack,实际函数内又var了一次(虽然var在其后),预解析时仍然会将其置undefined。这也是为什么书里都建议变量声明都放在代码块的最前面。

    题目6

    6,函数声明早于变量声明

    function change() {
        alert(typeof fn) // ?
        function fn() {
            alert('hello')
        }
        var fn
    }
    change()

    change内先alert出fn,后函数声明,再变量声明。如果fn没有函数声明而仅是变量声明,那么结果与5一样是undefined。但这里 却是function。即同一个作用域内,函数声明放在代码块后面和前面都没有关系,函数可以正常使用。而变量声明则需先置前,先使用则是 undefined。

    【以上转自】:坑爹的JS笔试题(持续更新)

    【以下转自】:深入理解JavaScript系列(20):《你真懂JavaScript吗?》答案详解

    题目1

    if (!("a" in window)) {
    var a = 1;
    }
    alert(a);

    代码看起来是想说:如果window不包含属性a,就声明一个变量a,然后赋值为1。

    你可能认为alert出来的结果是1,然后实际结果是“undefined”。要了解为什么,我们需要知道JavaScript里的3个概念。

    首先,所有的全局变量都是window的属性,语句 var a = 1;等价于window.a = 1; 你可以用如下方式来检测全局变量是否声明:

    "变量名称" in window

    第二,所有的变量声明都在范围作用域的顶部,看一下相似的例子:

    alert("a" in window);
    var a;

    此时,尽管声明是在alert之后,alert弹出的依然是true,这是因为JavaScript引擎首先会扫墓所有的变量声明,然后将这些变量声明移动到顶部,最终的代码效果是这样的:

    var a;
    alert("a" in window);

    这样看起来就很容易解释为什么alert结果是true了。

    第三,你需要理解该题目的意思是,变量声明被提前了,但变量赋值没有,因为这行代码包括了变量声明和变量赋值。

    你可以将语句拆分为如下代码:

    var a;    //声明
    a = 1; //初始化赋值

    当变量声明和赋值在一起用的时候,JavaScript引擎会自动将它分为两部以便将变量声明提前,不将赋值的步骤提前是因为他有可能影响代码执行出不可预期的结果。

    所以,知道了这些概念以后,重新回头看一下题目的代码,其实就等价于:

    var a;
    if (!("a" in window)) {
    a = 1;
    }
    alert(a);

    这样,题目的意思就非常清楚了:首先声明a,然后判断a是否在存在,如果不存在就赋值为1,很明显a永远在window里存在,这个赋值语句永远不会执行,所以结果是undefined。

    大叔注:提前这个词语显得有点迷惑了,其实就是执行上下文的关系,因为执行上下文分2个阶段:进入执行上下文和执行代码,在进入执行上下文的时候,创建变量对象VO里已经有了:函数的所有形参、所有的函数声明、所有的变量声明

    VO(global) = {
    a: undefined
    }

    这个时候a已经有了;

    然后执行代码的时候才开始走if语句,详细信息请查看《深入理解JavaScript系列(12):变量对象(Variable Object)》中的处理上下文代码的2个阶段小节。

    大叔注:相信很多人都是认为a在里面不可访问,结果才是undefined的吧,其实是已经有了,只不过初始值是undefined,而不是不可访问。

    题目2

    var a = 1,
    b = function a(x) {
    x && a(--x);
    };
    alert(a);

    这个题目看起来比实际复杂,alert的结果是1;这里依然有3个重要的概念需要我们知道。

    首先,在题目1里我们知道了变量声明在进入执行上下文就完成了;第二个概念就是函数声明也是提前的,所有的函数声明都在执行代码之前都已经完成了声明,和变

    量声明一样。澄清一下,函数声明是如下这样的代码:

    function functionName(arg1, arg2){
    //函数体
    }

    如下不是函数,而是函数表达式,相当于变量赋值:

    var functionName = function(arg1, arg2){
    //函数体
    };

    澄清一下,函数表达式没有提前,就相当于平时的变量赋值。

    第三需要知道的是,函数声明会覆盖变量声明,但不会覆盖变量赋值,为了解释这个,我们来看一个例子:

    function value(){
    return 1;
    }
    var value;
    alert(typeof value); //"function"

    尽快变量声明在下面定义,但是变量value依然是function,也就是说这种情况下,函数声明的优先级高于变量声明的优先级,但如果该变量value赋值了,那结果就完全不一样了:

    function value(){
    return 1;
    }
    var value = 1;
    alert(typeof value); //"number"

    该value赋值以后,变量赋值初始化就覆盖了函数声明。

    重新回到题目,这个函数其实是一个有名函数表达式,函数表达式不像函数声明一样可以覆盖变量声明,但你可以注意到,变量b是包含了该函数表达式,而 该函数表达式的名字是a;不同的浏览器对a这个名词处理有点不一样,在IE里,会将a认为函数声明,所以它被变量初始化覆盖了,就是说如果调用 a(--x)的话就会出错,而其它浏览器在允许在函数内部调用a(--x),因为这时候a在函数外面依然是数字。基本上,IE里调用b(2)的时候会出 错,但其它浏览器则返回undefined。

    理解上述内容之后,该题目换成一个更准确和更容易理解的代码应该像这样:

    var a = 1,
    b = function(x) {
    x && b(--x);
    };
    alert(a);

    这样的话,就很清晰地知道为什么alert的总是1了,详细内容请参考《深入理解JavaScript系列(2):揭秘命名函数表达式》中的内容。

    大叔注:安装ECMAScript规范,作者对函数声明覆盖变量声明的解释其实不准确的,正确的理解应该是如下:

    进入执行上下文: 这里出现了名字一样的情况,一个是函数申明,一个是变量申明。那么,根据深入理解JavaScript系列(12):变量对象(Variable Object)介绍的,填充VO的顺序是: 函数的形参 -> 函数申明 -> 变量申明。
    上述例子中,变量a在函数a后面,那么,变量a遇到函数a怎么办呢?还是根据变量对象中介绍的,当变量申明遇到VO中已经有同名的时候,不会影响已经存在的属性。而函数表达式不会影响VO的内容,所以b只有在执行的时候才会触发里面的内容。

    题目3

    function a(x) {
    return x * 2;
    }
    var a;
    alert(a);

    这个题目就是题目2里的大叔加的注释了,也就是函数声明和变量声明的关系和影响,遇到同名的函数声明,VO不会重新定义,所以这时候全局的VO应该是如下这样的:

    VO(global) = {
    a: 引用了函数声明“a”
    }

    而执行a的时候,相应地就弹出了函数a的内容了。

    题目4

    function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
    }
    b(1, 2, 3);

    关于这个题目,NC搬出了262-3的规范出来解释,其实从《深入理解JavaScript系列(12):变量对象(Variable Object)》中的函数上下文中的变量对象一节就可以清楚地知道,活动对象是在进入函数上下文时刻被创建的,它通过函数的arguments属性初始化。arguments属性的值是Arguments对象:

    AO = {
    arguments: <ArgO>
    };

    Arguments对象是活动对象的一个属性,它包括如下属性:

    1. callee — 指向当前函数的引用
    2. length — 真正传递的参数个数
    3. properties-indexes (字符串类型的整数) 属性的值就是函数的参数值(按参数列表从左到右排列)。 properties-indexes内部元素的个数等于arguments.length. properties-indexes 的值和实际传递进来的参数之间是共享的。

    这个共享其实不是真正的共享一个内存地址,而是2个不同的内存地址,使用JavaScript引擎来保证2个值是随时一样的,当然这也有一个前提, 那就是这个索引值要小于你传入的参数个数,也就是说如果你只传入2个参数,而还继续使用arguments[2]赋值的话,就会不一致,例如:

    function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
    }
    b(1, 2);

    这时候因为没传递第三个参数a,所以赋值10以后,alert(a)的结果依然是undefined,而不是10,但如下代码弹出的结果依然是10,因为和a没有关系。

    function b(x, y, a) {
    arguments[2] = 10;
    alert(arguments[2]);
    }
    b(1, 2);

    题目5

    function a() {
    alert(this);
    }
    a.call(null);

    这个题目可以说是最简单的,也是最诡异的,因为如果没学到它的定义的话,打死也不会知道结果的,关于这个题目,我们先来了解2个概念。

    首先,就是this值是如何定义的,当一个方法在对象上调用的时候,this就指向到了该对象上,例如:

    var object = {
    method: function() {
    alert(this === object); //true
    }
    }
    object.method();

    上面的代码,调用method()的时候this被指向到调用它的object对象上,但在全局作用域里,this是等价于window(浏览器 中,非浏览器里等价于global),在如果一个function的定义不是属于一个对象属性的时候(也就是单独定义的函数),函数内部的this也是等 价于window的,例如:

    function method() {
    alert(this === window); //true
    }
    method();

    了解了上述概念之后,我们再来了解一下call()是做什么的,call方法作为一个function执行代表该方法可以让另外一个对象作为调用者来调用,call方法的第一个参数是对象调用者,随后的其它参数是要传给调用method的参数(如果声明了的话),例如:

    function method() {
    alert(this === window);
    }
    method(); //true
    method.call(document); //false

    第一个依然是true没什么好说的,第二个传入的调用对象是document,自然不会等于window,所以弹出了false。

    另外,根据ECMAScript262规范规定:如果第一个参数传入的对象调用者是null或者undefined的话,call方法将把全局对象 (也就是window)作为this的值。所以,不管你什么时候传入null,其this都是全局对象window,所以该题目可以理解成如下代码:

    function a() {
    alert(this);
    }
    a.call(window);

    所以弹出的结果是[object Window]就很容易理解了。

  • 相关阅读:
    R语言实现CNN(卷积神经网络)模型进行回归数据分析
    R语言中的多项式回归、B样条曲线(B-spline Curves)回归
    R语言方差分析(ANOVA)学生参加辅导课考试成绩差异
    R语言人口期望寿命统计预测方法
    R语言用多项式回归和ARIMA模型预测电力负荷时间序列数据
    R语言主题模型LDA评估公司面临的风险领域与可视化
    Matlab通过市场数据校准Hull-White利率模型参数
    R语言用逻辑回归、决策树和随机森林对信贷数据集进行分类预测
    Matlab通过市场数据校准Hull-White利率模型参数
    R语言动量和马科维茨Markowitz投资组合(Portfolio)模型实现
  • 原文地址:https://www.cnblogs.com/colorstory/p/2707190.html
Copyright © 2020-2023  润新知