函数
function funcName(arg0, arg1, arg2){}
console.log(funcName.name)//funcName(函数的名字)
console.log(funcName.length)//3(参数个数)
递归
在递归时, 可以用arguments.callee代替自身函数名, 这样就可以解耦, 随意修改函数名
function factorial(num) { if (num <= 1) { return 1; } return num * arguments.callee(num-1);}
闭包
闭包会携带包含它的函数作用域, 所以它所占的内存逼其他函数多, 建议尽量少用; V8引擎会尝试回收被闭包占用的内存;个人理解: 没有闭包这东西, 无非就是作用域导致的现象, 也可以说任何函数其实都是闭包
闭包与变量
本来有一个需求是, 调用createFunctions()1
函数就返回对应的索引的值, 也就是1, 但是结果却是10; 因为这个函数返回的是一个闭包;这个闭包又要返回i, 但在它自身的作用域里无法找到这个变量, 它就会去作用域链上查找, 但是作用域链上的i, 最循环结束后, 已变成10了; 所以调用任何一个闭包,都是指向同一个作用域链上的i, 其值为10;
function createFunctions() { var result = []; for (var i=0; i < 10; i++) { result[i] = function() { return i; }; } return result;}createFunctions()1//10
可以修改为如下, 将i通过函数的方式传递进去, 那么num就是i的副本, 它的改变不所i而改变;因此当调用createFunctions()1
时, 需要返回num, 再其自身作用域里没有num, 就往上一级作用域里查找,正好可以找到num, 并返回, 其值也是和外层循环时传递进来的值一样;
function createFunctions() { var result = []; for (var i=0; i < 10; i++) { result[i] = (function(num) { return function() { return num; } })(i) } return result;}createFunctions()1//1
内存泄露
在ie9以前的浏览器dom节点是使用计数引用的方式管理回收内存, 因此不合理利用闭包会导致内存泄露;下面这个函数onclick的闭包函数, 引用了elemnt.id, 所以导致element无法被回收
function assignHandler() { var element = document.getElementById("someElement"); element.onclick = function() { alert(element.id) };}
可以将代码改成如下, 避免泄露, 首先建立一个element.id的副本, 再最后将element设置为null
function assignHandler() { var element = document.getElementById("someElement"); var id = element.id; element.onclick = function() { alert(id) }; element = null;}
关于this
var name = "the window"var object = { name: "my object", getName: function() { return this.name; }};object.getName();//"my object"(object.getName)();//"my object"(object.getName = object.getName)();//"the window"
模仿块级作用域
javaScript没有强类型语言中的块级作用域, 但可以利用匿名函数自执行来模拟;当一个函数声明被放在一个双扩里时, 就变成了表达式, 再添加双括号调用, 就会执行此函数;在函数内声明的变量, 也不会影响到外部, 实现块级作用域的效果.
(function() { for (var i = 0; i < 10; i++) { console.log(i); } })()console.log(i)//ERROR
私有变量
静态私有变量
JavaScript中的静态私有变量, 也是通过闭包模拟实现的;先用匿名函数自执行, 建立一个全新作用域, 这样变量就不能被外部直接访问,然后将构造函数挂载到外面的变量上暴露出去, 在其原型链上再添加获取和修改私有变量的方法,因为闭包的原因, 即使构造函数被实例化多次, 他们还是公用同一个name
值来实现静态效果.如果想通过原型对象上添加方法修改私有变量, 这样也无法实现, 因为在外面添加的原型方法,无法访问到里面作用域的变量.
var Person = null;(function() { var name = ""; Person = function(value) { name = value; } Person.prototype.setName = function(value) { name = value; } Person.prototype.getName = function() { return name; }})()var p1 = new Person("hello");p1.getName();//"hello"var p2 = new Person("world");p1.getName();//"world"p2.getName();//"world"Person.prototype.getName2 = function() { return name;}p1.getName2();//""
模块模式(单例模式)
var singleton = function() { //私有变量 var privateVar = 1; function privateFunc() { return privateVar; } //用户自定义的对象 var obj = new customObj(); //共有变量 obj.publicVar = true; //共有方法 obj.publicMethod = function() { privateVar ++; return privateFunc(); } return obj;}