Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

函数 #4

Open
wweggplant opened this issue Sep 25, 2023 · 0 comments
Open

函数 #4

wweggplant opened this issue Sep 25, 2023 · 0 comments

Comments

@wweggplant
Copy link
Owner

参数

在ES5中,人们更希望函数被改进的功能是:

  1. 可以设置参数默认值
  2. 函数多个参数的情况下,取参数没有简便的办法
  3. 函数调用时,传入多个参数
  4. 函数的this绑定问题
  5. 判断是对象是否是通过构造方法创建的
  6. 更好的尾递归优化

参数默认值

function foo(a = 1 b = 2) {
    return a + b
}
foo() // 3
foo(2) // 4
foo(undefined, 1) // 2 

注意最后的foo(undefined, 1),第一个参数传入undefined,如果参数a有默认值的话,使用默认值。

参数临时死区

参数可以访问后定义的参数。但是要注意的是,这里的参数类似let,存在临时死区。如果访问的变量没有被初始化,那么就会报错。

function foo(a = b, b = 2) {
    return a + b
}

foo(1, 1) // 2
foo(undefined, 1) // 报错

要注意调用函数时,对应参数位置传入undefined意味着跳过这个参数,如果该参数设置了默认值的话,就会把默认值当做实际的参数,所以foo(undefined, 1)意味着跳过了参数a赋值,a就会把b当做默认值, 但是此时b还没有完成初始化,是不可访问的状态,所以这里会报错。

无命名参数

上面都是讲的命名参数, 而对于无命名参数,在ES5中是通过arguments对象处理的,ES6中有了新的方法去处理无命名参数。

不定参数

在定义参数的时候,使用三个点后面跟一个名字表示不定参数,该参数为一个数组,包含了自它之后所有传入的参数。

function foo(a, ...args) {
    console。log(args[0])
}
console。log(1, 2) // 2

不同于arguments,不定参数是一个数组。需要注意的是,不定参数必须放在最后,否则会报错,与此同时,ES6中也是可以使用arguments的。

增强Function构造函数

在ES5中,Function增强函数如下:

new Function([arg1 [, arg2 [, 。。。argN]] ,] functionBody)

在ES6中,可以使用默认参数和不定参数

const foo = new Function('a','b = a', 'return a + b')
const bar = new Function('。。。args', 'console。log(args[0])')

展开运算符

当函数允许多个参数的时候, 如果方便的把多个参数呢?在ES6中,提供了展开运算符。

ES5有一个传入多个参数技巧:

let values = [1, 2, 3, 4]
Math。max。apply(Math, values) // 借用了apply方法可以传入的数组的特性

上面的代码在ES6中,可以这样写:

let values = [1, 2, 3, 4]
Math。max(。。。values) // 4
Math。max(。。。values, 5) // 5, 展开运算符后面可以继续跟参数

name属性

在ES5中, 函数的name值是函数的名字,在ES6中由于多了几种情况,所以name的值就有了一些增强

var doSomeThing = function doSomethingElse() {
    // 空函数
}
var person = {
    get firstName() {
        return 'abc'
    }
    sayName() {
        console。log(this。name)
    }
}

var foo = function () {}

console。log(doSomeThing。name) //  doSomethingElse
console。log(person。sayName。name) // sayName
console。log(person。firstName。name) //  get firstName
console。log(foo。bind()。name) // bound foo
console。log((new Function())。name); // anonymous

name会返回函数的name加上前缀,如getter函数会返回get XXX。需要注意的是name属性,不一定是引用的同名变量,所以不能通过name值来反向获取变量。

元属性(Metaproperty) new.target

new。target主要是用来判断当前对象是否是通过new构造出来的。在es5中,要判断是否是new出来的,通常是用instanceof来判断,不过这样的判断是可以绕过的。

function Person() {
    if (this instanceof Person) {
        console。log('是通过new构造出来的')
    } else {
        throw new Error('不是通过new构造的')
    }
}
var p1 = new Person() // 提示正确
var p2 = Person。call(p1) // 提示正确,实际是错误的

那么在ES6中,怎么使用new。target呢?当调用new的时候,new。target赋值为new操作的目标,否则值为undefined

function Person() {
    if (typeof new。target !== 'undefined' ) {
        console。log('是通过new构造出来的')
    } else {
        throw new Error('不是通过new构造的')
    }
}
var p1 = new Person() // 提示正确
var p2 = Person。call(p1) // 报错

new。target是函数的元属性(Metaproperty),要注意的是,这个理的new虽然后面跟着,但是它不是对象。 new。target指向被new调用的构造函数,所以"new。"成为了一个虚拟上下文。在箭头函数中中,new。target 指向最近的外层函数的new。target

块级函数(有疑问)

在规范里,在块级内声明函数是错误的,但是很多浏览器支持这样的操作。所以在ES5的严格模式中,如果这做会报错。

"use strict";
if(true) {
    function foo() {

    }
}

但是在ES6的严格模式中,会被认为是一个块级声明,只可以在代码快中访问使用这个函数

"use strict";
if(true) {
    function foo() {

    }
}
console。log(foo)

在ES6的非严格模式下,块级函数不会起作用,也就是和ES5的非严格模式一样的。代码块中的声明的函数会被提升到外部或者全局

箭头函数

与正常的函数相比,箭头函数主要区别是:

1。 没有this、super、arguments和new。target绑定,这些值都是由最近的外层决定的
2。 不能通过new创建
3。 没有原型
4。 不可以使用this绑定
5。 不支持arguments对象
6。 不支持重复命名参数(?)

之所以有上面的这些限制,主要是因为设计箭头函数出发点是确定this的绑定,所以要把以上会干扰this绑定的因素排除掉。这样可以使得引擎更好的优化执行过程。

返回一个对象

```javascript
    let foo = id => ({a: id, b:2})


```

尾递归优化

ECMAScript6缩减了严格模式下尾调用栈的大小(非严格模式下不受影响),如果满足以下条件,尾调用不再创建新的栈帧,而是清除并重用当前栈帧:

1。 尾调用不访问当前战帧的变量(也就是说函数不是 一个闭包〉。
2。 在函数内部,尾调用是最后一条语句。
3。 尾调用的结果作为函数值返回。

下面的都不会优化,因为没有直接把函数调用作为最后的返回

"use strict"
function doSomething() {
    // 会优化
    return doSomethingElse();
}
function doSomething() {
    // 不会优化
    doSomethingElse();
}
function doSomething() {
    // 不会优化
    return 1 + doSomethingElse();
}

function doSomething() {
    // 不会优化
    return 1 + doSomethingElse();
}
function doSomething() {
    // 不会优化
    let result = doSomethingElse();
    return result
}

如果里面=包含闭包,也是不能优化的

function doSomething() {
    var num = 1, func = () => num
    // 包含闭包,不能优化
    return func
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant