笔记 04 JS 函数 – 声明,表达式,this

原文地址

函数

函数是JavaScript中的一等对象
=> 可以把函数像其它值一样传递。

1 函数声明与表达式

1 函数声明

存在于当前上下文的任意一个地方,
方法会在执行前被解析

foo(); // 正常运行,因为foo在代码运行前已经被创建
function foo() {}

2 函数赋值表达式

/**
 * 由于var定义了一个声明语句,
 * 对变量foo的解析是在代码运行之前,
 * foo变量在代码运行时已经被定义过了。
 * 但是由于赋值语句只在运行时执行,
 * 因此在相应代码执行之前,foo的值缺省为undefined
 */

foo; // 'undefined'
foo(); // 出错: TypeError: foo is not a function
var foo = function() {};

3 命名函数的赋值表达式


/**
 * 神奇的递归死循环
 * 实践方法-函数自执行 (function bar() { console.log(1); bar(); })()
 */
var foo = function bar() {
  console.log(1);
  bar(); // 正常运行
}

/**
 * bar函数声明外市不可见的。
 * 这是因为我们已经把函数赋值给了 foo
 * 然而在 bar 内部依然可见。
 * 这是由于 JavaScript 的命名处理所致,
 * 函数名在函数内总是可见的。
 */
bar(); // 在外边调用不起来

2 this的工作原理

JavaScript有一套完全不同于其它语言的对this的处理机制。

1 全局范围内

this; // 它将会指向全局对象

2 函数调用

ES5 注意: 在严格模式下(strict mode),不存在全局变量。 这种情况下 this 将会是 undefined。

foo(); // 函数内部this指向全局对象

3 方法调用

test.foo(); // 方法内部this指向test对象

4 调用构造函数

/**
 * 如果函数倾向于和new关键词一块使用,
 * 则我们称这个函数是 构造函数
 */
new foo(); // 在构造函数内部this指向新创建的对象

5 显式的设置this apply,call 等函数

/**
 * 当使用 Function.prototype 上的 call 或者 apply 方法时
 * 函数内的 this 将会被 显示设置为 `函数调用的第一参数`
 */

function foo(a, b, c) {};

var bar = {};
foo.apply(bar, [1, 2, 3]); // 数组将会被扩展,如下所示
foo.call(bar, 1, 2, 3); // 传递到foo的参数是: a = 1, b = 2, c = 3
// 在 foo函数内 this被设置成了bar

误区 - 例子1

Foo.method = function() {
  function test() {
    // this 将会被设置为全局对象 (浏览器环境中也就是 window 对象)
  }
  test();
}

/**
 * 为了在 test 中获取 Foo 对象的引用,
 * 我们需要在 method 函数内部创建一个局部变量
 * 指向 Foo 对象
 */
Foo.method = function() {
  var that = this;
  function test() {
    // 使用 that 来指向 Foo 对象
  }
  test();
}

误区 - 例子2

/**
 * test 就像一个比普通函数调用被调用
 * 因此,函数内的 this 将不在被指向到
 * someObject 对象。
 */
var test = someObject.methodTest;
test();
function Foo() {};
Foo.prototype.method = function() {};

function Bar() {};
Bar.prototype = Foo.prototype;

new Bar().method(); // 当 method 被调用是,this 将指向 Bar 的实例对象