第8章:01-函数的定义与调用

函数定义

函数使用 function 关键字来定义,有 函数定义表达式函数声明语句 两种方式。


函数定义表达式

var fun = function () {
    // some code ...
}

函数声明语句

function fun () {
    // some code ...
}

// 本质:声明了一个变量 fun,并把函数对象赋值给 fun。


如果函数定义表达式中存在函数名称标识符,那么该标识符只存在于函数体内中,并指代该函数对象本身。

var fun = function f () {
  console.log(f);
}

fun();
console.log(f);

如果一个函数定义表达式包含名称,那么该函数的局部作用域将会包含一个绑定到函数对象的名称。


函数声明语句会被提前到外部脚本或外部函数作用域的顶部。(“变量提升”)

fun();

function fun () {
  console.log('fun:我可以在定义之前被调用...');
}

// 相当于
function fun () {
    console.log('fun:我可以在定义之前被调用...');
}

fun();

上面代码中,变量 funfunction 命令声明,会发生变量提升,即脚本开始运行时,函数声明语句就已经存在了。所以可以在被定义之前所调用。


函数定义表达式虽然也存在变量提升,但无法被提前调用。

fun();

var fun = function () {
  console.log('fun:我不可以在定义之前被调用...');
}

// 相当于
var fun;

fun();   // 此时 fun 是 undefined,并不是一个函数。

fun = function () {
    console.log('fun:我不可以在定义之前被调用...');
}

上面代码中,变量 funvar 命令声明,虽然会发生变量提升,即脚本开始运行时,变量 fun 已存在,但是此时还不是一个函数,所以会报错。


函数中的 return 语句。

function fun1 () {
  return '123';
}

function fun2 () {
  return;
}

function fun3 (x, y) {
  let result = x + y;
}

console.log(fun2());
console.log(fun3(1, 2));

在这里插入图片描述

如果 return 语句有与之相关的表达式,会返回表达式的值给调用者。

如果没有与之相关的表达式,则返回 undefined 值。

如果一个函数不包含 return 语句,那会返回 undefined 值。

函数的调用

有4种方式来调用JS函数:

+ 作为函数
+ 作为方法
+ 作为构造函数
+ 通过它们的 call() 与 apply() 方法间接调用

作为函数调用

function fun (x, y) {
    return x + y;
}

fun(1, 2);

根据 ECMAScript 3 和非严格的 ECMAScript 5 对函数调用的规定,调用上下文(this 的值)是全局对象。然而,在严格模式下,调用上下文则是 undefined


可以通过下列方法判断当前是否严格模式。

var strict = (function() { return !this })();

作为方法调用

// 如果一个函数 fun 是一个对象 obj 的方法,则通过如下方式调用
obj.fun();

此时,fun 函数被当做一个方法,而不是作为一个普通函数来调用。


在方法调用表达式里,对象 obj 成为函数的调用上下文,函数体可以使用关键字 this 引用该对象。

var obj = {
    add: function () {
        console.log(this)
    }
}

obj.add();

上面代码中,方法 add 体内的 this 指向的是对象 obj 的本身。

任何函数只要作为方法调用实际上都会传入一个隐式的实参—这个实参是一个对象,方法调用的母体(如 obj)就是这个对象。


作为构造函数调用

如果函数或方法调用之前带有关键字 new,它就构成构造函数调用。构造函数调用和普通的函数调用以及方法调用在实参处理调用上下文返回值方面都有不同。


实参处理:

如果构造函数有实参,先计算实参表达式,然后传入函数内,这和普通函数调用时一致的。但如果构造函数没有形参,调用时都可以省略圆括号,如下,下面两行代码是等价的:

var obj1 = new Object();
var obj2 = new Object;

console.log(obj1);
console.log(obj2);


调用上下文:

构造函数调用创建一个新的空对象,这个对象继承自构造函数的 prototype 属性。并将这个对象用作上下文,因此构造函数可以使用 this 关键字来引用这个新创建的对象。

// 情况一
function Obj() {
    this.name = 'cez',
    this.fun = function() {
        console.log(this);
    }
}

var obj = new Obj();
obj.fun();

// 情况二
var o = {
  Obj: function () {
    this.name = 'zlz';
    this.getThis = function () {
      console.log(this);
      console.log(this == o);
    }
  }
}

var obj = new o.Obj();
obj.getThis();

上面代码中,构造函数体内的 this 指向的是新创建的对象。也就是说,在表达式 new o.Obj() 中,调用上下文并不是 o


返回值:

构造函数通常不使用 return 关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显示返回。如果构造函数显示的使用 return 语句返回一个对象,那么调用表达式的值就是这个对象。如果构造函数使用 return 语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。

// 没有 return 语句
function Obj() {
  this.name = 'cez';
}

var obj = new Obj();
console.log(obj);

// return 语句返回一个对象
function Obj() {
  this.name = 'cez';
  return { name: 'zlz' };
}

var obj = new Obj();
console.log(obj);

// return 语句没有返回值
function Obj() {
  this.name = 'cez';
  return;
}

var obj = new Obj();
console.log(obj);

// return 语句返回一个原始值
function Obj() {
  this.name = 'cez';
  return 'zlz';
}

var obj = new Obj();
console.log(obj);

没有 return 语句:

return 语句返回一个对象:

在这里插入图片描述

return 语句没有返回值:

return 语句返回一个原始值:


间接调用

JS 中的函数也是对象,函数对象也可以包含方法。其中的两个方法 call()apply() 可以用来间接地调用函数。两个方法都允许指定调用所需的 this 值,也就是说,任何函数可以作为任何对象的方法来调用,哪怕这个函数不是那个对象的方法。

var obj = {
  name: 'cez'
}

function fun() {
  console.log(this);
}

fun();
fun.call(obj);
fun.apply(obj);

上面代码中,正常情况下,函数体内的 this 指向的是全局对象(Window),在使用 callapply 方法时可以显示的指定this 的值。


函数可以作为任何对象的方法来调用,哪怕这个函数不是那个对象的方法。
var obj = {
  name: 'cez'
}

function fun() {
  console.log(this);
}

fun();
fun.call(obj);
fun.apply(obj);

上面代码中,正常情况下,函数体内的 this 指向的是全局对象(Window),在使用 callapply 方法时可以显示的指定this 的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值