一、常见函数创建的六种方式
方式一:函数声明
-
特点:通过函数声明的方式如下,函数声明存在提升,会将变量的声明提升到作用域顶部,也就是可以在声明之前调用;且其this的指向是window对象
function A() { return this; }
- 观察函数的执行结果我们可以发现全局函数声明后,this指向window
方式二:函数表达式
-
通过将函数声明赋值给一个变量,不存在变量提升,this的指向依旧是window
let B =function() { return this; }
- 观察函数的执行结果我们看到this的指向window
方式三:箭头函数
-
特点:写法比较简洁,针对不同的条件可有不同的写法,this的指向要根据调用的实例(具体的后面的博客谈到this的时候会提到),比如下面的函数在执行的时候,就是window实现,但是要记住一点,箭头函数的this指向不可以通过apply call bind修改
// 如果参数只有一个可以省略() // 如果执行语句只有一句可以省略{} // 没有写明return,默认返回undefined let C1 = p => p += 1
// 上面的条件不符合即这样定义 let C2 = (p1, p2) => { return p1 + p2 }
- 观察C1和C2,C1的返回语句是只有那一行代码的执行结果,C2是写明的return语句对应的返回值
方式四:立即函数
- 特点:函数定义需要用()包裹,且定义后就会立即执行;且我们可以观察到如何给function传参
方式五:构造器函数
特点:可被new,创建一个实例对象
function person(name) {
this.name = name
}
let p = new Person('d')
方式六:生成器函数
特点:可控制函数的指向步骤
function* generatorFun() {
yield 'a'
yield 'b'
yield 'c'
}
generatorFun()
for(let item of generatorFun()) {
console.log(item)
}
// a b c
二、常见函数传参的方式
方式一:预先定义好所有需要的形参
-
特点:需要预知参数的个数
function f(a, b, c, d) { return a + b + c + d } f(1, 2, 3, 4)
方式二:只定义部分可预知的参数,剩余的用剩余参数定义
-
特点:剩余参数是一个数组类型,是将剩余的参数转换为一个数组
function f(a, ...rest) { let res = a rest.forEach(e => res += e) return res } f(1, 2, 3, 4) // 10
方式三:将所有的参数组合成一个数组
特点:不用预知参数的个数,需要遍历数组进行处理
function f(...arguments) {
let res = 0
arguments.forEach(e => {
res += e
})
return res
}
f(1, 2, 3, 4) //10
方式四:定义默认参数
-
特点:预先定义的参数均可定义默认参数
function f(a = 1, b = 2, c = 3, d = 4) { return a + b + c + d } f() // 10
三、常见函数调用的方式
方式一:直接使用函数名调用,作为一个普通函数被调用
-
特点:函数内或者函数外均可调用
var a = 0 function f1() { a++ } function f2() { f1() a++ return a } f2() // 2
方式二:作为方法被某个实例对象调用
-
特点:方法被定义在某个对象的属性中
var obj = { name: 'OBJECT', f: function() { return this.name } } obj.f() // OBJECT
方式三:作为构造函数被new调用
function person(name) {
this.name = name
}
let p = new Person('d')
-
new到底发生了什么
function newPerson(name) { let o = {} // 创建一个对象 o.name = name // 给对象的属性赋值 return o // 返回该对象 }
方式四:使用call apply被使用
-
call和apply的第一个参数是新的函数上下文(改变了this指向当前的第一个参数),后面的参数是函数的参数,下面的栗子2展示了call和apply传参的区别,apply需要传入的是数组
// 栗子1:通过call和apply改变新的this指向 var obj = { name: 'OBJECT', f:function() { return this.name } } var obj1 = { name: 'OBJECT1' } obj1.f.call(obj1) // OBJECT1 obj1.f.apply(obj1) // OBJECT1
// 栗子2:call中如何传参 let name = 'window' function f1(prop) { return this.name + prop } let o = { name: 'object' } f1.call(o, 'type') f1.apply(o, ['type'])