美文网首页
关于js声明提升和作用域链

关于js声明提升和作用域链

作者: Llane00 | 来源:发表于2017-03-21 10:21 被阅读0次

    一句话:函数的作用域,与声明时有关,与调用时无关。

    1. 函数声明和函数表达式有什么区别

    函数声明,使用function关键字可以声明一个函数,声明不必放到调用的前面。
    函数表达式,声明必须放到调用的前面

    2. 什么是变量的声明前置?什么是函数的声明前置

    在一个作用域下,var 声明的变量和function 声明的函数会前置。
    变量的声明前置,var声明的变量按顺序提升到js最前,赋值为undefined
    函数的声明前置,function声明的函数和变量一样前置,且都按照顺序提升。

    3. arguments 是什么

    argument是类数组对象,每个函数中都存在argument对象,argument并不是一个真正的数组,所以不具备除length属性之外的属性,这个对象维护着所有传入该函数的参数列表,通过arguments[1、2、3]等...可以获取到相应的传入参数。

    4. 函数的"重载"怎样实现

    在 JS 中没有重载, 同名函数会覆盖。 但可以在函数体针对不同的参数调用执行相应的逻辑。
    例子:

    function fn(a, b, c){
      if( a !== void 0){  //若a不为undefined,就输出a
        console.log(a);
      }
      if( b !== void 0){  //若b不为undefined,就输出b
        console.log(b);
      }
      if( c !== void 0){  //若c不为undefined,就输出c
        console.log(c);
      }
    }
    

    5. 立即执行函数表达式是什么?有什么作用

    立即执行函数表达式,首先它是一个表达式,而不是一个声明函数。其次,因为是表达式,所以可以用(), +, !, -等运算符来触发。
    例如:(function(){…})()
    函数会立即执行,并且可以隔离作用域,立即执行函数内的任何赋值都不会影响这个函数外的变量和函数。

    6. 求n!,用递归来实现

    function factorial(n){
      if( n === 1 ){
        return 1;
      }
      return n * factorial(n-1);
    }
    

    7. 以下代码输出什么?

    function getInfo(name, age, sex){
      console.log('name:',name);
      console.log('age:', age);
      console.log('sex:', sex);
      console.log(arguments);
      arguments[0] = 'valley';
      console.log('name', name);
    }
    
    getInfo('Llane', 2, '男'); 
    //name: Llane
    //age: 2
    //sex: 男
    //["Llane",2,"男"]
    //name valley
    
    getInfo('小L', 3); 
    //name: 小L
    //age: 3
    //sex: undefined
    //["小L",3]
    //name valley
    
    getInfo('男'); 
    //name: 男
    //age: undefined
    //sex: undefined
    //["男"]
    //name valley
    

    8.写一个函数,返回参数的平方和?

    function sumOfSquares(){
      var sum = 0
      for(var i =0; i < arguments.length; i++){
        sum += arguments[i] * arguments[i];
      }
      return sum
    }
    var result = sumOfSquares(2,3,4)
    var result2 = sumOfSquares(1,3)
    console.log(result)  //29
    console.log(result2)  //10
    

    9.如下代码的输出?为什么

    console.log(a);
    var a = 1;
    console.log(b);
    

    变量提升后代码为:

    var a;
    console.log(a); //a此时还没赋值,所以输出 undefined
    a = 1;
    console.log(b); //变量b没有声明过,所以会报错 Uncaught ReferenceError: b is not defined
    

    10.如下代码的输出?为什么

    sayName('world');
    sayAge(10);
    function sayName(name){
      console.log('hello ', name);
    }
    var sayAge = function(age){
      console.log(age);
    };
    

    变量提升后代码为:

    function sayName(name){
      console.log('hello ', name);
    }
    var sayAge;
    
    sayName('world');
    sayAge(10); //函数表达式,声明必须在调用前
    
    sayAge = function(age){
      console.log(age);
    };
    
    // 输出:
    // hello world
    // Uncaught TypeError: sayAge is not a function
    

    11.如下代码输出什么? 写出作用域链查找过程伪代码

    var x = 10
    bar() 
    function foo() {
      console.log(x)
    }
    function bar(){
      var x = 30
      foo()
    }
    
    //声明提升后为
    var x
    function foo() {
      console.log(x)
    }
    function bar(){
      var x
      x = 30
      foo()
    }
    x = 10
    bar() 
    

    作用链伪代码:

    globalContext = {
      AO: {
        x:10
        foo:function
        bar:function
      }
      scope:null
    }
    foo.[[scope]] = globalContext.AO
    bar.[[scope]] = globalContext.AO
    
    barContext = {
      AO:{
        x:30
      }
      scope:globalContext.AO
    }
    
    fooContext = {
      AO:{}
      scope:globalContext.AO
    }
    

    bar()开始执行,声明局部变量x=30,
    foo()开始执行,执行console.log(x),发现fooContext中没有x,
    到scope:globalContext.AO中找x
    发现:globalContext.AO中x为10
    所以输出10

    12.如下代码输出什么? 写出作用域链查找过程伪代码

    var x = 10;
    bar() 
    function bar(){
      var x = 30;
      function foo(){
        console.log(x) 
      }
      foo();
    }
    
    //声明提升后为
    var x;
    function bar(){
      var x
      function foo(){
        console.log(x) 
      }
      x = 30;
      foo();
    }
    x = 10
    bar() 
    

    作用域伪代码为:

    globalContext = {
      AO:{
        x:10
        bar:function
      }
      scope: null
    }
    bar.[[scope]] = globalContext.AO
    
    barContext = {
      AO:{
        x: 30
        foo:function
      }
      scope:globalContext.AO
    }
    foo.[[scope]] = barContext.AO
    
    fooContext = {
      AO:{}
      scope:barContext.AO
    }
    
    

    bar()执行,声明局部变量x=30
    foo()执行,发现fooContext.AO中没有x
    根据scope:barContext.AO去找
    发现scope:barContext.AO中x为30
    所以输出30

    13.以下代码输出什么? 写出作用域链的查找过程伪代码

    var x = 10;
    bar() 
    function bar(){
      var x = 30;
      (function (){
        console.log(x)
      })()
    }
    
    //声明提升后
    var x;
    function bar(){
      var x
      x = 30;
      (function (){
        console.log(x)
      })()
    }
    x = 10;
    bar() 
    

    作用域链伪代码:

    globalContext = {
      AO:{
        x:10
        bar:function
      }
      scope:null
    }
    bar.[[scope]] = globalContext.AO
    
    barContext = {
      AO:{
        x:30
        (anomyous):function
      }
      scope:globalContext.AO
    }
    (anomyous).[[scope]] = barContext.AO
    
    (anomyous)Context = {
      AO:{}
      scope:barContext.AO
    }
    

    bar()执行声明局部变量x = 30
    执行立即执行函数,立即执行函数中没有x
    所以去他的scope:barContext中找,发现x=30
    所以输出30

    14.以下代码输出什么? 写出作用域链查找过程伪代码

    var a = 1;
    
    function fn(){
      console.log(a)
      var a = 5
      console.log(a)
      a++
      var a
      fn3()
      fn2()
      console.log(a)
    
      function fn2(){
        console.log(a)
        a = 20
      }
    }
    
    function fn3(){
      console.log(a)
      a = 200
    }
    
    fn()
    console.log(a)
    
    //声明提升
    
    var a
    
    function fn(){
      var a 
      function fn2(){
        console.log(a)
        a = 20
      }
      console.log(a)
      a = 5
      console.log(a)
      a++
      fn3()
      fn2()
      console.log(a)
    }
    
    function fn3(){
      console.log(a)
      a = 200
    }
    
    a = 1;
    fn()
    console.log(a)
    
    

    作用域伪代码:

    globalContext = {
      AO:{
        a:1 => 200
        fn:function
        fn3:function
      }
    }
    fn.[[scope]] = globalContext
    fn3.[[scope]] = globalContext
    
    fnContext = {
      AO:{
        a:undefined => 5 => 6 => 20
        fn2:function
      }
      scope:globalContext
    }
    fn2.[[scope]] = fnContext
    
    fn3Context = {
      AO:{}
      scope:globalContext
    }
    
    

    fn()开始执行
    //输出 undefined 5 1 6 20 200

    ps:13题的伪代码中匿名函数的AO写法有待商榷。

    补充:

    1.如果是带参数的函数

    例如:

    function exampleFn(a){
      console.log(a);
    }
    example(10);
    
    //相当于
    
    function exampleFn(a){
       var a = 10;
      console.log(a);
    }
    

    它的伪代码作用域为:

    exampleFnConext = {
      AO:{
        a:10
      }
      scope:globalContext.AO
    }
    

    相关文章

      网友评论

          本文标题:关于js声明提升和作用域链

          本文链接:https://www.haomeiwen.com/subject/hauwnttx.html