# 函数表达式

### 一、回顾

```a();    // a
b();    // TypeError: b is not a function
function a() {
console.log("a");
}
var b = function() {
console.log("b");
};```

```if(true) {
function sayHi() {
console.log("Hi, Jerry!")
}
} else {
function sayHi() {
console.log("Hi, Tang!");
}
}
sayHi();
// 在chrome、firefox下输出：Hi, Jerry!
// 在Safari下输出：Hi, Tang!```

```var sayHi;
if(true) {
sayHi = function() {
console.log("Hi, Jerry!")
}
} else {
sayHi = function() {
console.log("Hi, Tang!");
}
}
sayHi();
// 全部输出：Hi, Jerry!```

```function sayHi() {
console.log("Hi, Jerry!")
}
function sayHi() {
console.log("Hi, Tang!");
}
sayHi(); // 全部输出：Hi, Tang!```

### 二、递归

```function factorial(num) {
if(num <= 1) {
return 1;   // 书写递归函数，尽量要先写结束条件
} else {
return num * factorial(num-1);  // num--
}
}
factorial(4);   // 24```
```var anotherFactorial = factorial;
factorial = null;
anotherFactorial(3);    // TypeError: factorial is not a function```

```function factorial(num) {
if(num <= 1) {
return 1;
} else {
return num * arguments.callee(num-1);   // num--
}
}```

```var factorial = function fn(num) {
if(num <= 1) {
return 1;
} else {
return num * fn(num-1);     // num--
}
}
var anotherFactorial = factorial;
factorial = null;
anotherFactorial(3);    // 6```

### 三、闭包

```function createComparisonFunction(propertyName) {
return function(obj1, obj2) {
var value1 = obj1[propertyName],
value2 = obj2[propertyName];
return value1 - value2;
}
}

var p1 = { age: 25 };
var p2 = { age: 26 };
var compareAge = createComparisonFunction("age");
var result = compareAge(p1, p2);
if(result === 0) {
console.log("一样大！")
}else if(result > 0) {
console.log("p1大！")
}else {
console.log("p2大！");
}
compareAge = null;  // 释放内存```

```<ul>
<li>第一条</li>
<li>第二条</li>
<li>第三条</li>
<li>第四条</li>
</ul>```

```var list = document.getElementsByTagName("li");

for(var i = 0, len = list.length; i < len; i++) {
list[i].onclick = function() {
console.log(i); // 4
}
}```

```for(var i = 0, len = list.length; i < len; i++) {
return function() {     // function(i)
console.log(i);
}
})(i))
}```

```list.onclick = function() {
console.log(\$(this).prevAll().length);
}```

### 四、this对象

this对象在运行时基于函数的执行环境绑定。 在全局函数中，this等于window，当函数作为某个对象的方法调用时，this等于当前对象。 JavaScript中的this（你不知道的JavaScript）

```var name = "window";
var object = {
name: "current object",
getName: function() {
return this.name;
}
};
object.getName();   // current object```
```var name = "window";
var object = {
name: "current object",
getName: function() {
return function() {
return this.name;
}
}
};
object.getName()();  // window
// var getNameByWindow = object.getName();
// getNameByWindow();```
```var name = "window";
var object = {
name: "current object",
getName: function() {
var that = this;
return function() {
return that.name;
}
}
};
object.getName()(); // current object```

### 五、内存溢出

JavaScript对象和Dom对象循环引用，导致内存不能释放，内存溢出！ 示例10：

```var element = document.getElementById("id");    // Dom对象
var id = element.id;                            // JavaScript对象
element.onclick = function() {
console.log(id);
};
element = null;```

### 六、块级作用域

```for(var i = 0; i < 10; i++) {}
var i;  // 被忽略，变量提示
console.log(i); // 10```
```(function() {
for(var i = 0; i < 10; i++) {}
})();
var i;
console.log(i);  // undefined```

### 七、私有变量

JavaScript函数作用域，使得函数中定义的变量，都可以被认为是私有变量。 示例12 –构造函数模式：

```function Person(name) {
this.getName = function() {
return name;
};
}

var p1 = new Person("Jerry");
var p2 = new Person("Tang");
p1.getName();
p2.getName();```

```(function() {
var name = "";
Person = function(value) {
name = value;
};
Person.prototype.getName = function() {
return name;
}
})();

var p1 = new Person("Jerry");
var p2 = new Person("Tang");
p1.getName();
p2.getName();```

```var getSingle = function(fn) {
var result;
return function() {
return result || (result = fn.apply(this, arguments));
};
};

// 测试
function testSingle(){}
getSingle(testSingle)() === getSingle(testSingle)();    // true```

238 篇文章31 人订阅

0 条评论