深入认识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));//function
alert(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”。

       //function
alert(typeof(Function));
alert(typeof(new Function()));
alert(typeof(Array));
alert(typeof(Object)); //object
alert(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,2
Myfunc(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);// function 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));//
alert(myFunc(1,2));//

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

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

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

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

     //apply call
function 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);//
var 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();// obj2.getP=obj1.getP;//函数对象赋值给函数对象
obj2.getP();//
//由此可见,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();//

JS OOP -02 深入认识JS中的函数的更多相关文章

  1. js oop中的三种继承方法

    JS OOP 中的三种继承方法: 很多读者关于js opp的继承比较模糊,本文总结了oop中的三种继承方法,以助于读者进行区分. <继承使用一个子类继承另一个父类,子类可以自动拥有父类的属性和方 ...

  2. JS OOP -04 JS中的公有成员,私有成员和静态成员

    JS中的公有成员,私有成员和静态成员 a.实现类的公有成员 b.实现类的私有成员 c.实现类的静态成员 a.实现类的公有成员 之前定义的任何类型成员都属于公有成员的范畴,该类的任何实例都对外公开这些属 ...

  3. 画布跟js.oop

    <Canvas> 是HTML5中新出现的一个元素.就是可以通过  JS绘制图形. 画布(Canvas)是一个没有内容也没有边框的矩形区域.我们可以控制里面的每一个像素. 下面我们首先定义一 ...

  4. 【02】Node.js 安装配置(OK)

    [02] Node.js 安装配置 本章节我们将向大家介绍在window和Linux上安装Node.js的方法. Node.js安装包及源码下载地址为:http://www.nodejs.org/do ...

  5. js如何实现动态在表格中添加标题和去掉标题?

    js如何实现动态在表格中添加标题和去掉标题? 一.总结 1.通过table标签的createCaption(),deleteCaption()方法实现. document.getElementById ...

  6. Three.js 快速上手以及在 React 中运用[转]

    https://juejin.im/post/5ca22692f265da30a53d6656 github 的地址 欢迎 star! 之前项目中用到了 3D 模型演示的问题,整理了一下之前学习总结以 ...

  7. JS判断网页是否在微信中打开/

    JS判断网页是否在微信中打开,代码如下: <script type="text/javascript"> function is_weixn(){ var ua = n ...

  8. JS中同名函数有效执行顺序

    html中如果出现函数同名时:如果有多个外部引入的js文件,例如a.js和b.js(引入顺序假定是a.js,然后是b.js),同时html中本身也有内部的js.那么针对 出现函数名一样的情况时,无论他 ...

  9. 在JS函数中执行C#中的函数、字段

    1.调用字段 cs文件的代码: ; protected void Page_Load(object sender, EventArgs e) { id = ; } js页面的代码: function ...

随机推荐

  1. LINUX增加SWAP分区---install_oracle

    我们都知道在安装Linux系统时在分区时可以分配swap分区,而系统安装后(在运行中)如何建立或调整swap分区呢?在装完Linux系统之后,建立Swap分区有两种方法.1.新建磁盘分区作为swap分 ...

  2. 【Java】能提高日常工作效率的一些Java函数

    自编工具总是临时抱佛脚来得顺溜,宜常备手边以提高工作效率: package com.hy; import java.io.File; /** * 日常工作常用的一些工具方法 * @author 逆火 ...

  3. 寻找丢失的微服务-HAProxy热加载问题的发现与分析 原创: 单既喜 一点大数据技术团队 4月8日 在一点资讯的容器计算平台中,我们通过HAProxy进行Marathon服务发现。本文记录HAProxy服务热加载后某微服务50%概率失效的问题。设计3组对比实验,验证了陈旧配置的HAProxy在Reload时没有退出进而导致微服务丢失,并给出了解决方案. Keywords:HAProxy热加

    寻找丢失的微服务-HAProxy热加载问题的发现与分析 原创: 单既喜 一点大数据技术团队 4月8日 在一点资讯的容器计算平台中,我们通过HAProxy进行Marathon服务发现.本文记录HAPro ...

  4. 淘宝npm镜像安装失败的问题

    一:背景 心血来潮要简单搞一搞前端运行.打包的东西.结果第一步通过npm安装淘宝npm的时候就出问题了,如图: 二:解决方法 图片显示有点垃圾,但是看出来“Missing write access t ...

  5. div和span显示在同一行

    div和span标签的区别 div  是块级元素标签,独占一行,后面跟的内容换行显示 span  是内联元素标签,后面可以跟其他显示内容,不独占一行 display属性可以改变内联元素和块级元素的状态 ...

  6. (十一)Centos之帮助命令

    帮助命令man  (manual) 比如我们可以看下man命令的解释 [root@localhost ~]# man man MAN(1)                               ...

  7. Spring Cloud(6.2):搭建OAuth2 Client

    配置web.xml 添加spring-cloud-starter-security,spring-security-oauth2-autoconfigure和spring-boot-starter-o ...

  8. Windows下免费的屏幕录制软件——EV录屏——推荐

    EV录屏,现在使用起来效果还不错. 软件地址:https://www.ieway.cn/evcapture.html

  9. Mac安装7Z以及Mac下查看隐藏文件夹

    一:Mac下安装7Z: 1:brew直接安装解压工具 $ brew search 7z 会搜索到: ==> Formulae p7zip 2:$ brew install p7zip       ...

  10. 关于远程链接 redis的坑·

    今天遇到了一个问题,在redis.conf 中 将 bind: 注释掉bind 127.0.0.1 仍然不行 其实是要把bind 127.0.0.1 改为 0.0.0.0 才行 下面附赠详细过程 查看 ...