函数的定义

首先在javascript中,函数就是对象,程序可以随意操控它们。比如,可以给它们设置属性,甚至调用它们的方法。函数使用function关键字来定义。它既可以用在函数定义表达式,也可以用在函数声明语句中。函数声明function后面必须要更上函数名称也就是所谓的函数名称标识符。如果是函数表达式函数名称标识符可有可无。这段重点是函数是对象,所以函数表现出来的种种行为你想想成对象,那么很多疑惑可能就恍如昨日初见。

函数调用

4种方式来调用javascript函数:

1.作为函数

就是函数名称后加上圆括号加上参数列表 例如 func(2,3); 这里需要说明的是如果函数里有没有return obj;那么改函数返回值都是undefined除非返回就是undefined值。每个函数都有默认的返回值undefined;除非给予返回值。

2.作为方法

如果一个对象的属性被赋值为一个函数表达式,那么该函数就被当作一个方法,而不是作为一个普通函数来调用了。

例如:o.m=f; o.m();

3.作为构造函数

如果函数或方法调用之前带有关键字new,它就是构造函数调用,构造函数调用和普通的函数调用以及方法调用在实参处理,调用上下文和返回值方面都有不同。 构造函数通常不会使用return关键字,它们通常初始化新对象。

4.通过它们的call()和apply()方法间接调用

再次强调javascript中的函数也是对象,和其他javascript对象一样,函数对象也可以包含方法,其中每个函数都都有两个很熟悉不过的函数call()和apply()可以用来间接地调用函数。指定上下文this值,指定参数列表。后者传入参数时需要按照数组的形式传入参数。

函数的实参对象

如果在调用方法时少传参数,那么其余参数都将置为undefined。那么如何知道到底传了多少参数呢,实际的参数到底是多少个呢?在函数体内,标识符arguments就是指向实参对象的引用,实参对象视一个类数组对象。

例如

  1. function f(x,y,z)
  2. {
  3. if(arguments.length!=3){
  4. throw new Error(“arguments length is should be 3”);
  5. }
  6. }

arguments.length是指实参个数,而f.length是指形参的个数

callee和caller属性

callee属性指代当前正在执行的函数,caller可以访问调用栈

浅说闭包

现在不得不扯到闭包,javascript采用词法作用域,就是说函数的执行依赖于变量作用域,这个作用域是在函数定义时决定的,而不是函数执行时决定的。为了实现这种词法作用域,javascript函数对象的内部状态不仅包含函数逻辑代码,还必须引用当前的作用域链。函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性就叫做闭包。函数定义时的作用域链在调用函数时依然有效,但是这并不影响闭包。

首先上一段简单的代码:

  1. var scope=”global scope”;
  2. function f(){
  3. var scope=“local scope”;
  4. function func(){return scope;}
  5. return func();
  6. }
  7. console.log(f()); //”local scope“

简单解释一下,关键是变量scope在函数func定义的时候就在同一个作用域链中,而var scope=”global scope”;是在最外层的作用域中,一般都在作用域中都会存在一个变量对象来专门存放作用域链,全局变量肯定是最先被存放就进去,即压入栈底,而此时在执行调用func就会找最近的变量scope找到了,立马返回。所以就会是local scope不知道我的语言组织你能明白么?

  1. var scope=”global scope”;
  2. function f(){
  3. var scope=“local scope”;
  4. function func(){return scope;}
  5. return func;
  6. }
  7. console.log(f()());

请问结果是多少?

这个时候将javascript词法作用域的基本规则体现的很淋漓尽致,javascript函数执行用到了作用域链,这个作用域链式函数定义的时候创建的。嵌套的函数func()定义在这个作用域链里,其中变量scope一定是选取最近的局部变量,不管任何时候执行func(),这种绑定在执行func()时依然有效,因此返回为”local scope”. 多个函数共享一个作用域

  1. function counterfun(){
  2. var n=0;
  3. return{
  4. count:function(){return n++;},
  5. reset:function(){return n=0;}
  6. };
  7. }
  8. var c=counterfun(),d=counterfun();
  9. console.log(c.count()); //0
  10. console.log(c.reset()); //0
  11. console.log(d.count()); //0
  12. console.log(c.reset()); //0
  13. console.log(d.count());//

分析:因为函数count和reset共享一个属性,所以如果c.count()和c.reset()都会改变n的值并且相互影响,但是影响不了d.count()和d.reset()因为它们创建了各自独立的作用域链。 但是为什么n的值会被保存下来呢?此时你再回过头看看scope变量的那个例子道理一样,用return返回函数时都已经将私有变量保存起来了,下次再执行时肯定还是取这段作用域中的变量来操作。

易出错且经典的例子

如下:

  1. function constfuncs(){
  2. var funcs=[];
  3. for(var i=0;i<10;i++)
  4. funcs[i]=function(){return i;};
  5. return funcs;
  6. }
  7. var funcs=constfuncs();
  8. console.log(funcs[5]());//输出是什么呢?

这个应该不会出错吧。必须是10,因为这里所有的函数funcs[i]都共享一个作用域链其中变量i同样是共享。所以最终是循环结束的最大值10 那接下来的这个呢?

  1. function constfunc(v){return function(){return v;};}
  2. var funcs=[];
  3. for(var i=0;i<10;i++) funcs[i]=constfunc(i);
  4. console.log(funcs[5]());//输出是什么呢?

输出是5,结果是我们预期的。 这里如果按照所有的函数作用域是定义的时候就确定了的,理解起来比较费劲么,不管你信不信,反正我是中枪了。 从函数嵌套来理解,因为函数中返回函数嵌套时必须会将函数及其作用域链保存起来,这样就新创建了一个作用域链,其中的变量i也就被保存起来赋值给v了,每每return一次就会新创建一个作用域链。所以得到的v就是当时保存的i值。

prototype属性

每个函数都用一个prototype属性,请记住它是函的一个属性,尽管这个prototype我们总是称之为对象,但是它确实是函数的一个对象。它就称之为原型对象,不管你是否打算将这个函数作为构造函数来用。那问题来了,为啥我们要关注prototype属性呢?

1.原生构造函数(如 Object()/Array()/Function()等)使用prototype属性,以便让构造函数实力继承属性和方法。

2.当用户自定义构造函数时,可以像javascript原生对象那样使用继承。

3.可以借用别人编写的优秀代码的时候继承赋值过来自己用

4.通过使用原型继承,我们可以创建有效的对象实例,并且使用相同的方法,这样就节省了很多代码。

结束语

本节重点是函数是对象,所表现出来的一些特性,同时函数作用域链相关的闭包这4个例子应该是堪称经典了,以后可以经常看看,还有比较重要的作用域链等等,以后再深入了解,再继续分享。同时如果有错误,还请指出。今天看了乐嘉书中,觉得有一句话说的挺好的,我全力回顾了自己曾有的梦想,对比已实现的和没实现的,终于发现,梦想都与行动有关,不动就是幻想,动了就是梦想,动到底梦想就实现了。也许我做的梦,刚好也是你的梦,果真如此,此刻开始,你我就算是同梦中人了。如果你觉得对你有所帮助,推荐一下,给我下次写作的动力。

ps: 给大家介绍一个新词(不要问我是谁,请叫我好人)。

  路见不平   

  旧意:指走在路上遇见不公平的事情   

  新意:指走在路上在一大波平胸妹子中发现一个大波妹子   

  例句:路见不平,拔屌想护

私人定制javascript中函数小知识点的更多相关文章

  1. 私人定制javascript中对象小知识点(Only For Me)

    废话不多讲,先上笑话,然后再,.看懂这个的说明你的节操已经不再了. 晚饭后去理发店理发...割了吧...老板问我怎么剪,我悠悠的来一句往帅了剪...高潮往往令人想不到....旁边一在焗油烫头发的大妈说 ...

  2. 私人定制javascript中数组小知识点(Only For Me)

    先上笑话,1.刚看到一个游泳的,想起公司组织去三亚旅游,老板跳海里,各种挣扎,捞上来老板第一句话:我记得我会游泳的啊. 2.媳妇说:老公对不起,我把你新买的自行车撞散架了! 老公:没事宝贝,你若安好, ...

  3. Javascript中函数的四种调用方式

    一.Javascript中函数的几个基本知识点: 1.函数的名字只是一个指向函数的指针,所以即使在不同的执行环境,即不同对象调用这个函数,这个函数指向的仍然是同一个函数. 2.函数中有两个特殊的内部属 ...

  4. 私人定制自己的linux小系统

     私人定制自己的linux小系统 一.前言    linux操作系统至1991.10.5号诞生以来,就源其开源性和自由性得到了很多技术大牛的青睐,每个linux爱好者都为其贡献了自己的一份力,不管是在 ...

  5. JavaScript中函数的调用!

    JavaScript中函数的调用! 1 普通函数 // 1 普通函数 function fn() { console.log(123); } // 函数名 + 一个小括号! 或者 函数名.call() ...

  6. JavaScript中函数的定义!

    JavaScript中函数的定义! 1 自定义函数(命名函数) function fun() {}; 2 函数表达式(匿名函数) var fun = function () {}; 3 利用 new ...

  7. JavaScript中函数函数的定义与变量的声明<基础知识一>

    1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...

  8. JavaScript中函数的形参和实参的实现原理剖析

    我们都知道JS里面参数的传递是可以不一样的,比如我们有一个函数: <script type="text/javascript"> function one(a,b,c) ...

  9. JavaScript apply函数小案例

    //回调函数1 function callback(a,b,c) { alert(a+b+c); } //回调函数2 function callback2(a,b) { alert(a+b); } / ...

随机推荐

  1. 安装Microsoft .NET Framework 3.5 Service Pack 1回报1603错

    server升级了一下系统补丁(360安装),所有发现.net无法打开网站,提示" 因为无法创建应用程序域,因此未能运行请求.错误: 0x80070002 系统找不到指定的文件. " ...

  2. 【Linux探索之旅】第一部分第四课:磁盘分区,并完成Ubuntu安装

    内容简介 1.第一部分第四课:磁盘分区,并完成Ubuntu安装 2.第一部分第五课预告:Unity桌面,人生若只如初见 磁盘分区 上一课我们正式开始安装Ubuntu了,但是到了分区的那一步,小编却戛然 ...

  3. leetcode第一刷_Maximum Depth of Binary Tree

    这道题预计是ac率最高的一道了.你当然能够用层序遍历,我佩服你的耐心和勇气.由于看到别人的三行代码,会不会流眼泪呢.. class Solution { public: int maxDepth(Tr ...

  4. HDFS建筑与shell操作

    一个.hadoop1.1.0演示 hadoop它适合于大容量数据存储和分布式计算平台 hadoop核心由hdfs和mapreduce组成 hdfs这是一个主从结构,仅有一个.是namenode:从节点 ...

  5. POJ 2112 Optimal Milking (二分 + floyd + 网络流)

    POJ 2112 Optimal Milking 链接:http://poj.org/problem?id=2112 题意:农场主John 将他的K(1≤K≤30)个挤奶器运到牧场,在那里有C(1≤C ...

  6. P/Invoke与逆向P/Invoke

    1.在在 C# 中通过 P/Invoke 调用Win32 DLL这篇文中,详细介绍了P/Invoke的基本知识以及使用. 2.InAttribute和OutAttribute特性与C#中ref和out ...

  7. OpenGL路(四)自制的图形功能(立方体、汽缸、圆锥)

    #include <gl/glut.h> #include <gl/GLU.h> #include <gl/GL.h> #pragma comment(lib, & ...

  8. Vivado的helloword计划(一个):硬件project部分

    硬件平台:ZedBoard 软件平台:vivado2013.3 本演示样例通过综合.实现,生成比特流,发送到SDK实现. 启动vivado而且创建一个项目 依据提示操作一步步创建新项目的时候记得选择R ...

  9. Instll meld in windows

    在linux下用meld感觉颇为不错,但是在windows上真是折腾老久.p4merge也试了试, 但还是meld用起来更顺手. 使用 https://wiki.gnome.org/Meld/Wind ...

  10. spring+websocket综合(springMVC+spring+MyBatis这是SSM框架和websocket集成技术)

    java-websocket该建筑是easy.儿童无用的框架可以在这里下载主线和个人教学好java-websocket计划: Apach Tomcat 8.0.3+MyEclipse+maven+JD ...