A.函数
一.定义
一段可以被高度复用的代码段。
二.定义方式
- 声明式——有提升(整个声明都会提升)
fn1("先调用——我是乖哦bug");
function fn1(str) {
console.log("hi,我是声明的方式定义的 " + str);
}
fn1("后调用——我是乖哦bug");
- 表达式/赋值式——没有提升(变量名提升,赋值没有提升)
fn2("先调用——我是乖哦bug");
var fn2 = function(str) {
console.log("hi,我是表达式的方式定义的 " + str);
}
fn2("后调用——我是乖哦bug");
没有变量提升,因此先调用会报错。
- 构造函数式——函数是对象(没有提升:变量名提升了,赋值没有提升)
fn3("先调用——我是乖哦bug");
var fn3 = new Function('str', 'console.log("hi,我是构造函数的方式定义的 "+str);')
fn3("后调用——我是乖哦bug");
没有变量提升,因此先调用会报错。一般不建议使用这种方式定义函数。
3.调用函数
1)执行函数体内部的所有的代码;
2)有一个返回值,该返回值取决于函数体内部的return语句。
1.函数的返回值:取决于函数内部的return。如果调用没有return语句的函数时,该调用函数表达式的返回值一定是undefined(构造函数除外)。
2.return的作用:
控制调用函数表达式的返回值:如果函数体内部有return语句,那么调用该函数的表达式的返回值一定是return语句后面表达式的返回值。否则为undefined。
做流程控制:当程序运行到return语句时,程序会忽略return语句下面所有函数体内部的代码。
4.形参和实参
-
形参:在函数体内部声明的变量,只声明不赋值。
-
实参:为形参变量赋值(在本次调用中生效),即调用过程中传入的参数。
实参个数与形参个数不统一时:
-
实参>形参:程序会忽略多余的实参。
-
实参<形参:未被赋值的形参带入到函数体内部时,里面的值是undefined。
当声明函数时不确定调用函数会传入多少个实参时,会用arguments对象来代替形参。(arguments是一个类数组)
5.函数的引用
function fn() {
console.log(1)
}
fn
// 如果只写函数名,该表达式并不会调用函数体内部所有的代码
console.log(fn)
// 该表达式的返回值不取决于函数体内部的return语句,而一律返回函数自身(函数的引用)
// 函数的引用也是和Number,String..一样,作为一个数据类型
// 同样也可以被放置到另外的一个变量里
// 因为函数的引用后面加一对()就代表调用该函数
// 又因为m此时返回的就是fn的引用
// 所以m()就等价于fn()等价于调用了fn函数。
var m = fn;
console.log(m())
五. 函数参数的默认值
当我不传递参数的时候,使用默认值,传递参数了就使用传递的参数。
function fn(a) {
a = a || 10
console.log(a)
}
fn() // 不传递参数的时候,函数内部的 a 就是 10
fn(20) // 传递了参数 20 的时候,函数内部的 a 就是 20
//在 ES6 中我们可以直接把默认值写在函数的行参位置
function fn(a = 10) {
console.log(a)
}
fn() // 不传递参数的时候,函数内部的 a 就是 10
fn(20) // 传递了参数 20 的时候,函数内部的 a 就是 20
//这个默认值的方式箭头函数也可以使用
const fn = (a = 10) => {
console.log(a)
}
fn() // 不传递参数的时候,函数内部的 a 就是 10
fn(20) // 传递了参数 20 的时候,函数内部的 a 就是 20
//注意: 箭头函数如果需要使用默认值,那么一个参数的时候也需要写 ()
B.箭头函数
箭头函数(只能简写函数表达式,不能简写声明式函数)
一.语法
(函数的行参) => { 函数体内要执行的代码 }
function fn() {} // 不能简写
const fun = function () {} // 可以简写
const obj = {
//对象中的方法,进行了对象方法简写
fn: function () {} // 可以简写
}
二.特殊性
箭头函数的this指向问题:箭头函数会改变函数体内部this的指向,即每一个函数都会形成一个针对于this的封闭作用域,如果这是一个箭头函数则不会形成封闭作用域。这个箭头函数中的this指向会穿透本层到达上一层作用域上,以上一层this的指向作为本层this的指向。
- 在箭头函数定义的位置往上数,这一行是可以打印出 this 的。
var obj = {
fn: function() {
console.log(this)
},
// 这个位置是箭头函数的上一行,但是不能打印出 this
fun: () => {
// 箭头函数内部的 this 是书写箭头函数的上一行一个可以打印出 this 的位置
console.log(this);
}
}
obj.fn()
obj.fun()
//按照我们之前的 this 指向来判断,两个都应该指向 obj
//但是 fun 因为是箭头函数,所以 this 不指向 obj,而是指向 fun 的外层,就是 window
-
箭头函数内部没有 arguments 这个参数集合
const obj = {
fn: function() {
console.log(arguments)
},
fun: () => {
console.log(arguments)
}
}
obj.fn(1, 2, 3) // 会打印一个伪数组 [1, 2, 3]
obj.fun(1, 2, 3) // 会直接报错
三.简写
- 函数行参只有一个时,可以不写 () 其余情况必须写
const obj = {
fn: () => {
console.log('没有参数,必须写小括号')
},
fn2: a => {
console.log('一个行参,可以不写小括号')
},
fn3: (a, b) => {
console.log('两个或两个以上参数,必须写小括号')
}
}
- 函数体只有一行代码时,可以不写 {} ,并且会自动 return。
const obj = {
fn: a => {
return a + 10
},
fun: a => a + 10
}
console.log(fn(10)) // 20
console.log(fun(10)) // 20
C.构造函数
一.定义:
生产对象的工具。
二.语法
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.sayName = function(){
alert(this.name)
}
}
三.实例化对象
实例化对象时一定需要new关键字。
let bug = new Person("bug", 19, 1);