摘要:在函数内部定义的匿名函数的作用域链中,不包含外部函数的活动对象。在执行完毕以后,其执行环境的作用域链被销毁,但是其活动对象不会被销毁,因为匿名函数的作用域链中仍然引用着这个活动对象,直到匿名函数执行完毕后,才一起被销毁。
函数表达式和函数声明
函数声明:function 函数名称 (参数:可选){ 函数体 }
函数表达式:function 函数名称(可选)(参数:可选){ 函数体 }
函数声明只能出现在程序或函数体内。从语法上讲,它们不能出现在Block(块)({ ... })中。表达式和声明存在着十分微妙的差别,函数声明会在任何表达式被解析和求值之前先被解析和求值。无论变量在函数内何处声明,在代码执行阶段,变量都会在提到函数开始执行之前被声明,而函数声明发生在更早的阶段。
var foo; if (true) { foo = function (){ console.log(1); }; }else { foo = function (){ console.log(2); }; } foo(); // 1 先声明foo变量,在代码处理的第一步,按照程序执行顺序,创建函数表达式并赋值给foo。 if (true) { function foo(){ console.log(1); } }else { function foo(){ console.log(2); } } foo(); // 2 基于Gecko的浏览器 //1 函数声明在代码处理的第一步。function foo(){ console.log(2); }会覆盖前面的操作。 alert(sum(10,10)); //20 function sum(num1, num2){ return num1 + num2; } alert(sum(10,10)); //causes an error var sum = function(num1, num2){ return num1 + num2; }; //变量sum的声明还是放在第一步处理
命名函数表达式:var bar = function foo(){};需要注意的地方:这个名字只在新定义的函数作用域内有效(IE9以前版本的IE版本中)。命名函数表达式方便调试。
var f = function foo(){ return typeof foo; // foo是在内部作用域内有效 }; // foo在外部用于是不可见的 typeof foo; // "undefined" IE5-IE8中 " function" f(); // "function"调用模式
方法调用模式
当一个函数保存为对象的一个属性时,我们称它为方法。当一个方法被调用的时候,this被绑定到该对象。如果调用表达式包含一个提取属性的动作xxx.xxx,那么它就是被当做方法来调用的。
函数调用模式
this被绑定到全局对象。
构造器调用模式
this被绑定到创建的新对象。
apply调用模式
apply允许我们选择this的值,方法接受两个参数,第一个是要绑定this的值,第二个是参数数值。第一个参数为null,undefined将会被替换成全局对象。严格模式use strict的时候不会被替换。
很多现代语言都推荐延迟声明变量,js中推荐在函数体的顶部声明函数中可能用到的所有变量。
JScript的Bug
例1:函数表达式的标示符泄露到外部作用域 typeof g; // "function" var f = function g(){}; IE9已经修复 例2:将命名函数表达式同时当作函数声明和函数表达式 typeof g; // "function" var f = function g(){};
函数声明会优先于任何表达式被解析,上面的例子展示的是JScript实际上是把命名函数表达式当成函数声明了,因为它在实际声明之前就解析了g
匿名函数匿名函数中this 一般指向window对象
XXXX.prototype.__XXX = function(){} 不是匿名函数
在编写递归函数时,使用arguments.callee (但是es5严格模式下会报错)比使用函数名安全。
函数中的变量对象就是活动对象。
无论什么时候在函数内部访问一个变量时,就会从作用域链中搜索相应变量。一般来讲,当函数执行完毕后局部活动对象将被销毁。但是闭包情况有所不同。
在createComparisonFunction()函数内部定义的匿名函数的作用域链中,不包含外部函数createComparisonFunction()的活动对象。
var compare = createComparisonFunction("name");
var result = compare(obj1, obj2);
createComparisonFunction()在执行完毕以后,其执行环境的作用域链被销毁,但是其活动对象不会被销毁,因为匿名函数的作用域链中仍然引用着这个活动对象,直到匿名函数执行完毕后,才一起被销毁。闭包会携带包含他的函数的作用域,占用内存较多。
闭包只能取得包含函数中变量最后保存的值。 function createFunctions() { var result = new Array(); for (var i = 0; i < 10; i++) { result[i] = function() { return i; }; } return result; } var funcs = createFunctions(); //every function outputs 10 for (var i = 0; i < funcs.length; i++) { document.write(funcs[i]() + "用闭包保存状态
"); } 使用匿名函数再添加一层外部函数,多了一个闭包使原来的闭包满足条件 function createFunctions() { var result = new Array(); for (var i = 0; i < 10; i++) { result[i] = function(num) { return function() { return num; }; }(i); } return result; } var funcs = createFunctions(); //every function outputs 10 for (var i = 0; i < funcs.length; i++) { document.write(funcs[i]() + "
"); }
闭包直接可以引用传入的参数,利用这些被lock住的传入参数,自执行函数表达式可以有效地保存状态。
// 这个代码是错误的,因为变量i从来就没背locked住 // 相反,当循环执行以后,我们在点击的时候i才获得数值 // 因为这个时候i操真正获得值 // 所以说无论点击那个连接,最终显示的都是I am link #10(如果有10个a元素的话) var elems = document.getElementsByTagName("a"); for (var i = 0; i < elems.length; i++) { elems[i].addEventListener("click", function (e) { e.preventDefault(); alert("I am link #" + i); }, "false"); } // 这个是可以用的,因为他在自执行函数表达式闭包内部 // i的值作为locked的索引存在,在循环执行结束以后,尽管最后i的值变成了a元素总数(例如10) // 但闭包内部的lockedInIndex值是没有改变,因为他已经执行完毕了 // 所以当点击连接的时候,结果是正确的 var elems = document.getElementsByTagName("a"); for (var i = 0; i < elems.length; i++) { (function (lockedInIndex) { elems[i].addEventListener("click", function (e) { e.preventDefault(); alert("I am link #" + lockedInIndex); }, "false"); })(i); } // 你也可以像下面这样应用,在处理函数那里使用自执行函数表达式 // 而不是在addEventListener外部 // 但是相对来说,上面的代码更具可读性 var elems = document.getElementsByTagName("a"); for (var i = 0; i < elems.length; i++) { elems[i].addEventListener("click", (function (lockedInIndex) { return function (e) { e.preventDefault(); alert("I am link #" + lockedInIndex); }; })(i), "false"); }自执行函数表达式
利用了闭包的特性,可以避免全局变量
javascript语法中()内部不能包含语句,只能包含表达式。 (function () { /* code */ } ()); // 推荐使用这个
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/91528.html
摘要:基础巩固基础总结使用已经好几年了,由于工作主要是做服务端开发,在工作中逐渐发现的使用范围原来越广泛。这里要注意,务必将基础部分掌握牢靠,磨刀不误砍柴功,只有将基础部分掌握并建立起系统的知识体系,在后面学习衍生的其他模式才能游刃有余。 基础巩固:JavaScript基础总结 使用JavaScript已经好几年了,由于工作主要是做服务端开发,在工作中逐渐发现JavaScript的使用范围原...
摘要:在定义函数的作用域外调用,得到的返回仍然是函数创建时所在的作用域的局部变量。这是因为所在的匿名函数的闭包中存放的是第一行的,而不是在循环中获得的的当前值。 原文: http://pij.robinqu.me/JavaScript_Core/JavaScript_Basics/Function.html 源代码: https://github.com/RobinQu/Pr...
摘要:之前写过一篇天学通前端开发,内容主要讲的就是前端学习路径,今天再来写一篇零基础的学习路径,希望能帮编程零基础的前端爱好者指明方向。十框架三选一,零基础的初学者强烈推荐,如果是后台转前端推荐,如果技术型前端,推荐。 之前写过一篇26天学通前端开发,内容主要讲的就是前端学习路径,今天再来写一篇零基础的JavaScript学习路径,希望能帮编程零基础的前端爱好者指明方向。 一、开发环境和Ja...
摘要:变量定义变量使用关键字变量名变量名可以任意取名,但要遵循命名规则变量必须使用字母下划线或者美元符开始。语法参数说明在消息对话框中要显示的文本返回值值。返回值点击确定按钮,文本框中的内容将作为函数返回值。 简述 本系列将持续更新Javascript基础部分的知识,谁都想掌握高端大气的技术,但是我觉得没有一个扎实的基础,我认为一切高阶技术对我来讲都是过眼云烟,要成为一名及格的前端工程师,必...
摘要:用和包裹的内容,称为字符串。关系运算符用于进行比较的运算符。强制依赖于,非强制依赖于。使用场合全局环境构造函数对象的方法闭包闭包是指有权访问另一个函数作用域中的变量的函数。所有全局对象函数以及变量均自动成为对象的成员。 1 什么是JavaScript JavaScript一种直译式脚本语言,一种基于对象和事件驱动并具有安全性的客户端脚本语言;也是一种广泛应用客户端web开发的脚本语言。...
摘要:数组创建数组数组字面量使用构造函数数组本质上是所以要判断是不是数组,需要通过判断。数组长度使用属性获取元素的个数。例如函数的对象就是这样 原文: http://pij.robinqu.me/JavaScript_Core/JavaScript_Basics/Array.html 源代码: https://github.com/RobinQu/Programing-In-...
阅读 1056·2021-11-24 09:39
阅读 1287·2021-11-18 13:18
阅读 2372·2021-11-15 11:38
阅读 1800·2021-09-26 09:47
阅读 1589·2021-09-22 15:09
阅读 1607·2021-09-03 10:29
阅读 1462·2019-08-29 17:28
阅读 2935·2019-08-29 16:30