js函数定义的三种方式
在Javascript定义一个函数一般有如下三种方式:
- 函数声明
function fnMethodName(x){
alert(x)
}
- 函数表达式,又叫函数字面量
var fnMethodName = function(x){
alert(x)
}
- Function()构造函数
var sum3=new Function('n1','n2','return n1+n2')
console.log(sum3(2,3)) // 5
// 由Function构造函数的参数个数可变。最后一个参数写函数体,前面的参数写入参。 参数必须加引号
// var b = 10
function fn1(){
var b = 10
var a = new Function('x', 'y', 'console.info(b) return x+y') // 会报错,找不到b 除非全局变量里面有b
a(1,2)
}
fn1()
// 上面的函数里面是获取不了局部变量的, 因为它总是被当作顶级函数执行的,所以里面的变量指的都是全局变量
上面三种方法的区别:
函数声明 | 函数字面量 | Function()构造函数 |
---|---|---|
静态 | 静态 | 动态 |
预先解析加载 | 按顺序解析 | 按顺序解析 |
效率高 | 效率高 | 效率低 |
顶级作用域 |
- 第一种函数声明是最常用的。后两种都是把一个函数复制给变量fnMethodName,而这个函数是没有名字的,即匿名函数。
- 第一种解析器会
预先读取加载
,并使其在执行任何代码之前可以访问。则必须等到解析器执行到它所在的代码行才会真正被解释执行。
- Function()构造函数允许运行时Javascript代码
动态的创建和编译
。在这个方式上它类似全局函数eval()。前面2种是静态的。
- Function()构造函数每次执行时都会解析函数主体,并创建一个新的函数对象,所以当在一个循环或频繁执行的函数中调用Function()构造函数
效率是非常低的
。而函数字面量却不是每次遇到都会重新编译的。
- Function()构造函数创建一个函数时
并不遵循典型的作用域
,它一直把它当作是顶级函数
来执行。
函数的this指向
this总是指向调用者
。谁调用这个函数,函数里面的this就指向谁
下面的示例都以非严格模式下
讲解,因为非严格模式
下,顶层对象是window
, 严格模式下
顶层对象是undefined
。
ES6 默认是严格模式。
- 函数声明的情况
// add() // 正常执行
var name=10
function add(){
var name=20
console.log(this) //非严格模式指向window, 严格模式指向 undefined
console.log(this.name) //10
console.log(name) //20
}
add() // 等价于window.add()
- 函数表达式
// zjj() // 报错,必须放到函数下面执行
var name=10
var zjj=function(){
var name=30
console.log(this) //非严格模式指向window, 严格模式指向 undefined
console.log(this.name) //10
console.log(name) //30
}
zjj