总结对函数创建、传参和调用理解

442 阅读4分钟

一、常见函数创建的六种方式

方式一:函数声明

  • 特点:通过函数声明的方式如下,函数声明存在提升,会将变量的声明提升到作用域顶部,也就是可以在声明之前调用;且其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'])