深入认识JS中的函数:

1.概述,认识函数对象

2.函数对象和其他内部对象的关系

3.将函数作为参数传递

4.传递给函数的隐含参数:arguments

5.函数的apply,call方法和length属性

6.深入认识JS中的this指针

1.概述,认识函数对象

  JS中的函数不同于其他的语言,每个函数都是作为一个对象被维护和运行的。通过函数对象的性质,可以将一个函数赋值给一个变量或者将函数作为参数传递。

用法:

  function Func1(...){......};

  var Func2 = function(...){......};

  var Func3 = function Func4(...){......};

  var Func5 = new Function();

**函数对象!!

  可以用function关键字定义一个函数,并为每个函数指定一个函数名,通过函数名来进行调用。在JS解释执行时,函数都是被维护为一个对象,这就是函数对象(function object)。

  函数对象与其他用户所定义的对象有着本质的区别,这一类对象称之为内部对象,例如Date,Array,String 都属于内部对象。这些内置对象的构造器是由JS本身所定位的:通过执行 new Array() 这样的语句返回一个对象,JS内部有一套机制来初始化返回的对象,而不是由用户来指定对象的构造方式。

  在JS中,函数对象对应的类型是Function,(数组对应Array,日期对应Date),可以通过 new Function() 来创建一个函数对象,也可以通过 function 关键字来创建一个对象。

            var myArray = [];var myArray = new Array();function myFunction1(a,b){return a+b;};var myFunction = new Function('a','b','return a+b');

  以上代码,通过和构造数组对象语句的比较,可以清楚的看到函数对象本质。第一种方式,在解释器内部,当遇到这种语法时,就会自动构造一个Function对象,将函数作为一个内部的对象来存储和运行。(一个函数对象名称(函数变量)和一个普通变量名称具有同样的规范,都可以通过变量名来引用这个变量,但是函数变量名后面可以跟上括号和参数列表来进行函数的调用。var myFunction = new Function("a,b","return a+b"),这个方式可读性较差)。

  ** var funcName = new Function(P1,P2,P3...Pn,body)  参数的类型都是字符串,P1到Pn表示所创建函数的参数名称列表,body表示所创建函数的函数体语句。

  **注意,P1到Pn是参数名称的列表,即P1不仅能代表一个参数,它也可以是一个逗号隔开的参数列表。

  **JS导入Function类型并提供 new Function() 这样的语法是因为函数对象添加属性和方法就必须借助于Function这个类型。

  **函数的本质是一个内部对象!由JS解释器决定其运行方式。**

  **注意:直接在函数声明后面加上括号就表示创建完成后立即进行函数调用。返回一个number类型

            var myfunc2= function(a,b){return a+b;}(100,200);//优先级决定的,‘(’优先级大于‘=’,所以myfunc2是一个变量,而不是一个函数
            alert(typeof(myfunc2));//number
            alert(myfunc2);alert(myfunc2(10,20));//报错,myfunc2不是一个函数!

  **但是不直接调用,返回的是一个function类型

       var Myfunc2=function(a,b){return a+b;}alert(typeof(Myfunc2));//functionalert(Myfunc2(1,2));

   **注意有名函数和无名函数!

   **区别:对于有名函数,它可以出现在调用之后再定义;而对于无名函数,必须在调用之前定义。

   **因为JS是一门解释型语言,但它会在函数调用时,检查整个代码中是否存在相应的函数定义。只有通过function FuncName(...){...} 才有效,而不是无名函数。

       function Myfunc1(a,b){//有名函数return a+b;}alert(Myfunc2(1,2));//报错var Myfunc2=function(a,b){//无名函数return a+b;}alert(typeof(Myfunc2));//function

2.函数对象和其他内部对象的联系

  除了函数对象,还有很多内部对象,比如:Object,Array,Date.....这些都表示一个类型,可以通过 new 操作符返回一个对象,然而函数对象和其他对象不同,当用typeof得到一个函数对象的类型时,它仍然会返回字符串“function”,而typeof一个数组对象或其他的对象时,它会返回字符串“Object”。

       //functionalert(typeof(Function));alert(typeof(new Function()));alert(typeof(Array));alert(typeof(Object));//objectalert(typeof(new Array()));alert(typeof(new Date()));alert(typeof(new Object()));if(typeof(tt)=="function"){//判断是function类型在运行,通常的做法
                arg();}

  **new 一个Function,实际上是返回一个函数。这于其他的对象有很大的不同。其他的类型Array,Object等都会通过 new 操作符返回一个普通对象(Object)。

  **尽管函数本身也是一个对象,但它与普通的对象还是有区别的,因为它同时也是对象构造器,也就是说,可以new 一个函数来返回一个对象,所有typeof返回‘function’的对象都是函数对象,也叫构造器(constructor)。所有的构造器都是对象,但不是所有的对象都是构造器。

  **Function类型的作用,就是可以给函数对象本身定义一些方法和属性,借助于函数的prototype对象,可以方便地修改和扩充Function类型的定义。

  **Function是所有函数对象的基础,而Object则是所有对象(包括函数对象)的基础。在JS中,任何一个对象都是Object的实例。因此,可以修改Object这个类型来让所有的对象具有一些通用的属性和方法,修改Object类型是通过prototype来完成的。

       Function.prototype.Methods=function(){alert('function');}function tt(){alert('tt');}tt.Methods();tt.Methods.Methods();//递归的定义。Methods本身也是一个函数,所以它同样具有函数对象的属性和方法,                    //所有对Function类型的方法扩充都具有这样的递归性质。
            Object.prototype.getType=function(){return typeof(this);}var array1=new Array();function func1(a,b){return a+b;}alert(array1.getType());alert(func1.getType());

3.将函数作为参数传递

  函数对象的本质:就是一个内部对象!Function类型的对象,类型还是Function。

  **每个函数都被表示为一个特殊的对象,可以方便地将其赋值一个变量,再通过这个变量名进行函数调用。作为一个变量,它可以以参数的形式传递给另一个函数。

            function func1(thefunc){if(typeof(thefunc)=='function'){//
                    thefunc();}else{alert(typeof(thefunc));}}function func2(){return '123';}function func3(a,b){var result =a+b;alert(result);}function func4(a,b,c){var result =a+b+c;alert(a+b+c);}func1(func2());//执行结果传递过去func1(func2);//func2作为一个对象传递给func1的形参thefunc,再由func1内部进行thefunc的调用。//事实上,将函数作为参数传递,或者是将函数赋值给其他变量是所有事件机制的基础。//将func3传递给func1;//var t=new func3(1,2);//func1(func3);var t1 = new func3(1,2);alert(typeof(t1));

4.传递给参数的隐含参数 arguments

  当进行函数调用时,除了指定的参数外,还创建了一个隐含的对象--arguments,arguments是一个类似数组但不是数组的对象,说它类似是因为它具有数组一样的访问性质,可以用arguments[index]这样的语法取值,拥有数组长度属性length。arguments对象存储的是实际传递给函数的参数,而不局限于函数声明所定义的参数列表,例如:

       function Myfunc(a,b){alert(a);alert(b);for (var i=0;i<arguments.length;i++) {alert(arguments[i]);}}Myfunc(1,2)//显示:1,2,1,2Myfunc(1,2,3)//显示:1,2,1,2,3

  **因此,在定义函数的时候,即使不指定参数列表,仍然可以通过arguments引用到所获得的参数,这给编程带来了很大的灵活性。

  

  **arguments对象的另一个属性callee,它表示对函数对象本身的引用,这有利于实现无名函数的递归或者保证函数的封装性。

       var sum =function(n){if(1==n){return 1;}else{return n+sum(n-1);//递归的调用
                }}alert(sum(100));//arguments.callee 表示对函数对象本身的引用,有利于实现无名参数的递归或者保证函数的封装性var sum2 =function(n){if(1==n){return 1;}else{return n+arguments.callee(n-1);//arguments.callee,递归的调用
                }}alert(sum2(100));

  **callee属性并不是arguments不同于数组对象的唯一特征,以下代码:

       Array.prototype.p1 = 1;//给所以数组对象添加属性p1,初始化值为1.alert(new Array().p1);//1function func(){alert(arguments.p1);}func();//undefined 说明p1不是arguments的属性

  **arguments的length的模拟实现方法的重载

     //arguments可以实现方法的重载!function myFunc(){var result=0;if(arguments.length==2){result =arguments[0]+arguments[1];}else if(arguments.length==3){result=arguments[0]+arguments[1]+arguments[2];}/*for(var i=0;i<arguments.length;i++){result+=arguments[i];}*/return result;}alert(myFunc(1,2,3));//6alert(myFunc(1,2));//3

5.函数的apply,call方法和length属性

  JS对函数对象定义了两个方法:apply和call,它们的作用都是将函数绑定到另外一个对象上去运行,两者仅在定义参数的方式有所区别:

     Function.prototype.apply(thisArg,argArray);Function.prototype.call(thisArg,"arg1","arg2"...)

  从函数原型可以看到,第一个参数都被取名为thisArg,即所有函数内部的this指针都会被赋值为thisArg,这就实现了将函数作为另外一个对象的方法运行的目的.

     //apply callfunction func1(){this.p="func1-";this.A=function(arg){alert(this.p+arg+'<func1>');};};function func2(){this.p="func2-";this.B=function(arg){alert(this.p+arg+"<func2>");}}var obj1=new func1();var obj2=new func2();//obj1.A("byA");//正常调用//obj2.B("byB");//正常调用obj1.A.apply(obj2,["byA"]);obj2.B.apply(obj1,["byB"]);obj1.A.call(obj2,"byA");obj2.B.call(obj1,"byB");//可以看出,obj1的方法A被绑定到obj2运行后,整个函数A的运行环境就转移到了obj2,即this指针指向了obj2.//同样,obj2的函数B也可以绑定obj1运行,整个函数B的运行环境就转移到了obj1,即this指针指向了obj1.

  函数对象的属性length,它表示函数定义时所指定参数的个数,而非调用时实际传递的参数个数

     //函数对象的属性length,它表示函数定义时所指定参数的个数,而非调用时实际传递的参数个数function sum(a,b,c) {return a + b+c;}alert(sum.length);//3var t1=sum;alert(t1);

6.深入认识JS中的this指正

  this指针是面向对象程序设计中的一项重要概念,塔表示当前运行的对象.在实现对象的方法时,可以使用this指针来获得该对象的自身的引用.

  和其他语言不同,JS中的this指针是一个动态的变量,一个方法内的this指针并不是始终指向定义该方法的对象的,它可以是动态的!

      var obj1=new Object();var obj2=new Object();obj1.p=1;obj2.p=2;obj1.getP=function(){alert(this.p);}obj1.getP();//1
obj2.getP=obj1.getP;//函数对象赋值给函数对象obj2.getP();//2//由此可见,getP函数仅定义了一次,在不同的场合运行,显示了不同的运行结果.这是由this指针的变化所决定的.//在obj1的getP方法中,this就指向了obj1对象,而在obj2的getP方法中,this就指向了obj2对象,并通过this指针引用到了两个对象都具有的属性p

  **JS中的this指针是一个动态变化的变量,它表面了当前运行该函数的对象.由this指针的性质,也可以更好的理解JS中对象的本质:一个对象就是由一个或多个属性(方法)组成的集合.每个集合元素不是仅能属于一个集合,而是可以动态的属于多个集合.这样,一个方法(集合元素)由谁调用,this指针就指向谁!

  **实际上,apply方法和call方法都是通过强制改变this指针的值来实现的,使this指针指向参数所指定的对象,从而达到将一个对象的方法作为另一个对象的方法运行.

  命名空间的概念(重要)

        /** 每个对象集合的元素(即属性或方法)也是一个独立的部分,全局函数和作为一个对象方法定义的函数之间没有任何区别.* 因为可以把全局函数和变量看作为window对象的方法和属性.也可以使用new操作符来操作一个对象的方法来返回一个对象,* 这样一个对象的方法也就可以定义为类的形式,其中的this指针则会指向新创建的对象.这时对象名可以起到一个命名空间的* 作用,这是使用js进行面向对象程序设计的一个技巧.* */var namespace1 = new Object();//这里就可以把namespace1看成一个命名空间namespace1.class1 = function() {//namespace1命名空间下面的类class1//初始化对象代码
        }var obj1=new namespace1.class1();//

转载于:https://www.cnblogs.com/youguess/p/10552143.html

JS OOP -02 深入认识JS中的函数相关推荐

  1. JS子窗口调用父窗口中的函数

    很简单只需要一句话就可以了: window.opener.changeColor(); 这里的changeColor()就是父窗口中JS的一个函数 本文转自sucre03 51CTO博客,原文链接:h ...

  2. html中js定义的方法无效,javascript中定义函数有几种常用方法?

    JavaScript函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块.使用函数您能够对代码进行复用:只要定义一次代码,就可以多次使用它. JavaScript定义函数的几种常用方法: 1.使 ...

  3. h5引入不同的js文件怎样让第二个js使用第一个js文件中的函数_px2rem-loader使用及注意事项...

    1.安装lib-flexible.js: //基于vue-cli配置手淘的lib-flexible + rem,实现移动端自适应 2.安装px2rem-loader://使用 webpack 的 px ...

  4. python调用js库中的函数_Python 调用JS文件中的函数

    Python 调用JS文件中的函数 1.安装PyExecJS第三方库 2.导入库:import execjs 3.调用JS文件中的方法 Passwd = execjs.compile(open(r&q ...

  5. 美丽的闭包,在js中实现函数重载

    引言 最近在js的学习中,看到了函数重载的问题,一开始,只看到了实现代码,看着代码冥思苦想了半个小时,总算是理清了其实现的原理,也为其实现的巧妙感到赞叹,也是在自己搞懂原理之后,去网络上搜索了下,才知 ...

  6. js实现随机选取[10,100)中的10个整数,存入一个数组,并排序。 另考虑(10,100]和[10,100]两种情况。...

    1.js实现随机选取[10,100)中的10个整数,存入一个数组,并排序. 1 <!DOCTYPE html> 2 <html lang="en"> 3 & ...

  7. 微信小程序首页index.js获取不到app.js中动态设置的globalData的原因以及解决方法

    微信小程序首页index.js获取不到app.js中动态设置的globalData的原因以及解决方法 参考文章: (1)微信小程序首页index.js获取不到app.js中动态设置的globalDat ...

  8. js插件---webuploader 使用(lavarel中使用)

    js插件---webuploader 使用(lavarel中使用) 一.总结 一句话总结: 多去看几个具体使用的实例,很多blog教程都有坑,多看几个交叉印证可以没那么多坑 1.webuploader ...

  9. android js变量定义数组长度,js 声明数组和向数组中添加对象变量的简单实例

    数组有四种定义的方式 使用构造函数: var a = new Array(); var b = new Array(10); var c = new Array("first", ...

最新文章

  1. mysql半同步复制问题排查
  2. 剑指offer 算法 (递归与循环)
  3. djngo快速实现--使用Bootstrap
  4. AMD规范:简单而优雅的动态载入JavaScript代码
  5. xgboost防止过拟合
  6. qt creater创建自己的第一个小程序
  7. linux 运维视频集合
  8. The credentials you provided during SQL Server 2008 install are invalid
  9. 轻松学习 Flex 布局的小游戏
  10. Spring-全局异常拦截
  11. switch一定比if else好用吗
  12. php魔术方法例子,PHP魔术方法示例
  13. 瑞昱rtl8168网卡支持Linux吗,瑞昱 RTL8168F PCI-E专用网卡驱动,亲测可用
  14. 2021年黄石二中高考成绩查询,【黄石二中2018高考金榜】黄石二中2004届高考总结...
  15. 怎么注册自定义域名Email.cn邮箱?
  16. Tomcat重启服务器
  17. 虚幻引擎 Unreal Engine 详细笔记 根据谌嘉诚视频无遗漏总结 快速上手
  18. 关于Fiddler使用和答疑
  19. 摆脱恐惧(老俞演讲稿)
  20. laravel artisan命令大全

热门文章

  1. IReport报表分组与分组统计
  2. struts2校验再提交多条提示信息
  3. linux 主目录 配置文件
  4. 【Redis】4.Redis数据存储listsetsorted_set
  5. 性能测试工具系列(一):性能测试工具对比分析
  6. 你都知道么?Android中21种drawable标签大全
  7. [RN] React Native 调试技巧
  8. 记录第一次使用Texlive+TexStudio写论文时遇到的问题(随时更新)
  9. 通过数据库动态视图'v$',查看数据库信息
  10. D. Imbalanced Array