[js] 函数 闭包

原创 2016年08月30日 09:25:58

函数声明与函数表达式
函数声明会自动提升(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)

js 函数的参数 问题 arguments对象 及闭包

js 参数的传递  是按值传递,在函数内部对变量所做的操作,不会影响到外部的变量。但是如果传递的是复合类型的对象,在内部对其属性所做的操作,则会影响外部对象,这是按址传递。 例如 var ...
  • tustyao
  • tustyao
  • 2015年06月27日 23:35
  • 816

JS学习笔记:JavaScript匿名函数与闭包(closure)

这部分之所以会放在一起整理,是因为匿名函数和闭包的概念很容易混淆,经常会用错。闭包是JavaScript的一个难点,也是它的一个特色,很多高级应用都要通过闭包实现,正确的理解和使用闭包是很重要的。闭包...

JS(二)-闭包和箭头函数

闭包 一、函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。 求和的函数定义: function sum(arr) {     return arr.reduce(fu...

js闭包的用途(匿名自执行函数,缓存,实现封装,实现面向对象)

文章转载自:http://blog.csdn.net/sunlylorn/article/details/6534610

js匿名函数和闭包的学习

匿名函数的写法总结有三种: //函数字面量:首先声明一个函数对象,然后执行它。 (function(){ alert(1); })(); //优先表达式:由于Javascript执行表达式是从...
  • zyujie
  • zyujie
  • 2012年10月16日 11:36
  • 772

【笔记】关于js的匿名函数问题, 还有闭包的问题, 做下笔记

写在前面 看到这样一段js代码, 是不明白的, 于是上网找相关资料, 这是匿名函数的一种写法!function($){ ... code ... }(jquery)(function($){ ...
  • zyjcxc
  • zyjcxc
  • 2017年08月06日 12:26
  • 158

JS笔记--探讨闭包中内部函数在各情况下的可访问范围

闭包实质有权访问另一个函数作用域中的变量的函数,通过通过在一个函数中创建的另一个函数而获得闭包。首先要说明的是,闭包并不等于匿名函数,匿名函数可以构成闭包,但不等于闭包。          闭包的作用...
  • fspwz
  • fspwz
  • 2015年05月03日 15:25
  • 706

js闭包函数和 this指针

本文总结了一下闭包里的实例,逐步分析了每一步的运行状态,帮助读者更好的理解闭包函数的运行机制。 JS闭包函数 window.onl...

js函数闭包

今写js时遇到一问题,要用内函数引用外函数的变量,我知道 用函数闭包能解决这个问题 ,但没写成,故参考了些博客,并复制了此文章,用作参考。 我遇问题,并解决实现代码如下: 五角...
  • z123500
  • z123500
  • 2012年03月08日 22:19
  • 305

js函数4-闭包

js采用词法作用域,也就是说函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数调用时决定的。函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[js] 函数 闭包
举报原因:
原因补充:

(最多只允许输入30个字)