1. JS的立即执行函数

需要立即执行的代码放在一个匿名函数中并立即执行,可以隔离作用域

(functino(){

    //代码
    
})()

之所以用圆括号把function(){}括起来是因为js解释器会将function解释为函数声明,而函数声明不能直接跟着(),我们需要将其转换为函数表达式。然后()代表执行函数

2. JS的闭包

闭包其实并不复杂,就是普通的函数,因为js拥有两个特性

  1. js函数可以访问 父级作用域

  2. js函数返回值可以是函数

function s1()
{

	var n=0;

	function s2()
	{

		n+=1;

		console.log(n);

	}

	return s2;

}

var s3 = s1();

s3(); //1

s3(); //2

函数s1 返回值是函数s2 

s1 执行一次完毕之后 ,初始化的 n不会被销毁

所以s2 每次执行都 n 会被叠加


3. JS this

函数中的this指向调用该函数对象的作用域,而非函数本身

function s1()
{
	console.log(window==this);
}

s1(); //true

var o = {

	f:function()
	{
		console.log(o==this);
	}

}

o.f(); //true

function s2()
{
	this.f = function(){
		return this;
	}
}

var o2 = new s2();

console.log(o2 == o2.f()); //true

s1的调用等价于 window.s1 ,所以s1中的this指向全局对象window

构造函数s2中的this指向他的实例 o2 ,所以等价

4. apply, call

改变函数中this的指向

function s1()
{
	this.name = "s1";
}

function s2()
{
	this.name = "s2";
	this.fn = function()
	{
		console.log(this.name);
	}
}

var o1 = new s1;

var o2 = new s2;

o2.fn.call(o1); // 输出 s1


//可以实现继承
function s3()
{
	this.f3=function()
	{
		console.log("f3");
	};
}

function s4()
{
	this.f4=function()
	{
		console.log("f4");
	};
}


function f5()
{
	s3.call(this);
	s4.call(this);
}

var o5 = new f5;

o5.f3(); //输出 f3

o5.f4(); //输出 f4

实例o2的方法fn中的this 被指向 s1 的 实例 o1的上下文,所以输出s1 

也可以实现继承

apply方法与call方法类似。两者唯一的不同点在于,apply方法使用数组指定参数,而call方法每个参数单独需要指定

5. 模块化编程

JavaScript并非模块化编程语言,至少ES6落地之前都不是。

然而对于一个复杂的Web应用,模块化编程是一个最基本的要求。

这时,可以使用立即执行函数来实现模块化,

正如很多JS库比如jQuery以及我们Fundebug都是这样实现的。

var module = (function() { 

    var N = 5; 
 
    function print(x) { 
        console.log("The result is: " + x); 
    } 
 
    function add(a) { 
        var x = a + N; 
        print(x); 
    } 
 
    return { 
        description: "This is description", 
        add: add 
    };
    
})(); 
 
 
console.log(module.description); // 输出"this is description"  
 
module.add(5); // 输出“The result is: 10”

所谓模块化,就是根据需要控制模块内属性与方法的可访问性,即私有或者公开。

在代码中,module为一个独立的模块,N为其私有属性,print为其私有方法,decription为其公有属性,add为其共有方法。