①定义函数最基本形式: function () {};与var一样是关键字
②函数名:起名与var类似,多个单词拼接必须符合小驼峰式规则,第一个单词首字母小写,后面的单词首字母大写。
函数可以简化代码,达到高内聚弱偶合原则
1.命名函数表达式 var test = function test(){};加分号,表达式会忽略函数名,函数名有name属性eg:
function abc(){} test.name——abc
;
2.匿名函数表达式 var demo = function (){};要加分号; 在表达式里会忽略函数名,如果再访问会报错
函数表达式中存储函数的变量就相当于函数,直接用变量名调用:demo();表达式必须加分号。
var f1 = function (){
console.log('a');
}
f1();——a
var f1 = function (){
console.log('b');
}
f1();——b
类似于var num=1;
console.log(num);——1
num = 2;
console.log(num);——2
function关键字 test函数名()参数:形参实参 {}
例:function test(a,b){ }相当于在函数体里var a,var b;test(1,2)对应a,b
参数不限制位数,无论形参有没有把实参表示完,实参都有地方存放;会存放在arguments(实参列表)里。
★只有实参和形参数量相等,实参列表才会和形参发生映射; 实参和形参里面有一个改变另一个也会改变,形参实参数量不相等就不会改变;arguments[]与实参不是同一个;
function sum(a,b){
a = 2;
console.log(arguments[0]);
}
sum(1,2);——2
function sum(a,b){
b = 2;
console.log(arguments[1]);
}
sum(1);——undefined不发生映射
return 结束条件,返回值
函数没有返回值但是在调用的时候接收了,那么结果就是undefined;如:
function f1(x,y){
var sum = x + y;
}
var result = f1(10,20);
console.log(result);——undefined
function f2(x,y){
var sum = x + y;
return;
}
var result = f2(10,20);
console.log(result);——undefined
函数中没有明确的返回值,调用的时候接收了,结果为undefined
求1-n所有数字的和
function getSum(n){
var sum = 0;
for(var i = n; i <= n;i ++){
sum += i;
}
return sum;
}
console.log(getSum(10));
求n-m之间所有数的和
function getSum2(n,m){
var sum = 0;
for(var i = 0;i <= m){
sum += i;
}
return sum;
}
求圆的面积
function gets(r){
return Math.PI * r * r;
}
例子:
function sum(a,b){
console.log('a');
return ;
console.log('b');
}
sum();——a
function sum(){
return 123;
}
var num = sum();——123
function test(fn){
console.log("hi");
fn();
}
function demo(){
console.log("hellow");
}
test(demo);
函数作为返回值使用值
function f1(){
console.log("f1被调用");
return function (){
console.log("这是一个函数");
}
]
var ff = f1();
ff();
1.语法分析:系统通篇扫描一遍,看是否有语法错误,但不执行;
2.预编译(函数声明整体提升,变量 —声明提升),预编译发生在函数执行的前一刻;
预编译前奏:①imply global暗示全局变量,即任何变量,如果变量未经声明就赋值,此变量就为全局对象(window)所有。
console.log(a);——10不报错
a = 10;
②一切声明的全局变量,全是window属性 。
var a = 123;
相当于window.a = 123;
在window仓库里寻找a
Ⅰ.创建AO对象,Activation Object(执行器上下文),函数执行前产生的存储空间库;
Ⅱ.找形参和变量声明,将变量和形参名作为Ao属性名,值为undefined;
Ⅲ.将实参值和形参相统一;
Ⅳ.在函数体里面找函数声明,值赋予函数体。
3.解释执行(解释一行执行一行)
全局变量如果页面不关闭,那么就不会释放,会占内存,消耗内存;
隐式全局变量:声明变量没用var;
全局作用域:全局变量的使用范围;
局部作用域:局部变量使用的范围;
例子:
function fn(a){
console.log(a);——function a(){}
var a = 123;
console.log(a);——123
function a(){}
console.log(a);——123
var b = function (){}
console.log(b);——undefined
function d(){}
}
fn(1);
预编译第一步:形参名变量名作为AO属性名
AO{
a : undefined,
b : undefined
}
第二步:形参实参相统一
AO{
a : 1,
b : undefined
}
第三步:找函数声明
AO{
a : function a(){}
b : undefined,
d : function d(){}
}
例子:
function test(a,b){
console.log(a);——1
c = 0;
var c;
a = 3;
b = 2;
console.log(b);——function b(){}
function b(){}
function d(){}
console.log(b);——function b(){}
}
test(1);
1.生成一个GO对象Global Object;GO === window
2.查找全局变量声明,变量名作为全局对象属性,值为undefined;
3.查找函数声明,值为全局函数引用
例子:
console.log(test);
function test(test){
console.log(test);——function test(){}
var test = 234;
console.log(test);
function test(){}——234
}
test(1);
var test = 123;
第一步:GO{
test : undefined
}
AO {
test : undefined
}
第二步:GO{
test : function test(){}
}
AO{
test : function test(){}
}
案例:1. function bar(){
return foo;
foo = 10;
function foo(){}
var foo = 11;
}
console.log(bar());——function foo(){}
如果下面有函数,直接输出函数
2.console.log(bar());——11
function bar(){
foo = 10;
function foo(){}
var foo = 11;
return foo;
}
如果上面被赋值,直接把值打印出来
小例子:
console.log("a");——error
console.log("b");——9
console.log("c");——9
function num(){
var a = b = c = 9;
console.log("a");——9
console.log("b");——9
console.log("c");——9
}
首先函数声明整体都提升到最上面,在函数内部 var a = b = c =9;声明提升把var a;提升到函数顶端,
a=b=c=9;就相当于,a=9;b=9;c=9;所以在内部访问就都是9。在外部访问时因为var a;经过声明,外部访问
不到内部变量,所以就报错,而b,c 没有声明,相当于是全局的变量,所以访问结果也是9.
fi();——报错error;这是函数表达式不能这样调用;
var f1 = function (){
console.log(a);
var a = 10;
}
1.[[score]]域:每个JavaScript都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取,[[score]]就是其中一个。
[[score]]指的就是我们所说的作用域,其中存储了运行期上下下文的集合
2.作用域链:[[score]]中所存储的执行期上下文对象的集合,这个集合呈链式连接;我们把这种链式连接叫做作用域链。(函数嵌套关系)
3.运行期上下文:当函数执行时,会创建一个称为执行器上下文(AO GO)的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。
4.查找变量:从作用域链的顶端一次向下查找
案例:function a(){
function b(){
var b = 234;
}
var a = 123;
b();
}
var glob = 100;
a();
//a函数被定义 a defined a.[[score]]——产生全局的执行上下文 0 :GO{}
//被执行 a doing a.[[score]]——新的作用域链 0 : AO{}
//a doing a.[[score]] ——1 : GO{}
//b defined b.[[score]]——0 : aAo{}所有aAO{}都是同一个
//b doing b.[[score]]——1 : GO{}
//b doing b[[score]]——0 : bAO{}
// 1 : aAO{}
//2 : GO
存到全局里的文件永远不会被销毁除非全局自身销毁
格式:
1.w3c建议:(function ( ){ } ())
2.(function ( ){ })( )
只有表达式才能被执行符号执行,执行完此函数就失去意义。
eg: var test = function (){ console.log('a');}()
——a
函数声明前加"+","-","!","||",等运算符会和立即执行函数一样
eg:- function(){ }()
趋势上要转换为表达式
eg:+ function test(){
console.log('a');
}()执行后忽略函数名,销毁引用
eg: var num = (function test(a,b,c){
var d = a + b + c;
retuen d;
}(1,2,3)) ——6
案例:(window.foo || (window.foo = 'bar'));
window.foo——bar
定义:当内部函数被保存到外部时会产生闭包,闭包会导致原有作用域链不释放,造成内存泄漏(内存被占用)。简单来说就是两个或多个函数嵌套把里面的函数保存到外部。
作用:1.实现公有变量.
eg:函数累加器
function add() {
function demo(){
count++;
console.log(count);
}
return demo;
}
}
var counter = add();
counter();
2.可以做缓存(存储结构)
3.可以实现封装,属性私有化
4.模块化开发防止污染全局变量
闭包案列:function a(){
function b(){
var bbb = 234;
console.log(aaa;)——123
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a;
demo();
只要是内部函数被保存到外部就会产生闭包
b保存到a的执行,aAO直到b执行完
闭包案例:打印1-10数字
function test(){
var arr = [ ];
for(var i = 0;i < 10;i++){
//数组每一位成为function作用打印i
arr[i] = function (){
document.write(i + "");
}
}
return arr;//返回数组
}
var myArr = test();//接收arr
for(var j = 0;j < 10;j++){
让数组每一位执行
myArr[j]();
}
结果:10 10 10 10 10 10 10 10 10 10
for循环转10圈执行了10次产生了十个彼此独立的函数,最后放数组里并且返回,这十个函数与test形成了10对1
的闭包;那么访问test的变量(arr,i)访问的是同一套;这十个函数在外部访问变量时访问的是同一个,是在
test执行完访问的而test执行完后i变成10了
解决后:
function test(){
var arr = [ ];
for(var i = 0;i < 10;i++){
(function (j){
document.write(j + "");
}(i));
}
return arr;//返回数组
}
var myArr = test();//接收arr
for(var j = 0;j < 10;j++){
让数组每一位执行
myArr[j]();
}
结果:1,2,3,4,5,6,7,8,9,10
闭包防范:闭包会导致多个执行函数共用一个公有变量;如果不是特殊需要应尽量防止这种情况发生。