讲函数前,先了解Function和function的区别。
- function是关键字(if else var )function声明一个函数
function f(){}
Function是全局对象new Function('x','y','return x+y',)
或者Function('x','y','return x+y')
声明函数有两种方法1.关键字声明 2.new Function声明
1.具名函数 function f(){ return undefined} 2.匿名函数 var f f = function(){} 这两个属于第一种
3.new Function('x','y','return x+y ') 这个属于第二种(除非无聊或者想用字符串拼凑的时候才有这种)
函数的五种声明方式
function f(x,y){ return x+y }
var f = function (x,y){ return x+y }
var f = function x(x,y){ return x+y }
var f = new Function('x','y','return x+y') // window.Function
-
var f= (x,y) => { return x+y }//es6的箭头函数
var f = (x,y) => x+y //return和花括号一起省略
var f = n => n*n //参数只有一个时,参数的括号可以省略
name知识点
每个函数都有名字,但是比较鸡肋,基本用不到
function f(){}
f.name // f
var f2 = function(){}
f2.name // f2
var f3 = function f4(){}
f3.name // f4
f4.name // f4 is not defined
f5 = new Function('x','y','return x+y ')
f5.name // anonymous
函数是可以反复调用的代码块 调用函数英文是call
call
var f = {}
f.params = ['x','y']
f.functionBody = 'console.log("fff")'
f.call = function (){
return window.eval(f.functionBody)
}
f.call() // fff
call其实就是函数的复杂写法
f(1,2) === f.call(undefined,1,2)
,实际参数从第二个开始传,undefined是this , 1,2是argumentscall的第一个参数可以用this得到,call后面的参数可以用arguments得到
f和的区别 f是函数体 f.call()指向这个对象的函数体
其中可以执行代码的对象就叫函数(我们写的代码)
函数原型Function.prototype
有三个重要的方法call apply bind
,会重写toString
方法覆盖Object的toString
方法
this
在普通模式下,如果this是undefined,浏览器会自动把this变成window
f = function (){
console.log(this == = window)
}
f.call(undefined) // true
如果是严格模式,给undefined打印出的就是undefined,
f = function (){
'use strict'
console.log(this === window)
}
f.call(undefined) //false
arguments
argument是伪数组,因为它的原型链上没有Array.prototype,或者 proto没有指向Array.prototype
下面判断
f = function(){
arguments.push(4)
console.log(arguments)
}
f.call(undefined,1,2,3)
会报arguments.push is not a function
的错,所以是伪数组
很好判断是不是伪数组,给push
方法
call stack 调用栈
Stack Overflow 和中国的segment fault 这两个网站的由来就是从栈溢出而来的
function sum(n){
if(n==1){
return 1
}else{
return n + sum.call(undefined, n-1)
}
}
sum.call(undefined,9650) //46566075
再大就栈溢出Maximum call stack size exceeded
,所有栈的调用最多在9650左右,再多就栈溢出了
作用域
在使用变量的时候 ,怎么去找它的声明 ,就找这个作用域里面的声明,找不到找外面作用域的声明,如果还找不到 。再往外面找,就近原则
声明提升:变量提升,函数的声明也提升,先提升在看代码
f1里的console.log是什么
var a = 1
function f1(){
f2.call()
console.log(a) //undefined
var a = 2
function f2(){
var a = 3
console.log(a)
}
}
f1.call()
console.log(a)
//3
//undefined
//1
先变量提升改写代码
var a = 1
function f1(){
var a
function f2(){
var a
a = 3
console.log(a) // a定义再赋值在console.log前面,所以是3 }
f2.call()
console.log(a) // a先定义,赋值在console.log下面,所以是undefined
a = 2
}
f1.call()
console.log(a)
例2
f4打印的是什么
var a = 1
function f1(){
console.log(a)
var a = 2
f4.call()
}
function f4(){
console.log(a) //1, f4的a 一定是f4的作用域或者它的父作用域
}
f1.call()
console.log(a)
f1的a只在f1函数里有效,而f4的a 一定是f4的作用域或者它的父作用域 ,不用和上面的变量提升搞混
例3
????里的内容有没有可能是的a输出的不是1
var a = 1
function f4(){
console.log(a)
}
??????? //a = 2 不是立刻执行就可能是2
f4.call()
作用域说的是a是那个a,但并没有说a是哪个a的值,如果????里设置了延时代码,那么a就不一定是1了
闭包
var a = 1
function f4(){
console.log(a)
}
这就是闭包 如果一个函数,使用了它范围外的变量,那么(这个函数+这个变量)就叫做闭包