一些基本概念
1.函数就是将一批重复的代码封装,以供调用;其本质就是代码块。
2.函数的name属性是一个字符串。
3.复杂的函数命名需要遵循“驼峰命名法”。
4.函数后面圆括号里面的是函数的参数,花括号里面的是函数代码块。
5.函数的参数分为形参和实参,形参是指:函数在定义时,圆括号里面的内容叫做形参,函数在调用时,圆括号里面的内容叫做实参,实参可以是变量也可以是值。
6.函数是变量的特例。(var声明一个变量,可以是7种数据类型;函数只能声明一个函数)
函数的几种声明方式
1.匿名函数
var f; f=function(x,y){ return x+y } f.name //'f'
**把一个函数给一个变量,这个函数就是一个匿名函数,这个变量就相当于一个函数,可以直接进行调用。
2.具名函数(命名函数)
function 函数名(参数){代码块}
function f (x,y){ return x+y } f.name //'f'
3.具名函数赋值
var x =function y (a,b){} console.log(y) //报错 x.name //'y' function y (a,b){} console.log (y) //不报错 //以上情况是由于JS的不一致
4.window.Function
var f = new Function('x','y','return x+y') f.name //"anonymous"(匿名的)
一个小例子
n=1; var f = new Function('x','y','return x +'n'+y') //等价于 var f = new Function('x','y','return x +1+y') f(1,2) //4
5.箭头函数
var f = (x,y) => {return x+y} var f = (x,y) => x+y //{}可以与return一起去掉 var n = n => n*n //若对象只有一个参数,()可以去掉
函数调用
call
function f(x,y){ return x+y }
内存图解:
**params、fbody标注为假设标注,实际不存在**
代码理解:
f.params=['x','y'] f.fbody='return x+y' f.call=function(){ eval (f.body) } f.call() //eval是window的全局对象 //eval(‘xxxx’)给一个字符串当代码执行 eval ('1+1') //2 eval ('1+"1"') //"11"
**函数就是对象,函数的调用过程就是eval调用体的过程**
call调用与()调用,this与arguments
f (1,2) //(1,2)就是arguments //等价于 f.call(undefined,1,2) //undefined就是this,1,2就是arguments
call的第一个参数可以用this得到,后面的参数可以用arguments得到
var f = function(){ console.log(this); } f.call()//window 普通模式下若this是undefined,浏览器会将this默认变为window function f(){ console.log(this) } f.call(1)//Number 对象 1 var f = function(){ 'use strict' console.log(this); } f.call()//undefined 严格模式下若this是undefined,则为undefined function f(){ 'use strict' console.log(this) } f.call(1)//1
//arguments 伪数组 原型链中没有Array.prototype这一环,__proto__指向的是Object.prototype,不能使用.push等属性
call stack 调用栈
function a (){ console.log('a1') b.call() console.log(a2) return 'a' } function b (){ console.log('b1') c.call() console.log(b2) return 'b' } function c (){ console.log(c') return 'c' }
a.call()
console.log('end')
栈溢出(内存溢出)
stack overflow
(还不知道这个要怎么解决,以后遇到再说吧.. -_- ..)
关于递归
function sum (n){ if(n==1){ return 1 } else { return n+sum(n-1) } } sum = 5;//5+sum(4) //sum (4) //4+sum(3) //sum(3)//3+sum(2) //sum(2)//2+sum(1) //sum(1)
关于作用域(scope)
一些概念:
Javascript 有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。
例:
var a = 1 function f1 () { var a = 2 f2.call() console.log(a)//2 function f2(){ var a=3 console.log(a)//3 } } f1.call() console.log(a)//1
声明提前
var a function f1 () { var a a = 2 function f2(){ var a a = 3 console.log(a)//3 } f2.call() console.log(a)//2 } a = 1 f1.call() console.log(a) //1
例:
var a = 1 function f1 (){ f2.call() console.log(a) var a=2 function f2(){ var a=3 console.log(a) } }
f1.call()
变量提升
var a function f1 (){ var a function f2(){ var a a=3 console.log(a) //3 } f2.call() console.log(a) //undefined a=2 } a = 1
f1.call()
例;
var a = 1 function f1(){ console.log(a)//undefined var a=2 f2.call() } function(){ console.log(a)//1 作用域里面没有a,则找父作用域里面的a }
关于闭包
若一个函数,使用了它作用域外的变量,那么(这个函数+这个变量)叫做闭包。
其作用就是让这个变量值一直保存在内存中,要使用的时候即刻可以使用,另外可以通过闭包在函数外访问函数内部。
var a=1 function f (){ console.log(a) }
关于立即调用函数
声明一个函数,立即调用
使用原因:
1.全局变量不好用
2.使用局部变量,需要一个函数,在函数里声明,立即调用
3.匿名函数直接调用,会有报错
解决办法
(1)整体添加()
(2)将函数()起来再.call()调用
(3)直接再function前面加减号-或者加号+
(4)在function前面加!或~ 》》推荐《《
(5)使用代码块
ES6:let的作用域就是{}里面,let不会变量提升
待补充... ...