函数,作用域链

2017-10-10  本文已影响0人  _达斯基

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

函数声明语法:

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

函数表达式语法

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

区别:
使用function关键字可以声明一个函数,它的特征是函数声明提升,执行代码前会先读取函数声明,即函数声明不必放在调用的前面,它可以放在当前作用域任何位置;函数表达式在使用前必须先赋值,所以声明必须放在调用前面,不然浏览器解析代码时会认为函数还不存在而抛出错误,理解函数提升的关键就是理解函数声明与函数表达式之间的区别。

错误做法

//函数调用
sayHi();
//函数声明
var sayHi = function(){
  console.log('Hi!');
};
会抛出错误:函数还不存在

正确写法:

//函数声明
function sayHi(){
console.log('hello');
}
//调用
sayHi()
//调用可以在声明之前
var sayHi = function() {
console.log();
}
sayHi()
//声明必须在调用前,

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

- 变量声明前置

变量声明出现在代码中的任何位置都会在该代码执行前处理,这意味着变量可以在声明之前使用。这个行为叫"hoisting",即把在指定作用域内声明的变量提升到函数或全局代码的顶部。
声明变量的作用域限制在其声明位置的上下文中,而未声明变量总是全局的,所以总在作用域最开始声明变量可以使变量的作用域变得清晰。

console.log(a);  //undefined
var a=1;
console.log(b);  //ReferenceError:b is not defined

由上到下执行代码之前,解析器会先找关键字var,找到了var a,就提升var a并将a初始化为undefined
再由上往下执行,读到consolo.log(a),控制台打印出来的就是undefined
接着给变量a赋值为1,如果这个时候后面再加一句consolo.log(a),那么控制台就会多打印出一个1
console.log(b)的结果很好理解,因为没有声明变量b所以抛出错误
也就是说变量声明会在代码执行之前就创建、初始化并赋值undefined

注意:
提升的是var a而不是var a=1,var a=1是后面赋的值。
这也印证了:变量声明会提升,变量的赋值不会提升!!!

- 函数的声明前置

使用function关键字可以声明一个函数,它的特征是函数声明提升,执行代码前会先读取函数声明,即函数声明不必放在调用的前面,它可以放在当前作用域的任何位置。
示例:

a();
function a(){
console.log("hello world")
};

js引擎有以下过程:
1找到所有用function声明的变量,在环境中创建这些变量
2将这些变量初始化并赋值为function(){console.log("hello world")}
3开始执行代码a()
也就是说function声明会在代码执行之前就创建、初始化、赋值。

注意:变量声明和函数声明都会提升,函数声明提升的优先级高于变量声明提升。
示例:
console.log(a);
var a=1;
function a(){};
//输出结果a是一个函数即:ƒ a(){}

3.arguments 是什么?

arguments是一个类数组对象,除了length属性外没有任何数组属性,是所有函数中可用的局部变量,仅在函数内部有效。

使用场景:调用一个函数时,当这个函数的参数数量比它显式声明的
参数数量更多时,就可以使用 arguments 对象。

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

js是弱类型语言,参数不是固定的某个类型,所以在js中没有重载,同名函数后面的会覆盖前面的。但我们也可以实现重载所需要的功能。

function printPeopleInfo(name,age,sex){
    if(name){
        console.log(name);
    }
    if(age){
        console.log(age);
    }
    if(sex){
        console.log(sex);
    }
}
printPeopleInfo("dot",23);  //dot 23
printPeopleInfo("dot","female",23);  //dot female 23


function add(){
    var num=0;
    for(var i=0;i<arguments.length;i++){
        num+=arguments[i];
    }
    console.log(num);
}
add(1);  //1
add(1,2,3);  //6

始终记住函数名只是一个指向函数对象的指针,并不会与某个函数绑定

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

// 以下都能实现立即执行
(function(){ /* code */ }());
(function(){ /* code */ })();
// function前加一元运算符也可实现
!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();

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

1.方法一

var factorial = (function f(n){
    if (n <= 0){
        return 1;
    } else {
        return n * f(n-1);
    }
});
factorial(5);  //120

2.方法二

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

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('饥人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');

输出分别为:

name: 饥人谷
age: 2
sex: 男
["饥人谷",2,"男"]
name valley
name: 小谷
age: 3
sex: undefined
["小谷",3]
name valley
name: 男
age: undefined
sex: undefined
["男"]
name valley

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

function sumOfSquares() {
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
        sum += Math.pow(arguments[i], 2);
    }
    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);  //undefined,因为变量a声明提升并赋值为undefined,先读取变量声明
var a = 1;
console.log(b);  //抛出ReferenceError:b is not defined,因为b没有声明

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

sayName('world');
sayAge(10);
function sayName(name){
    console.log('hello ', name);  //hello world,因为sayName函数声明提升
 }
var sayAge = function(age){
    console.log(age);  //抛出TypeError: sayAge is not a function,因为sayAge是函数表达式,使用前必须赋值,而声明放在了调用的后面,此时函数还不存在,所以会报错
 };

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

var x = 10;
bar() ;
function foo() {
  console.log(x);
}
function bar(){
  var x = 30;
  foo();
}

结果为10

// 对应的作用域链
globalContext = {
    AO: {
        x: 10,
        bar: function() {}
        foo: function() {}
    }
    Scope: null
}
bar.[[scope]] = globalContext.AO;
foo.[[scope]] = globalContext.AO;
barContext = {
    AO: {
        x: 30,
    }
    Scope: globalContext.AO;
}
fooContext = {
    AO: {},
    Scope: globalContext.AO;
}

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

var x = 10;
bar() 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) 
  }
  foo();
}   

结果为30

//  对应的作用域链
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;
}

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

var x = 10;
bar() 
function bar(){
  var x = 30;
  (function (){
    console.log(x)
  })()
}

结果为30

// 作用域链
globalContext = {
    AO: {
        x: 10,
        bar: function() {};
    }
    Scope: null
}
bar.[[scope]] = globalContext.AO;

barContext = {
    AO: {
        x: 30,
         anonymity :function() {}
    }
    Scope:globalContext.AO;
}
anonymity.[[scope]] = barContext.AO;


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

var a = 1;

function fn(){
  console.log(a)         // (1)
  var a = 5
  console.log(a)         //  (2)
  a++
  var a
  fn3()                         // (3)
  fn2()                         // (4)
  console.log(a)          // (5)      

  function fn2(){
    console.log(a)
    a = 20
  }
}

function fn3(){
  console.log(a)
  a = 200
}

fn()
console.log(a)                    // (6)

在上面标注了输出时代码的序号。

// 执行到(1)时对应的作用域链
globalContext = {
    AO:{
        a:1,
        fn: function() {},
        fn3: function() {},
    }
    Scope: null;
}
fn.[[scope]] = globalContext.AO;
fn3.[[scope]] = globalContext.AO;

fnContext = {
    AO: {
        a: undefined,
        fn2: function() {}
    }
    scope: fn.[[scope]] = globalContext.AO;
}
fn2.[[scope]] = fnContext.AO;

(1)此时输出 undefined

// 执行到(2)时对应的作用链
globalContext = {
    AO:{
        a:1,
        fn: function() {},
        fn3: function() {},
    }
    Scope: null;
}
fn.[[scope]] = globalContext.AO;
fn3.[[scope]] = globalContext.AO;

fnContext = {
    AO: {
        a: 5,
        fn2: function() {}
    }
    scope: fn.[[scope]] = globalContext.AO;
}
fn2.[[scope]] = fnContext.AO;

(2)此时结果:undefined 5

// 执行到(3)时对应的作用域链
globalContext = {
    AO:{
        a:1,
        fn: function() {},
        fn3: function() {},
    }
    Scope: null;
}
fn.[[scope]] = globalContext.AO;
fn3.[[scope]] = globalContext.AO;

fnContext = {
    AO: {
        a: 6,
        fn2: function() {}
    }
    scope: fn.[[scope]] = globalContext.AO;
}
fn2.[[scope]] = fnContext.AO;

fn3Content = {
    AO:{}
    scope: fn3.[[scope]] = globalContext.AO;
}

(3)此时结果:undefined 5 1

// 执行到(4)对应......
globalContext = {
    AO:{
        a:200,
        fn: function() {},
        fn3: function() {},
    }
    Scope: null;
}
fn.[[scope]] = globalContext.AO;
fn3.[[scope]] = globalContext.AO;

fnContext = {
    AO: {
        a: 6,
        fn2: function() {}
    }
    scope: fn.[[scope]] = globalContext.AO;
}
fn2.[[scope]] = fnContext.AO;

fn3Content = {
    AO:{}
    scope: fn3.[[scope]] = globalContext.AO;
}

fn2Content = {
    AO: {}
    scope: fn2.[[scope]] = fnContext.AO;
}

(4)此时结果为 undefined 5 1 6

// (5)对应的作用链
globalContext = {
    AO:{
        a:200,
        fn: function() {},
        fn3: function() {},
    }
    Scope: null;
}
fn.[[scope]] = globalContext.AO;
fn3.[[scope]] = globalContext.AO;

fnContext = {
    AO: {
        a: 20,
        fn2: function() {}
    }
    scope: fn.[[scope]] = globalContext.AO;
}
fn2.[[scope]] = fnContext.AO;

fn3Content = {
    AO:{}
    scope: fn3.[[scope]] = globalContext.AO;
}

fn2Content = {
    AO: {}
    scope: fn2.[[scope]] = fnContext.AO;
}

(5)此时结果为undefined 5 1 6 20

//  (6)
globalContext = {
    AO:{
        a:200,
        fn: function() {},
        fn3: function() {},
    }
    Scope: null;
}
fn.[[scope]] = globalContext.AO;
fn3.[[scope]] = globalContext.AO;

fnContext = {
    AO: {
        a: 20,
        fn2: function() {}
    }
    scope: fn.[[scope]] = globalContext.AO;
}
fn2.[[scope]] = fnContext.AO;

fn3Content = {
    AO:{}
    scope: fn3.[[scope]] = globalContext.AO;
}

fn2Content = {
    AO: {}
    scope: fn2.[[scope]] = fnContext.AO;
}

(6)输出结果 : undefined 5 1 6 20 200

上一篇下一篇

猜你喜欢

热点阅读