函数也是对象(具备控件变量区域)
函数是由一系列语句块组成的
typeof 函数 // function
函数创建方法:
1.命名函数创建
function 函数名(){}:这是一个函数,运行到当前代码之前就已经执行了,预加载和预赋值
函数名.length:形参的长度
函数名.arguments:实参的长度
纯函数:没有引用函数之外的变量,不改变函数外的变量和内容,相对已经完全独立的函数体
2.匿名函数创建
var 变量 = function(){}:这里的变量在运行到当前代码之前并没有赋值函数,只有在赋值函数之后才可以运行
3.自执行函数创建
(function(){})():运行到该函数,只能执行一次,以后无法调用
~function(){}()
+function(){}()
-function(){}()
!function(){}()
后面的四个跟第一个是一样的,只是书写不一样
优点:形成一个封闭的空间
缺点:因为函数也是一个对象,所以会存储在堆里面,而自执行函数只会执行一次,所以执行完毕之后就会在堆里面一直存储,不会再次使用了,所以就会造成内存泄漏。
4.构造函数声明法
var 变量 = new Function ('参数','参数','return 返回值')
前面的参数都是函数的参数,最后一个是函数的返回值,里面的参数不能是变量
缺点:消耗内存,运行速度慢
优点:可以随时动态创建
变量与作用域
变量污染:未知情况下将变量的值重新赋值了
变量
全局变量:在script中定义的变量都是全局变量(window)
局部变量:在function中定义的变量就是局部变量,仅对自身和其内部的函数空间有效
在函数里面:参数也是局部变量
作用域与变量的结论:
1.命名函数预解析的时候,不单纯开辟了空间,还将函数赋值给了这个变量,因此,命名函数定义在任何位置都等同于在开始就定义完成。
2.只要在函数内部使用了var,定义变量或者参数传入的变量,都是局域变量,一旦有局域变量,则不能再调用到外部同名变量了,那么,这个变量也是预解析了。定义前获取就是undefined,定义后获取就是这个变量的值。
3.变量调用只能调用到当前作用域及当前作用域所有父代作用域范围的非同名变量,不能调用到当前作用域中子代的作用域范围变量。
函数的参数
形参:函数作用域中的局部变量
形参:执行函数时传入的值
实参是按照形参的顺序一一赋值
参数分为:必填参数、默认值参数、可选参数、不定量参数
// 必填参数 //默认值参数 ES5: function fn(a,b){ if(b===undefined) b=0 } ES6: function fn(a,b=0){} //可选参数还没有出现 //不定量参数 ES5: function fn(a,b,c,d){ console.log(arguments)//打印出实参的一个列表型对象 } ES6:使用..arg arg就是对应数组 function fn(a,b,...arg){ console.log(a,b,arg) } fn(1,2,3,4,5,6,7) //1,2,[3,4,5,6,7]
js是一种弱类型的语言,意味着参数类型可以任意填入,这就会造成函数内执行的结果可能与预期不符
把函数当成参数传入另一个函数执行,这种方式叫做回调
arguments:列表型对象
arguments.callee:指的是当前函数
arguments.callee.caller:调用当前函数的上下文函数,如果是在window中调用,则是null(ES6中严格模式禁止这种方法的使用)
关于arguments和this问题
在ES5中,直接执行的命名函数中this就是window
除了ES6之外,回调函数执行后,执行的回调函数中的this只是window
回调函数如果使用arguments调用回调,在执行的回调函数中this只想调用当前函数的上下文环境中的arguments。
块作用域
先解析后赋值
1.将函数写在块语句中,函数只会预解析,不会预赋值,在执行语句块时,才会赋值函数。
2.如果块语句中出现同名变量和函数名同名时,执行语句块最后打印的是正常顺序赋值的结果,但是在语句块外,变量是最后一个同名函数上面的赋值变量的结果。
3.如果语句块中,同名变量和函数名相同时,只有一个变量和一个函数,并函数在前时,最后在语句块外打印的是函数,反之,如果函数在后,则返回这个变量的值。
4.在语句块中,不管有几个同名函数,都会被最后一个同名函数覆盖掉。
// 第2点 var a = 1; { a = 2; function a(){ console.log('a') } a = 6; function a(){ console.log('a') } a = 12; function a(){ console.log('a') } a = 18 console.log(a) // 18 } console.log(a) // 12 //第三点:只有一个函数和一个同名变量时,谁在前返回谁 var a = 1; { a = 2; function a(){ console.log('a') } console.log(a) // 函数 } console.log(a) // 2 var a = 1; { function a(){ console.log('a') } a = 2; console.log(a) // 2 } console.log(a) // 函数 // 第四点 var a = 1; { function a(){ console.log('a') } function a(){ console.log('a') } function a(){ console.log('a') } } console.log(a) //返回最后一个函数
return
作用:跳出返回
目的:为了返回一个结果,函数最终完成后得到的结果
return返回一个新的元素:工厂模式
function fn(tag){ return '<'+tag+'></'+tag+'>' } // 加工一个标签
如果对象的属性名和变量名相等时,直接写变量,意味着创建了同名属性
单例: function getInstance(){ var _instance return function(){ return _instance || instance = 创建新的对象 } }
函数使用return只能返回1个内容
当需要返回多个内容时,可以使用对象或者数组返回。
根据返回的数据是否要说明属性属于谁的,如果需要就使用对象返回,如果不需要就使用数组。
function fn(){ return arguments[0]() } function fn1(){ console.log(this)// 此时的this指的就是:当前函数fn1的上下文函数fn的arguments } console.log(fn(fn1,2,3,4,5))
回调函数
使用回调函数时,this指向分为2个:
1.window
2.指向调用回调函数的上下文函数的arguments。
回调函数:在达到某个条件时,或者运行到某个时间时才会让这个函数执行。
回调函数无法传参
实现回调函数传参的效果的几种方法
第一种:
animation.a=10 var id = setInterval(animation,1000) function animation(){ console.log(animation.a) // 10 }
第二种:
var id = setInterval(fn(5),1000) function fn(n){ animation.a = n return animation; } function animation(){ console.log(animation.a) //5 }
第三种:
var id = setInterval(animation(4,5),1000) function animation(m,n){ return function(){ console.log(m,n) //4,5 } }