zoukankan      html  css  js  c++  java
  • Js 编程题汇总

    Coding题: 1. 预测以下代码的输出结果:
    var Foo = function(a) {  
      function bar() {   
        console.log(a); 
      };
      this.baz = function() {
          console.log(a);
      };
    };
    
    Foo.prototype = {  
      biz: function() {    
        console.log(a); 
      }
    };
    
    var f = new Foo(7); 
    //预测输出结果:
    f.bar(); // result: TypeError, f.bar is not a function.  
    f.baz(); // result: 7  
    f.biz(); // result: ReferenceError, a is not defined

    2、

    // 函数声明语句
    {
      let a = 'secret';
      function f() {
        return a;
      }
    }
    
    // 函数表达式
    {
      let a = 'secret';
      let f = function () {
        return a;
      };
    }

     

    3、闭包

      https://www.cnblogs.com/lulin1/p/7324435.html

    var x = 10;
    function foo() {
      alert(x);
    }
    (function (funArg) {
    var x = 20;  // 变量"x"在foo中静态保存的,在该函数创建的时候就保存了  如果是x=20输出20
      funArg(); // 10, 而不是20
    })(foo);

     

    4、闭包

    var firstClosure;
    var secondClosure;
    
    function foo() {
    
      var x = 1;
    
      firstClosure = function () { return ++x; };
      secondClosure = function () { return --x; };
    
      x = 20; // 影响"x", 在2个闭包公有的[[Scope]]中
    
      alert(firstClosure()); // 21, 通过第一个闭包的[[Scope]]
    }
    
    foo();
    
    alert(firstClosure()); // 22
    alert(secondClosure()); // 21

     

    5、ES6函数作用域

    var x = 1;
    function foo(x, y = function() { x = 2; }) {
      var x = 3;
      y();
      console.log(x);
    }
    
    foo() // 3
    x // 1
    var x = 1;
    function foo(x, y = function() { x = 2; }) {
      x = 3;
      y();
      console.log(x);
    }
    
    foo() // 2
    x // 1

       

      上面代码中,函数foo的参数形成一个单独作用域。这个作用域里面,首先声明了变量x,然后声明了变量yy的默认值是一个匿名函数。这个匿名函数内部的变量x,指向同一个作用域的第一个参数x。函数foo内部又声明了一个内部变量x,该变量与第一个参数x由于不是同一个作用域,所以不是同一个变量,因此执行y后,内部变量x和外部全局变量x的值都没变。

      如果将var x = 3var去除,函数foo的内部变量x就指向第一个参数x,与匿名函数内部的x是一致的,所以最后输出的就是2,而外层的全局变量x依然不受影响。

    function foo() {
    	console.log(this.a)
    }
    var a = 1
    foo()
    
    var obj = {
    	a: 2,
    	foo: foo
    }
    obj.foo()
    

      比较没有 this 的情况:

    function foo() {
        console.log(a)
    }
    var a = 1
    foo()
     
    var obj = {
        a: 2,
        foo: foo
    }
    obj.foo()
    

      

    6、ES6箭头函数

    function foo() {
      console.log('id:', this.id);
    }
    
    var id = 21;
    
    foo.call({ id: 42 }); // id : 42

     

    var foo = () => {
      console.log('id:', this.id);
    }
    
    var id = 21;
    
    foo.call({ id: 42 });  // id: 21

     

    function foo() {
      setTimeout(function() {
        console.log('id:', this.id);
      }, 100);
    }
    
    var id = 21;
    
    foo.call({ id: 42 });  // id : 21

     

    function foo() {
      setTimeout(() => {
        console.log('id:', this.id);
      }, 100);
    }
    
    var id = 21;
    
    foo.call({ id: 42 });  // id : 42   箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id: 42}),所以输出的是42

     

    7、ES6箭头函数 

    function Timer() {
      this.s1 = 0;
      this.s2 = 0;
      // 箭头函数
      setInterval(() => this.s1++, 1000);
      // 普通函数
      setInterval(function () {
        this.s2++;
      }, 1000);
    }
    
    var timer = new Timer();
    
    setTimeout(() => console.log('s1: ', timer.s1), 3100);
    setTimeout(() => console.log('s2: ', timer.s2), 3100);
    // s1: 3
    // s2: 0

      上面代码中,Timer函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)。所以,3100 毫秒之后,timer.s1被更新了 3 次,而timer.s2一次都没更新。

     

    8、ES6箭头函数

      请问下面的代码之中有几个this

    function foo() {
      return () => {
        return () => {
          return () => {
            console.log('id:', this.id);
          };
        };
      };
    }
    
    var f = foo.call({id: 1});
    
    var t1 = f.call({id: 2})()(); // id: 1
    var t2 = f().call({id: 3})(); // id: 1
    var t3 = f()().call({id: 4}); // id: 1

      上面代码之中,只有一个this,就是函数foothis,所以t1t2t3都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this

     

    9、即时函数执行过程

    var result = (function(){
        return 1;
    },function(){
        return "2"
    },function(){
        return "3"
    })()
    
    console.log(typeof result)   // string
    console.log( result)    // 3

      从右向左执行,并只执行一次就结束。 

    10、执行上下文

      我们先看个简单的例子:

    var t = function() {
        var n = 99;
        var t2 = function() {
        	n++
        	console.log(n)
        }
        return t2;
    };
    
    var a1 = t();
    var a2 = t();
    
    a1(); // 100
    a1(); // 101
    
    a2(); // 100
    a2(); // 101
    

      

      我们会发现,n 的值都是从 99 开始,执行 一次a1() 的时候,值会加一,再执行一次,值再加一,但是 n 在 a1() 和 a2() 并不是公用的。你可以理解为:同一个函数形成的多个闭包的值都是相互独立的。

      接下来看这道题目,关键在于 nAdd 函数。

    var nAdd;
    var t = function() {
        var n = 99;
        nAdd = function() {
        	 n++;
        }
        var t2 = function() {
        	console.log(n)
        }
        return t2;
    };
    
    var a1 = t();
    var a2 = t();
    
    nAdd();
    
    a1(); //99
    a2(); //100
    

      当执行 var a1 = t()的时候,变量 nAdd 被赋值为一个函数 ,这个函数是function (){n++},我们命名这个匿名函数为 fn1 吧。接着执行 var a = t()的时候,变量 nAdd 又被重写了,这个函数跟以前的函数长得一模一样,也是function (){n++},但是这已经是一个新的函数了,我们就命名为 fn2 吧。

      所以当执行 nAdd 函数,我们执行的是其实是 fn2,而不是 fn1,我们更改的是 a2 形成的闭包里的 n 的值,并没有更改 a1 形成的闭包里的 n 的值。所以 a1() 的结果为 99 ,a2()的结果为 100。

     11、执行上下文+闭包 

    A:

    var scope = "global scope";
    function checkscope(){
        var scope = "local scope";
        function f(){
            return scope;
        }
        return f();
    }
    checkscope(); // local scope
    

    B:

    var scope = "global scope";
    function checkscope(){
        var scope = "local scope";
        function f(){
            return scope;
        }
        return f;
    }
    checkscope()(); // local scope
    

      两段代码都会打印'local scope'。虽然两段代码执行的结果一样,但是两段代码究竟有哪些不同呢?

      如果你理解了A的执行流程,那么B的流程在细节上一致,唯一的区别在于B的环境栈变化不一样,

        A: contextStack = [globalContext] ---> contextStack = [checkscopeContext, globalContext] ---> contextStack = [fContext, checkscopeContext, globalContext] ---> contextStack = [checkscopeContext, globalContext] ---> contextStack = [globalContext]

        B: contextStack = [globalContext] ---> contextStack = [checkscopeContext, globalContext] ---> contextStack = [fContext, globalContext] ---> contextStack = [globalContext]

      也就是说,真要说这两段代码有啥不同,那就是他们执行过程中环境栈的变化不一样,其他的两种方式都一样。

      其实对于理解这两段代码而言最根本的一点在于,javascript是使用静态作用域的语言,他的作用域在函数创建的时候便已经确定(不含arguments)。

    12、闭包

      刷题必刷,面试必考的闭包题:

    var data = [];
    
    for (var i = 0; i < 3; i++) {
      data[i] = function () {
        console.log(i);
      };
    }
    
    data[0](); //3
    data[1](); //3
    data[2](); //3
    

     

      让我们改成闭包看看:

    var data = [];
    
    for (var i = 0; i < 3; i++) {
      data[i] = (function (i) {
            return function(){
                console.log(i);
            }
      })(i);
    }
    
    data[0](); //0
    data[1](); //1
    data[2](); //2
    

      使用let定义后:

     

    var data = [];
    
    for (let i = 0; i < 3; i++) {
      data[i] = function () {
        console.log(i);
      };
    }
    
    data[0](); //0
    data[1](); //1
    data[2](); //2
    

     参考:

    13、参数传递(按值传递 || 共享传递)  

      (1)按值传递

    var value = 1;
    function foo(v) {
        v = 2;
        console.log(v); //2
    }
    foo(value);
    console.log(value) // 1
    

      (2)共享传递

    var obj = {
        value: 1
    };
    function foo(o) {
        o.value = 2;
        console.log(o.value); //2
    }
    foo(obj);
    console.log(obj.value) // 2
    

      

    var obj = {
        value: 1
    };
    function foo(o) {
        o = 2;
        console.log(o); //2
    }
    foo(obj);
    console.log(obj.value) // 1
    

      共享传递是指,在传递对象的时候,传递对象的引用的副本。

      所以修改 o.value,可以通过引用找到原值,但是直接修改 o,并不会修改原值。所以这两个例子其实都是按共享传递。

    14、变量对象(VO)

    (1)

    function foo() {
        console.log(a);
        a = 1;
    }
    
    foo(); // ???
    
    function bar() {
        a = 1;
        console.log(a);
    }
    bar(); // ???  

      第一段会报错:Uncaught ReferenceError: a is not defined

      第二段会打印:1

      这是因为函数中的 "a" 并没有通过 var 关键字声明,所有不会被存放在 AO 中。

      第一段执行 console 的时候, AO 的值是:

    AO = {
        arguments: {
            length: 0
        }
    }

      没有 a 的值,然后就会到全局去找,全局也没有,所以会报错。

      当第二段执行 console 的时候,全局对象已经被赋予了 a 属性,这时候就可以从全局找到 a 的值,所以会打印 1。

    (2)

    console.log(foo);
    
    function foo(){
        console.log("foo");
    }
    
    var foo = 1;
    

      会打印函数,而不是 undefined 。

      这是因为在进入执行上下文时,首先会处理函数声明,其次会处理变量声明,如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。

     

     

  • 相关阅读:
    Typora的使用
    selenium中webdriver提供的八大定位元素方法
    JAVA的Data和Timestamp的相互转换
    Jmeter设置参数作为断言依据
    Springboot +Poi 导入Excel表格
    window.location.reload();
    带参数的链接跳转
    Layui结束时间不能小于开始时间
    后台返回数据渲染Layui表格
    Layui中layedit模板的使用
  • 原文地址:https://www.cnblogs.com/lulin1/p/7381889.html
Copyright © 2011-2022 走看看