函数基础+变量声明提升/作用域链 +函数声明提升

A={V:2};  //加个;隔开  不加分号跟下面的自执行函数混在一起会报错
(function(A){
console.log(A); //{V: 2}
})(A)
function 函数名([参数])
	   {
	      函数体语句
	   }

注:
1、function是关键字
2、'函数名’是标识符,要符合JavaScript的标识符定义规则
3、‘参数’:函数可以有参数可以没有参数,但无论有没有参数,函数后的()都不能省略
4、{}:表示函数的作用范围,不能省略

4、函数的分类:在这里插入代码片
4.1、根据有无返回值划分:
A、有返回值函数:在函数中含有return语句,通常使用某种运算,并将运算结果返回。在此也需要强调一下return的作用,(1)返回值的一个值;(2)从当前函数退出。

B:无返回值函数:在函数中没有return语句,通常函数只是实现某种功能,无需返回任何值。

4.2、根据函数有无参数划分:
有参函数:表示函数在实现某种运算或实现某种功能时,需要外部参数的参入。
注:实参将数据传递给形参,传递方向是单向的,即若形参发生了改变不会影响实参
关于函数的参数:形参和实参的个数可以不同

A、当实参数量多于形参数量时,函数正常执行,多余的实参会被忽略。

B、当实参数量小于形参数量时,多出来的形参类似于一个已声明未赋值的变量,其值为undefined。

C、arguments的使用:在定义函数时,每个函数都有一个隐含的内置对象arguments,在该对象中保存了函数调用时的所有实参。、

function num(){
            console.log(arguments.callee) //就是整个num函数体  f num(){}
            console.log(arguments)//输出函数调用时所传递的所有实参  //[1,3,5]
            console.log(arguments.length)//arguments是一个数组  //3
            console.log(arguments[2])//输出数组中下标(索引)为1的元素,输出第二个实参   //5
        }
        num(1,3,5)

回调函数指一个函数A作为参数转递给函数B,然后在B函数体内调用A函数,此时A函数就是回调函数。


function sum(num1,num2,fn){//fn为函数,是函数sum的参数
    return fn(num1,num2)//调用fn,使num1,num2为fn的参数
}

var s=sum(30,70,function(a,b){
    return a+b
})

console.log(s)  //100

立即调用匿名函数

(function([参数]){ //匿名函数
		 
		    函数体语句
			
		 })(); //在函数括号后加入双括号为立即调用此匿名函数

三、作用域的分类
1、什么是作用域
作用域就是一个变量可以生效的范围,一个变量他不是在所有的地方都可以使用的,而这个变量的使用范围就是它的作用域。
2、全局变量
(1)在函数外部声明的变量
(2)在函数内部省略var关键字,声明的变量
使用var声明变量,在方法内部是局部变量,在方法外部是全局变量
不使用var声明,在方法内部和外部都是全局变量,但是若声明在方法内部,在外部使用时必须先调用方法,向系统声明全局变量后才可使用

var obj = {
     fun:function varceshi() {
       // var a = 10;   //局部
         a = 10;  //全局
     }
 }
 obj.fun();  //调用方法 
 console.log(a); //10

js当中没有var就是全局变量
因为在js中,如果某个变量没有var声明,会自动移到上一层作用域中去找这个变量的声明语句,如果找到,就用,如果没找到,就继续向上寻找,一直查找到全局作用域为止,如果全局中仍然没有这个变量的声明语句,那么会自动在全局作用域进行声明,这个就是js中的作用域链,也叫变量提升

console.log(a); //  a is not defined 是因为确实还没执行a=10这句话,所以a还没被声明
a=10
a=10
console.log(a); //10 被声明赋值后

function name() {
  var a //
  function na() {
    console.log(1);
    a=10
  }
na()

}

name()
console.log(a); *****// a is not defined*****
function name() {
  
  function na() {
    console.log(1);
    a=10
  }
na()

}

name()
console.log(a); **// 10**

3、局部变量:在函数内部使用var关键字声明的变量。只在函数内部有效
4、块级变量:在ES6(ECMAScript6)标准中提出的。是用户let声明的变量,只在语句块({})中有效
5、作用域链:当一个函数内部声明另一个函数时,首先会在当前作用域寻找,若未找到,则继续向上一层级的作用域中寻找,直到全局作用域,称这种链式的查询关系为作用域链。

函数的使用建议
函数就是程序模块,建议函数的功能尽量单一化。在项目中模块之间应该是高内聚、低耦合(耦合:模块之间结合的紧密程度;内聚:模块内部结合的紧密程度)

函数的声明提升和变量的声明提升详解:
牢记这三点:
只有声明本身会被提升,而赋值操作不会被提升,即执行代码的顺序不会变,还是自上而下。
变量会提升到其所在函数的最上面,而不是整个程序的最上面。
函数声明会被提升,但函数表达式不会被提升。
(函数表达式指var a=function形式的声明)

js知识盲区:js预解析与解析变量声明的顺序
js预解析:在执行代码之前,js会预解析代码,代码中如果有变量声明和函数声明的话,那么便将变量声明和函数声明置顶,函数声明比变量声明优先。

js解析声明变量的顺序:js在解析变量声明的时候,是分为两个步骤的。
比如这句代码:var a = 1;其实是分为(1)var a;(2)a=1;两个解析步骤来进行的。

因为作用域链,所以在调用变量或者一个对象属性等的时候,查找的顺序是由里向外的,js执行代码是自上而下的

1.函数提升优于与变量提升,且不会被变量声明覆盖,但是会被变量赋值覆盖 ,如下

var name3  //相同的变量只会被声明一次,函数提升优于var提升
console.log(name3); // function
name3=5  //与函数重名,直接赋值
function name3() {
    
}
console.log(name3); //5
name3() //name3 is not a function

var name=function(){
    console.log(4);
}

function name(){  
 console.log(5);
}
name()  //打印4,因为不管function name()在前在后他都会被先声明提升,然后再被赋值
 console.log(a) // 函数
  var a = 1; 
  console.log(a) //变量 1
  function a() {
  }  
  console.log(a) //变量 1
var a; //a不会被变量声明覆盖,是因为变量只会声明一次,多个var也不会重复声明,只会赋值
    function a(){  
      console.log(10);   //如果函数提升不优于与变量提升,那么第二段代码应该打印undefined
    }  
    console.log(a); //function  
function a(){  
      console.log(10);  
    }  
    var a; 
    console.log(a); //function 

2.只有声明本身会被提升,而赋值或其他运行逻辑会留在原地(代码执行顺序不变)。如果提升改变了代码执行的顺序,会造成非常严重的破坏。函数声明的形式可以提升,但函数表达式的形式不可以提升

证明函数声明会被提升,但函数表达式不会被提升。
  1.    a;
      console.log(a); //function
  
       function a(){  
      console.log(10);  
    }  


  2.    a;
      console.log(a); // undefined
  
      var a= function a(){  
      console.log(10);  
    }  

3.变量名与函数名重名的问题

var a = 1;
    function b(){
        a = 10;
        return;
        function a(){
            console.log(a);
        }    
    }
b();
console.log(a); //1

那么我们来分析下上面的代码:
1)先声明变量a,系统给变量a分配一个内存,注意,这里变量a暂时还不知道它的变量类型,因为还没有赋值;
2)a=1,给变量赋值为1,变量类型为number;
3)开始执行函数b,函数b内有一个函数名为a的函数声明,且函数a下面有一个变量名为a的变量,且赋值为10,这里便开始了难点分析。首先看函数a,由于在执行函数b的时候,并没有调用函数a,因此函数a并没有起作用;但是执行到a=10的时候,js是这样做的:1.首先查找变量a的地址,从系统内存中开始按照作用域链查找;2.由于作用域链的查找顺序是由里向外的,故要先从函数b里面开始查找;3.在查找的过程中,发现函数b中已经声明了一个函数名为a的函数(重名问题!),所以查找到函数名为a的函数后,这里便不再往外查找;4.所以这里的a=10其实是将10赋值给了函数名为a的这个函数对象!
4)因为既然a=10这个值10赋值给了函数对象a,那么在全局环境下运行console.log(a),访问的是全局变量a,而全局变量a在系统内存中查找的值为1,所以打印的值为1

函数声明提升参考了这篇文章

4.自执行的函数不会有函数声明和提升,因为没有必要去提升浪费资源

(function name1() {
     console.log(1); //1
 })()

 console.log(name1); // name1 is not defined

案例:
1.

    function name2(){
      console.log(a); //undefined  变量a提升但未赋值
    }
   name2()
   var a="5";


//自执行函数没有函数声明提升
   (function (){
      console.log(a); 
    })()
   var name="Wordld";
  
    function name2(){
      console.log(name); //undefined  因为后面又声明了var name="jack",这会导致name变量提升到前面,会先从局部作用域中找name变量,但赋值没提升,所以就undefined
        if(typeof name==="undefined")  //true
        {
            var name="jack"
            console.log("hellp"+name); //hellpjack
        }
        else
        {
            console.log("hellp"+name);
        }

    }
   name2()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值