关闭

[js] 函数 闭包

113人阅读 评论(0) 收藏 举报
分类:

函数声明与函数表达式
函数声明会自动提升(function declaration hoisting)

test();
function test() {console.log('for fun')} // for fun
test();
var test = function() {} // error

if(condition){
  function sayHi(){}
} else {
  function sayHi(){}
} // 无效语法,不同引擎会采取不同方式返回第一或第二个声明
var sayHi;
if (condition) {
  sayHi = function (){}
} else {
  sayHi = function (){}
} // 正常

函数参数
函数在调用时会获取arguments变量,和参数对应
两者并不访问相同的内存空间,但值会同步
agruments对象有一个callee属性,指向拥有该对象的函数

function a() {
  console.log(arguments.callee == a);
}
a(); // true

所有的值类型都通过值类型传递不通过引用传递

function doo(num1, num2) {} // arguments[0] 和 num1 对应

函数属性

caller保存调用该函数的函数的引用,若是全局变量返回null

function a() {
  b();
}
function b() {
  console.log(arguments.callee.caller);
}

a(); // function a() { b(); }
b(); // null

length表示函数希望接受的命名参数
arguments见下

函数调用
函数在调用时会自动获取this和arguments两个特殊变量
函数调用都是通过值传递,即使引用类型也是通过值传递

// professional js for web developers p71
function setName(obj) {
    obj.name = 'N'; // obj是一个内存中对象的引用,指向内存
    obj = {}; // obj是值传递,因此不会造成原来的指针变化
    obj.name = 'M';
}
var p = {};
setName(p);
p.name; // N

函数调用有四种方式,不同调用方法this指向不同
即使在不同环境中执行(传递的参数,如this值不同),指向的仍是同一个函数

function a(){}
var x = {
    b: function(){}
}
function NewObj(){}

x.b() // 方法调用(The Method Invocation Pattern) this == x
a() // 函数调用(The Function Invacation Pattern) this == window(this指向全局变量)
var Obj = new NewObj() // 构造器调用(The Constructor Invocation Pattern) this == Obj
a.apply(obj, arguments) // apply调用(The Apply Invocation Pattern) this == obj

arguments并不是真正的数组,arguments有length属性,但没有任何数组的方法

函数返回值

匿名函数(lambda)

闭包
指有权访问另一个函数作用于衷的变量的函数
不合理的使用闭包会造成内存泄漏

function outter(property) {
  return function() {
    alert(property);
  }
}
var def = outter('just for fun');
def();
def = null; // 解除对匿名函数的引用以释放内存

function domHandle(){
    var ele = document.getElementById('a');
    ele.onclick = function(){
        alert(ele.id); // 循环引用造成无法销毁ele
    }
}

function domHandle(){
    var ele = document.getElementById('a');
    var id = ele.id; // 消除循环引用
    ele.onclick = function(){
        alert(id);
    }
    ele = null; // 闭包保存的是外部函数所有的对象,所以要将ele设为null解除对DOM对象的引用
}

闭包通过作用域链获取数据,因此保存的是整个变量对象而非特定值

function create() {
  var result = [];

  for (var i = 0; i < 10; i++) {
    result[i] = function() {
      return i; // 在闭包调用的时候保存的i并非每次的值,而是最后的值10
    }
  }

  return result;
}

闭包的调用和声明时间不一致,因此在闭包中this值可能会发生改变

块级作用域
创建并立即调用一个函数,块级作用域中的变量会被从内存中立即销毁

(function(){
    // 块级作用域
})();

私有变量和特权方法
在函数中定义私有变量,通过闭包返回特权方法访问私有变量

//1
function MyObject(){
    var privateVariable = 10; // 私有变量
    function privateFunction(){} // 私有方法

    this.publicMethod = function(){ // 特权方法
        privateVariable ++;
        return privateFunction();
    }
}
var obj = new MyObject();
obj.publicMethdo(); // 通过特权方法访问私有变量和方法

//2
(function(){
    var privateVariable = 10; // 私有变量
    function privateFunction(){} // 私有方法

    MyObject = function(){ // 构造函数
    };
    MyObject.prototype.publicMethod = function(){ // 特权方法
        privateVariable ++;
        return privateFunction();
    }
})();
var obj = new MyObject();
obj.publicMethdo(); // 通过特权方法访问私有变量和方法

//3
(function() {
  var pub_pri_var = 0;
  function pub_pri_fun () {
    return pub_pri_var;
  }

  MyObj = function (name) {
    this.set = function (val) {
      name = val;
    }
    this.get = function () {
      return name;
    }
  }
  MyObj.prototype.pub_pub_fun = function () {
    pub_pri_var ++;
    return pub_pri_fun();
  };
})();
var a = new MyObj('a\'s name');
var b = new MyObj('b\'s name');
  • 第一种方法,不同的实例有自己的变量及方法
  • 第二种方法,所有实例享有同样的私有变量和私有方法
  • 第三种方法,所有实例有共同的方法和变量,也有私有的方法和变量
  • 使用私有变量会多增加一层作用域链,因此造成查找速度减慢

模块(Module)
利用闭包和私有变量构造模块

// <js: the good parts> p41
var serial_maker = function () { // 一个序列号生成函数
    var prefix = '';
    var seq = 0;
    return {
        set_prefix: function(p) {
            prefix = p;
        },
        gensym: function() {
            var result = prefix + seq;
            seq ++;
            return result;
        }
    }
}

var seqer = serial_maker();
seqer.set_prefix('Q');
var unique = seqer.gensym(); // Q1

通常可和单例共用,为单例创建私有变量和特权方法

var singleton = function () {
  var  privateVariable;
  function privateFunction() {}

  var obj = {}
  obj.publicProperty;
  obj.publicMethod = function () {}

  return obj;
} ();

级联
让方法返回this

var MyString = function (fir, sec) {
  this.first = fir;
  this.second = sec;
}
MyString.prototype.setF = function (val) {
  this.first = val;
  return this;
};
MyString.prototype.setS = function (val) {
  this.second = val;
  return this;
};
MyString.prototype.toString = function () {
  return this.first + ' ' + this.second;
};

var obj = new MyString('a', 'b');
obj.toString(); // 'a b'
obj.setF('aa').setS('bb').toString(); // 'aa bb'

柯里化(Currying)

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:5480次
    • 积分:355
    • 等级:
    • 排名:千里之外
    • 原创:32篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类