在javaScript中,函数是一个很基础的对象,同样也是非常随意,定义起来很随意,用起来那是更加随意。以下说明在javaScript中声明一个函数那是多麽的随意

  1. function fun1() {//声明一个函数
  2. }
  3. function() { //声明一个匿名函数
  4. }
  5. var fun2 = function() {//声明一个变量指向一个匿名的函数表达式
  6. }
  7. var fun3 = function fun4() {//声明一个变量指向一个非匿名的函数表达式
  8. }
  9. function fun5() {
  10. return function() { //返回一个匿名函数
  11. }
  12. }

那function和var的区别有哪些?我们不讨论深奥的,我们看下哪些运行结果

  1. alert(typeof fun1); //function
  2. alert(typeof fun2); //undefined
  3. alert(typeof fun3); //undefined
  4. alert(typeof fun4); //function
  5. alert(typeof fun5); //function
  6. function fun1() {//声明一个函数
  7. }
  8. function() { //声明一个匿名函数
  9. }
  10. var fun2 = function() {//声明一个变量指向一个匿名的函数表达式
  11. }
  12. var fun3 = function fun4() {//声明一个变量指向一个非匿名的函数表达式
  13. }
  14. function fun5() {
  15. return function() { //返回一个匿名函数
  16. }
  17. }

我们可以看到function比var还要优先。
我们之前说变量的时候已经说过,一个变量可以被反复赋值,对于函数来说,这可以吗?
对于习惯在静态语言下写代码的人,看到如下代码估计要气愤了,这个是啥破代码?

  1. function fun1() {
  2. alert("Y");
  3. }
  4. function fun1() {
  5. alert("N");
  6. }

但事实上,这个代码是可以执行的,执行的结果暗示我们函数的名称会被自动的作为对象的一个属性,函数体就是属性的值了

  1. fun1(); // n
  2. this["fun1"](); // n
  3. this.fun1(); // n
  4. window["fun1"](); // n
  5. window.fun1(); // n

现在我们把两个因素合起来看看,function在所有执行代码前先编译,且后面的function会覆盖前面的function定义,那么,如下的代码执行的是?

  1. var input = 5;
  2. switch (input) {
  3. case 10:
  4. function fun1() {
  5. alert(10);
  6. }
  7. break;
  8. case 5:
  9. function fun1() {
  10. alert(5);
  11. }
  12. break;
  13. default:
  14. function fun1() {
  15. alert("default");
  16. }
  17. break;
  18. }

令人恼怒的是,在chrome和IE下执行的是我们前面的推断,function在所有执行代码前先编译,且后面的function会覆盖前面的function定义结果是

  1. fun1(); //default

而FireFox把if中的语句作为执行快,运行时才编译,所以他的结果是

  1. fun1(); //5

为了解决这个问题,你需要吧动态分配的函数以函数的表达式来执行,避免编译器对函数还没有执行到就已经分配了,比如

  1. var input = 5;
  2. switch (input) {
  3. case 10:
  4. fun1 = function() {
  5. alert(10);
  6. }
  7. break;
  8. case 5:
  9. fun1 = function() {
  10. alert(5);
  11. }
  12. break;
  13. default:
  14. fun1 = function() {
  15. alert("default");
  16. }
  17. break;
  18. }

说到函数的表达式,那什么是函数的表达式呢?简单的说,在右边的都是函数的表达式

  1. var fun1 = function() {//函数表达式
  2. }
  3. var fun1 = function fun2() {//函数表达式
  4. }
  5. var obj = {
  6. Do: function() {//函数表达式
  7. }
  8. }
  9. new function() {//函数表达式
  10. }
  11. function fun3() {
  12. return function() { //函数表达式
  13. }
  14. }

还有两种就是在()内和【】内,原谅我为了看的清楚了些,用了中文的【】,具体看下代码就ok了

  1. (function() { });
  2. [function() { } ];

函数表达式和一般的表达式的值一样,都是执行到的时候才编译,不过有一个例外,就是非匿名的函数表达式

  1. var fun3 = function fun4() {//声明一个变量指向一个非匿名的函数表达式
  2. }

上面的代码如果你没有特定的含义,求你最好不要这么写,因为会出现你想不到的情况

  1. alert(fun3 === fun4);

上面的结果是无论如何都超过了初学者的想法:在IE中式false,在Chrome或FireFox中是错误

对于Chrome或FireFox原因比较明显,也就是说,fun4被赋值后就立即抛弃了

  1. alert(typeof fun3); //function
  2. alert(typeof fun4); //undefined

在IE中

  1. alert(typeof fun3); //function
  2. alert(typeof fun4); //function

这一点是IE的错误,但是从结果可以得知:命名函数表达式的名字在外部作用域是无效的。哪怕如下,你执行下fun3还是不行的

  1. var fun3 = function fun4() {//声明一个变量指向一个非匿名的函数表达式
  2. }
  3. fun3();
  4. alert(typeof fun3); //function
  5. alert(typeof fun4); //undefined

虽然IE是有错误,但是IE透露了一个信息,非匿名的函数表达式由于函数有名称,被优先的分配了。看看我们最上面的函数定义声明的案例中的fun4

这么一来,如果你一不小心的话

  1. function fun1() {
  2. alert("A");
  3. }
  4. var count = 2;
  5. var input = 10;
  6. switch (input) {
  7. case 5:
  8. function fun1() {
  9. alert(5);
  10. }
  11. break;
  12. case 10:
  13. if (count % 2 == 0) {
  14. function fun1() {
  15. alert("odd");
  16. }
  17. }
  18. else {
  19. function fun1() {
  20. alert("even");
  21. }
  22. }
  23. }
  24. fun1();

这些代码的执行会不会出乎你的意料呢?注意上面的代码在不同的浏览器中得到的是不同的。再看看下面的代码

  1. var fun1 = function(x) {
  2. if (x < 10) {
  3. return function fun2() {
  4. alert("min");
  5. }
  6. }
  7. return function fun2() {
  8. alert("max");
  9. }
  10. }
  11. fun1(4)();
  12. fun1(10)();

你是不是认为执行的结果又min也有max在不同的浏览器中,错了,这次他们都很正常的预期。说明return将后面的非匿名函数表达式有效的让编译器作为表达式而不是声明来看待了。
那么非匿名的函数表达式有什么问题嘛?
我们来看一个demo

  1. var fun1 = function fun2() {
  2. alert("OK");
  3. }
  4. fun1(); // OK
  5. fun2(); //在IE中弹出OK,在Chrome和FireFox中错误

既然只有IE支持,那我们在IE上继续点实现,学习一个种语言,千万不要被书上的条条框框限制,最好是多多多多的天马行空的乱想点不正经的代码出来,有静态语言经验的人都会被下面的代码的执行结果吓死

  1. var fun1 = function fun2() {
  2. alert("OK");
  3. }
  4. fun1 = function() {
  5. alert("fun1");
  6. }
  7. fun1(); //fun1
  8. fun2(); //OK

fun1和fun2竟然不是指向同一个对象,或者说内存地址。所以,如果说这个是IE的bug,那么我们幸好Chrome和FireFox不支持非匿名的函数表达式具有实在的意义,上帝保佑,这样我们尽可能的不要写出非匿名的函数表达式就可以避免很多问题了。不过也有说法是说,非匿名的函数表达式在递归的时候有用,以下代码告诉我们匿名函数表达式也一样可以递归的哦,亲。

一个匿名函数使用递归的阶乘demo

  1. alert((function(x) {
  2. if (x > 1) {
  3. return x * arguments.callee(--x);
  4. }
  5. else {
  6. return 1;
  7. }
  8. } (10)));// 3628800

以上说了一大堆,就是为了要告诉你一个关键事实:函数表达式只能在代码执行阶段创建而且不存在于变量对象中,换个更通俗的说法是:函数表达式只有当执行到的时候,其才存在,否则是当他不存在的。

我们用匿名函数除了是return和内部赋值外,还常常用来做一次性执行的自执行函数。以下就匿名函数自执行的demo

  1. (function() {
  2. alert("OK");
  3. })();
  4. (function() {
  5. alert("OK");
  6. } ());

上面的两种写法在所有浏览器中都可以执行,随你喜欢什么方式,只要固定就好,有些书推荐使用方式2,我不清楚为什么,反正对我来说很随意的使用了。
匿名函数也可以传参

  1. (function(x) {
  2. x--;
  3. alert(x);
  4. } (10));

匿名函数往往非常好用,我们可以把匿名函数作为一个参数来传递,有时候,我们传递的的确是函数的本身,有时候我们传递的是函数的结果,如果是函数的结果,那么函数的自调用就非常cool了

先看看传递函数,以下的代码会生成一组li元素,并且背景色是依据前一个li的背景色加一点点,这样看上去就是一个渐变区域。当然,真的画渐变区域不必这样处理。

  1. $(
  2. function() {
  3. $(":button").click(
  4. function() {
  5. for (var i = 0; i < 10; i++) {
  6. var ol = $("<li>").css({ width: 30, height: 30 }).
  7. addClass("left").
  8. appendTo("ol");
  9. ol.css("backgroundColor",
  10. function(index, value) {
  11. index = $("ol>li").index(this);
  12. var r, g, b = 0, colorValue = "";
  13. if (index == 0) {
  14. r = parseInt(Math.random() * 256);
  15. g = parseInt(Math.random() * 256);
  16. b = parseInt(Math.random() * 256);
  17. }
  18. else {
  19. colorValue = $("ol>li").eq(index - 1).css("backgroundColor").
  20. toString().replace("rgb(", "").replace(")", "")
  21. r = parseInt(colorValue.split(",")[0]);
  22. g = parseInt(colorValue.split(",")[1]);
  23. b = parseInt(colorValue.split(",")[2]) + 5;
  24. }
  25. return "rgb(" + r + "," + g + "," + b + ")";
  26. }
  27. );
  28. }
  29. }
  30. );
  31. }
  32. );

我们再看一个例子,匿名函数的自调用在传参的使用的用处。我们点击一个div的时候,我创建了一个新的div,这个div的样式完全的复制了被点击的div的样式,注意我的css函数中传递了一个匿名的自调用函数,这个函数返回了一个对象

  1. $(
  2. function() {
  3. $("div").click(
  4. function() {
  5. $("<div>").appendTo("body").css(
  6. (function(e) {
  7. var styleObj = {};
  8. for (var item in e.style) {
  9. if (e.style[item] != "") {
  10. styleObj[item] = e.style[item];
  11. }
  12. }
  13. return styleObj;
  14. } (this))
  15. );
  16. }
  17. );
  18. }
  19. );

本文转自shyleoking 51CTO博客,原文链接:http://blog.51cto.com/shyleoking/803085

当javaScript从入门到提高前需要注意的细节:函数部分相关推荐

  1. 当javaScript从入门到提高前需要注意的细节:变量部分

    到了HTML5的时代,对javaScript的要求不是降低了,而是更提高了.javaScript语言的入门非常简单,如果你有java.C#等C风格的结构化语言的基础,那javaScript你最多半天就 ...

  2. JavaScript从入门到放弃 -(五)函数进阶(高级用法)

    目录 1. 函数的定义和调用 1.1 函数定义的3种方式 1.2 函数调用方式(常见的6种) 1.2.1 普通函数的调用 1.2.2 对象中的函数调用 1.2.3 构造函数的调用 1.2.4 DOM元 ...

  3. 【Javascript 基础入门】

    目录 javascript基础入门 javascript的历史 JavaScript 与 ECMAScript 的关系 如何运行 JavaScript JavaScript 的特点 注释 单行注释 多 ...

  4. JavaScript之入门学习风云(1)

    JavaScript之入门学习风云(1) 一.js介绍 1.1.js起源与发展 1.2.js组成 二.JavaScript的使用 2.1.标签的使用 2.1.1行嵌入式 2.1.2内嵌入式 2.1.3 ...

  5. 推荐图书:《一看就会——会声会影9入门与提高》

    推荐图书:<一看就会--会声会影9入门与提高> 今年上半年写的一本书,出版了. 假如要去书店买学习会声会影9的书,推荐看到时翻一翻.如果买了这本书,有什么问题,可以问我,aaahts2@1 ...

  6. Docker 实战教程之从入门到提高 (五)

    本系列的前四篇文章,我们学习了如何在 Ubuntu 操作系统安装 Docker,并且通过实战练习,了解了 Docker 和宿主机操作系统文件目录互相隔离的实现原理,以及 Docker Volume 的 ...

  7. Docker 实战教程之从入门到提高 (四)

    本系列的前三篇文章,我们学习了如何在 Ubuntu 操作系统安装 Docker,并且通过实战练习,了解了 Docker 和宿主机操作系统文件目录互相隔离的实现原理,以及 Docker Volume 的 ...

  8. JavaScript从入门到放弃 -(七)ES6

    目录 1. ES6相关概念 1.1 什么是 ES6 ? 1.2 为什么使用 ES6 ? 2 ES6新增语法 2.1 新增关键字 2.1.1 let 关键字 小结 2.1.2 const 关键字 小结 ...

  9. JavaScript从入门到放弃 -(六)正则表达式

    正则表达式 1. 正则表达式概述 1.1 什么是正则表达式 1.2 正则表达式的特点 2. 正则表达式在JavaScript中的使用 2.1 创建正则表达式 2.1.1 通过调用 RegExp 对象的 ...

最新文章

  1. java自定义sql查询插件,Mybatis插件plugin应用测试,替换查询sql
  2. 08_传智播客iOS视频教程_Foundation框架
  3. Golang copy()函数
  4. HBase学习笔记——概念及原理
  5. java io流缓冲理解
  6. Javascript提升阶段学习
  7. 7个示例科普CPU Cache(转)
  8. 去哪网实习总结:JavaWeb配置404页面(JavaWeb)
  9. 反计算机病毒技术论文,计算机病毒反病毒技术论文
  10. 关于模电与数电的基础知识
  11. 汽车距离报警系统c语言编程,基于单片机的汽车防盗报警系统的设计本科生毕业论文.doc...
  12. [基本功练习素材]播音初学者资料—口部操,唇舌力量控制;声母韵母难点练习
  13. arduino 联动ULN2003驱动板营造夏日炫酷小风扇
  14. A Strong Baseline and Batch Normalization Neck for Deep Person Re-identification(论文笔记)(2019CVPR)
  15. 算法之排序算法(冒泡法和选择法)
  16. 国产手机支持鸿蒙系统,支持国产,支持鸿蒙!国产手机系统终于看到了希望
  17. 外网连接腾讯云mysql
  18. Eclipse Button按钮样式简单样式
  19. Unity AI 语音识别、语音合成、人机交互(一)
  20. 97整数小波压缩的FPGA实现过程

热门文章

  1. 惨烈!程序员放弃了 Python!?发生了啥?
  2. 冒号课堂 编程范式与OOP思想
  3. Spring集成spymemcached
  4. WCF4.0新特性体验(3):标准终结点(Standard Endpoints)
  5. openstack安装系列问题:window7 64位安装的virtualBox 只能选择32位的系统安装不能选择64位的系统安装...
  6. element not visible的解决方法
  7. 论文阅读--PVANET: Deep but Lightweight Neural Networks for Real-time Object Detection
  8. 标准化工作取得新突破 窄带物联网商用指日可待
  9. linux网络编程-posix信号量与互斥锁(39)
  10. OpenGL vertext shader 属性设置