第十章:函数

第十章:函数

  • 函数实际上是对象( Function的实例)
    • 函数名是指向函数对象的指针

10.1 箭头函数(ES6)

  • 不能使用 argumentssupernew.target,也不能用作构造函数
  • 没有 prototype属性

10.2 函数名

  • 函数名是指向函数对象的指针
function test() {
    console.log(123);
}

test();                 // 123

const another = test;
another();              // 123

test = null;
another();              // 123
  • ES6 中所有的函数对象都暴露了一个只读属性 name
console.log(test.name);             // test
console.log((() => { }).name);      // ""
console.log(new Function().name);   // anonymous
  • 获取函数、设置函数或者使用 bind()实例化,名称前会有前缀
function foo() { }
console.log(foo.bind(null).name);           // bound foo

let dog = {
    get age() {

    }
};
const pd = Object.getOwnPropertyDescriptor(dog, "age");
console.log(pd.get.name);                   // get age

10.3 理解参数

  • 所有参数都是按值传递的,传递对象参数时、传递的是对象的引用
  • 函数参数在内部表现为一个数组
    • 使用 function 定义函数时,可以通过类数组对象 arguments访问参数
    • arguments对象的值会同步对应的命名参数,但是二者在内存中是分开的
function test(arg1, arg2) {
    console.log(`arg1: ${arguments[0]}, arg2: ${arguments[1]}`);
}

test("jiy", "yij");     // arg1: jiy, arg2: yij
  • 严格模式下不能重写 arguments对象,修改其内部的值不会同步到命名参数
箭头函数中的参数
  • 箭头函数中不能使用 arguments访问参数,只能通过命名参数

10.4 没有重载

  • 后定义的函数会覆盖先定义的同名函数

10.5 默认参数值

  • arguments对象的值不反映参数的默认值
  • 默认参数值不局限于原始值或对象类型,可以使用函数返回值
默认参数作用域与暂时性死区
  • 多个默认参数值的定义与 let关键字顺序声明变量类似

10.6 参数扩展与收集

10.6.1 扩展参数


10.6.2 收集参数

  • 收集参数不影响 arguments
function test(...values) {
    return values.reduce((pre, cur) => pre + cur);
}

console.log(test(1, 2, 3));     // 6

10.7 函数声明与函数表达式

  • 函数声明提升:函数声明会在任何代码执行之前先被读取并添加到执行上下文
  • 函数表达式要执行到那一行才会生成函数定义(使用 var 也一样)

10.8 函数作为值


10.9 函数内部

10.9.1 arguments

  • arguments.callee:指向 arguments对象所在函数
    • 严格模式下无法访问
let test = function (num) {
    if (num <= 1) {
        return 1;
    }
    else {
        // 函数逻辑与函数名解耦
        return num * arguments.callee(num - 1);
    }
};

console.log(test(5));   // 120

10.9.2 this

  • 标准函数中:引用的是把函数当成方法调用的上下文对象
  • 箭头函数中:引用的是定义该函数的上下文

10.9.3 caller

  • 引用的是调用当前函数的函数,在全局作用域中调用则为 null
  • 严格模式下不能赋值
function outer() {
    inner();
}

function inner() {
    // arguments.callee.caller == inner.caller
    console.log(arguments.callee.caller);
}

outer();    // [Function: outer]

10.9.4 new.target

  • 函数正常调用:值为 undefined
  • 通过 new调用:引用被调用的构造函数

10.10 函数属性与方法

  • length:定义的命名参数的个数
  • prototype
apply()
  • 参数:函数内 this的值;一个参数数组
call()
  • 参数:函数内 this的值;所有参数…
bind()

10.11 函数表达式

  • 匿名函数

10.12 递归


10.13 尾调用优化

  • p307(第四版)

10.13.1 尾调用优化的条件


10.13.2 尾调用优化的代码


10.14 闭包

10.14.1 this对象

  • p313(第四版)
  • 内部函数永远不能直接访问外部函数的 thisarguments

10.14.2 内存泄漏


10.15 立即调用的函数表达式

(function () {
    console.log('func');    // func
})();

10.16 私有变量

  • 任何定义在函数或者块中的变量都可以认为是私有的
function Person() {
    let name = 'jiy';

    // 特权方法
    this.setName = function (value) {
        name = value;
    }
    // 特权方法
    this.getName = function () {
        return name;
    }
}

const p = new Person();
console.log(p.name);        // undefined
console.log(p.getName());   // jiy

10.16.1 静态私有变量

(function () {
    // name 由 Person 的所有实例共享
    let name = "jiy";

    // 不使用关键字,使变量创建到全局作用域上
    Person = function () { };
    Person.prototype.getName = function () {
        return name;
    };
})();

10.16.2 模块模式

let single = function () {

    // 私有变量和函数
    let name = "jiy";

    // 特权/公有方法和属性
    return {
        type: "person",
        getName() {
            return name;
        },
        setName(value) {
            name = value;
        }
    }
}();

10.16.3 模块增强模式

let single = function () {

    let name = "jiy";

    // 可以指定单例为特定类型的实例
    let obj = new CustomType();
    obj.type = "person";
    obj.getName = function() {
            return name;
        };
    obj.setName = function(value) {
            name = value;
        };

    return obj;
}();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值