函数表达式
定义函数
函数声明
function functionName(arg0,arg1){
// 函数体
}
// Firefox Safari Chrome,Opera 有效 就是IE不行呗
console.log(functionName.name) // functionName
关于函数声明,最重要的特征就是函数声明提升,意思是在执行代码之前会先读取函数声明,这就意味这可以把函数声明放在调用它的语句后面。
// 不要这样做
var m1 = true;
if(m1){
function funs(){
console.log("1")
}
}else{
function funs(){
console.log("2")
}
}
funs() // Chrome 1
多次声明同一个函数,最后声明的函数有效。不要把函数声明放在条件判断语句的分支里面,这样是无效的,依然会有声明,(Firefox例外,Chrome试了试也例外)不同浏览器做法不一致。。。。
使用函数表达式,是没有这个问题的。
函数表达式
var functionName = function(arg0,arg2){
// 函数体
}
void functionName() // 表示忽略返回值
创建一个函数并把它赋值给一个变量。创建的函数叫做匿名函数因为function关键字后面没有函数名。(有时也叫拉姆达函数),它的name属性是空字符串。
函数表达式和其他表达式一样,使用之前必须先赋值。
递归
递归函数是在一个函数通过名字掉要自身的情况下构成的。
arguments.callee 是一个指向正在执行的函数的指针。编写递归函数的时候,使用arguments.callee比直接使用函数名,更保险。
function factorial(num){
if(num <= 1 ){
return 1;
}else{
return num * arguments.callee(num-1)
}
}
严格模式下,这个arguments不能使用,arguments.callee也就不可以调用了,可以使用命名函数表达式。
var factorial = (function f(num){
if(num <= 1 ){
return 1;
}else{
return num * f(num-1)
}
})
// 括号好像没什么作用 在Safari会导致错误,???
闭包
闭包是指有权访问另一个函数作用域中的变量的函数。 创建闭包的常见方式就是,在一个函数内部创建一个另一个函数。
function createCom(property){
return function(obj){
var value1 = obj[property]; // 这里使用了外面函数的变量proerty
return 1;
}
}
闭包与变量
作用链的这种配置引出了一种副作用,即闭包只能取得包含函数中任何变量的最后一个值。
function createFunction(){
var result = new Array();
for(var i = 0; i< 10; i++){
result[i] = function(){
return i;
}
}
return result;
}
console.log(createFunction()[0]()) // 10
可以通过创建另一个匿名函数强制让闭包的行为符合预期。
function createFunction(){
var result = new Array();
for(var i = 0; i< 10; i++){
result[i] = (function(num){
return function(){
return num;
}
})(i)
}
return result;
}
console.log(createFunction()[0]()) // 10
生成拥有更长的作用域链的闭包,将数据保存到下一级里面。
this
闭包中使用this可能会导致一些问题。this对象是在运行时基于函数的执行环境绑定的。全局函数中,,this等于window,函数作为某个对象的的方法调用的时候,this等于那个对象。匿名函数的执行环境具有全局性,因此对象通常指向window
call() apply() bind() 可以改变this指向
每个函数被调用的时候会自动取得两个特殊变量,this和arguments内部函数在搜索这两个变量的时候,只会搜索到它的活动对象为止。因此无法直接访问到外部函数的这两个变量,可以把外部作用域中的this对象保存在一个闭包能够访问的变量里面。
var name = "The Window";
var obj = {
name: "My Object",
getName: function (){
var that = this;
return function(){
return that.name
}
}
}
console.log(obj.getName()()) // My Object
内存泄漏
如果闭包的作用域链中保存着一个HTML元素。那么就意味该元素无法被销毁。
function assignHandler(){
var element = document.getElementById("some");
element.onclick = function(){
console.log(element.id);
}
}
function assignHandler(){
var element = document.getElementById("some");
var id = element.id;
element.onclick = function(){
console.log(e);
}
element = null;
}
通过吧element.id 保存在变量中,在闭包中引用这个变量,消除循环引用。闭包会引用包含函数的整个活动对象。包括element,即使闭包不直接引用element,包含函数的活动对象也会引用,所以需要手动吧element置为null,解除对DOM对象的引用。
模仿块级作用域
JavaScript中没有块级作用域,在块级语句中定义的变量,实际在包含函数中。
多次声明同一个变量,是没有效果的,但是会执行后续声明中的变量初始化。匿名函数可以用来魔方块级作用域,
块级作用域(通常被称为私有作用域)
(function(){
// 这里是块级作用域
})()
以上代码定义并立即调用了一个匿名函数,将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式,紧随其后的圆括号立即调用了这个函数,
常常用在全局作用域中,从而限制向全局作用域中添加过多的变量和函数。也可以减少闭包占用内存的问题。
私有变量
JavaScript没有私有成员概念。所有对象属性都是公有的,倒是有一个私有变量的概念,,**任何在函数中定义的变量,都可以认为是私有变量,以为不能在函数的外部访问这些变量,**私有变量包括函数的参数,局部变量,和函数内部定义的其他函数。
function add(num1,num2){
var sum = num1 + num2;
return sum;
}
函数内部有三个私有变量,num1、num2和sum,在函数内部可以访问这几个变量,在函数外部则不可以,,如果在函数内部创建一个闭包,那么闭包可以通过自己的作用域 链访问,利用这一点可以创建,用于访问私有变量的公有方法,
有权访问私有变量和私有函数的公有方法被称为特权方法,
function MyObj(){
// 私有变量
var privateVar = 10;
// 私有函数
function privateFun(){
return false;
}
// 特权方法
this.publicMet = function(){
privateVar++;
return privateFun();
}
}
特权方法作为闭包有权访问在构造函数中定义的所有变量和函数,利用私有(私有变量,私有函数)和特权成员,可以隐藏那些不应该被直接修改的数据。
但是这样每个MyObj的每个实例中都会重新创建,特权方法,使用静态私有变量可以避免这个问题。
静态私有变量
通过私有作用域中定义私有变量或函数,同样也可以创建特权方法,基本模式如下
(function (){
// 私有变量
var privateVar = 10;
// 私有函数
function privateFun(){
return false;
}
// 构造函数 初始化未经声明的变量
MyObj = function(){
}
// 公有 特权方法
MyObj.prototype.publicMet = function(){
privateVar++;
return privateFun();
}
})
初始化未经声明的变量会,创建一个全局变量。在严格模式下给未经声明的变量赋值会导致错误。
这个方法和在构造函数中定义特权方法的主要区别,在于私有变量和函数是由实例共享的。有特权方法是在原型上定义的。因此所有实例都使用的同一个函数。而这个特权方法,作为一个闭包函数,保存着对包含作用域的引用。
多查找作用域链中的一个层次,就会在一定程度上影响查找速度,这正是是用闭包和私有变量的一个明显不足之处。
模块模式
模块模式是为单例创建私有变量和特权方法。所谓单例指的是,只有一个实例的对象。JavaScript是以对象字面量模式创建单例对象的。
var singLeton = {
name: value,
method: function(){
// 这里是方法的代码
}
}
模块模式是通过为单例添加私有变量和特权方法,使其得到增强。
var singLeton = function (){
// 私有变量
var privateVar = 10;
// 私有函数
function privateFun(){
return false;
}
return {
publicFun: true,
publicMet:function(){
privateVar++;
return privateFun();
}
}
}
在Web应用程序中,常常需要使用一个单例来管理应用程序级的消息。
vue.js ???
增强的模块模式
有人改进了模块模式,在返回对象之前加入对其增强的代码,这种增强模式,适合那些单例必须是某种类型的实例。同时还必须添加某些属性,和方法对其增强,