zoukankan      html  css  js  c++  java
  • 对js中Function的浅见

    它到底是什么

    String Array 都是系统内置对象(已经定义好,可以直接使用)当然,这货也是一样,我们之前定义的函数,其实就是一个这货的实例。

    JS中,所有的对象都是由函数实现的,函数的数据类型是objectSo,我们以前定义的函数也是一个对象。

    几种写法

     1  function fn1(a,b){
     2   return a+b;
     3  }
     4 
     5   //前面表示参数,后面表示函数语句
     6   var fn2 = new Function("a","b","return a+b");
     7 
     8   // 匿名函数
     9   var fn3=function(a,b){
    10     return a+b;
    11   }
    12 
    13 
    14   console.log(fn1(1,2));
    15   console.log(fn2(1,2));
    16   console.log(fn3(1,2));    // 注意,一定要在声明函数的后面调用

    另外,如果函数没有明确的返回值,或者调用了没有参数的return,那么它真正返回的值是undefined

     1 function fn(){
     2   //.....
     3 }
     4 
     5 
     6 function fn1(){
     7   return;
     8 }
     9 
    10 
    11 console.log(fn()===undefined);  // true
    12 console.log(fn1()===undefined); // true

    arguments  

    arguments只有在代码运行的时候才起作用,它是一个数组(准确的说是伪数组),保存函数的参数。

     1 function fn(){
     2     var sum=0;
     3     for(var i=0;i<arguments.length;i++){
     4         sum+=arguments[i];
     5     }
     6     return sum;
     7   }
     8 
     9   var sum = fn(1,2);
    10   var sum2 = fn(1,2,3);
    11   console.log(sum);      // 3
    12   console.log(sum2);     // 6
    13 
    14   function fn1(a,b,c,d){
    15       console.log(arguments.length);
    16       console.log(arguments[0]);
    17   }
    18 
    19   fn1();                    //  0 、  undefined
    20   fn1(1);                   //  1 、 1
    21   fn1('a',2);               //  2 、 a
    22   fn1('李志',2,3);          //  3 、 李志
    23   fn1('李B',2,2,3,4,4);     //  6 、 李B

    Length

    我们需要了解两个东东,形参与实参(不同的资料书籍可能叫法有所差异)

    形参:函数定义的时候的参数  实参:调用函数的时候传递的参数

    length指的是形参个数   arguments.length指的是实参个数

    1  function fn(a, b) {
    2     console.log(fn.length);
    3     console.log(arguments.length);
    4  }
    5 
    6 fn(1, 2);  // 2   2
    7 fn(1);     // 2   1

    call  apply

    1,借用另一个对象的方法  2,替换this指向

    Apply方法  调用函数,并用指定对象替换函数的this值,同时用指定数组替换函数的参数。

    Call方法    调用一个对象的方法,用另一个对象替换当前对象。

     1     //对象1
     2     var obj1={
     3         getAllStudentsNumbers:function(sum,sum1){
     4             return sum+sum1}
     5     };
     6 
     7     //对象2
     8     var obj2={
     9         getDetail:function(){
    10             return {name:'阿拉三',age:'18'}
    11         }
    12     };
    13     console.log(obj1.getAllStudentsNumbers.call(obj2,10,200));      // 210
    14     console.log(obj1.getAllStudentsNumbers.apply(obj2,[10,200]));   // 210

    Function.apply(obj,args)方法能接收两个参数
    obj:这个对象将代替Function类里this对象
    args:这个是数组,它将作为参数传给Functionargs-->arguments

    我们通过如下方式将其转换成数组

    1 /* slice : 截取数组,返回的还是数组,这里我们截取全部  */
    2 var divs = document.getElementsByTagName("div")
    3 var domNodes =  Array.prototype.slice.call(divs);

    还可以实现继承,在上篇文章中说过,这里不做赘述。

    caller callee

    caller属性 获取调用当前函数的函数。caller属性只有当函数正在执行时才被定义。

    返回函数调用者,主要用于察看函数本身被哪个函数调用.

     1     function fn() {
     2         //判断某函数是否被调用
     3         if (fn.caller) {
     4             alert(fn.caller.toString());
     5         } else {
     6             alert("函数直接执行");
     7         }
     8     }
     9 
    10     function fn1() {
    11         fn();
    12     }
    13     fn1();
    14     fn();

    callee属性 返回正被执行的 Function 对象,即指定的Function 对象的正文。

    如下是一个递归算法 计算 1+2+3+4+...+n

    什么是递归?    可以这样理解,一个方法,自己调用自己,用上一次调用得出的结果作为这次的参数。

    传统方式的缺点:

    1、破坏了,零重复法则,当一旦函数名称更改,需要更改多处

    2、fn是一个全局变量,fn内部一般使用局部变量,而这里是一个全局变量,这是一个潜在的全局变量污染

    1 var fn=function(n){
    2     return n>0 ? n+fn(n-1) : 0;
    3 }
    4 console.log('采用传统方式:'+fn(10));

    优点:这样就让代码更加简练。又防止了全局变量的污染

    1 var fn=(function(n){
    2     return  n>0 ? n+arguments.callee(n-1) : 0;
    3 })(10);
    4 console.log('采用callee方式: '+fn);

    constructor prototype

    constructor属性,就是用来构造对象实例的函数引用。

    prototype属性,获取对象的原型。

    每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。

     contructorprototype属性是系统自动生成的。但本质上只是是函数对象的属性而已。

    对象是一个函数,而函数对象含有contructorprototype等属性,

    那么实例化的过程就是拷贝构造函数属性的过程,所以每个实例自然就拥有了contructorprototype这两个属性。

    自定义对象:函数实现的--函数又是Function的一个实例,所以这个自定义对象含有Function对象的一切属性和方法

    1 var product = function(){}
    2 /*自动有一个 prototype属性 它是一个对象--- 原型对象*/
    3 /* product.prototype也是对象,对象都是函数实现的,这货也包含Function对象的一切属性和方法,所以他也有。*/
    4 product.prototype.buy=function(){}
    5 product.prototype={}

    bind  

    Bind方法,创建具有与原始函数相同的主体的绑定函数。 在绑定功能中,this对象解析为传入的对象。 该绑定函数具有指定的初始参数。

    为了能在改变了上下文之后继续引用到this,大家通常选择使用self that _this 等方式先保存起来。这是完全可以的,现在有了bind:

     

     1 var obj={
     2       fn1:function(){
     3         console.log(1);
     4       },
     5       fn2:function(){
     6         console.log(2);
     7       },
     8       fn3:function(fn){
     9         fn();
    10         console.log(3);
    11       },
    12       fn4:function(){
    13         // var that=this;           // 还保存吗?
    14         // this.fn3(function(){
    15         //   console.log(4);
    16         //   that.fn1();
    17         //   that.fn2();
    18         // });
    19         this.fn3(function(){
    20           console.log(4);
    21           this.fn1();
    22           this.fn2();
    23         }.bind(this));        //  咦,发生什么?
    24       },
    25     }
    26     obj.fn4();

    再看一眼:

    1  var foo={
    2       x:3,
    3     }
    4     var bar=function(){
    5       console.log(this.x);
    6     }
    7     bar();
    8     var boundFunc=bar.bind(foo);
    9     boundFunc();

    想到了什么?call? apply? 没错,看下面三者的区别:

    1 fn1.hello.call(fn2,1,2,3);
    2 fn1.hello.apply(fn2,[1,2,3]);
    3 fn1.hello.bind(fn2)(1,2,3);

    好消息是,IE8以下并不支持。肿么办?  

    没关系,大牛们写好了,我们来看一下

     1 if (!Function.prototype.bind) {
     2         Function.prototype.bind = function (oThis) {
     3           if (typeof this !== "function") {
     4             throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
     5           }
     6         var aArgs = Array.prototype.slice.call(arguments, 1),
     7           fToBind = this,
     8           fNOP = function () {},
     9           fBound = function () {
    10             return fToBind.apply(this instanceof fNOP  ? this : oThis || this ,
    11                                  aArgs.concat(Array.prototype.slice.call(arguments)));
    12           };
    13           fNOP.prototype = this.prototype;
    14           fBound.prototype = new fNOP();
    15           return fBound;
    16 
    17         };
    18       }

    最后:

    JS中,函数的使用是非常之灵活,比如闭包、立即函数、等等等等,以后有机会专门讨论。

  • 相关阅读:
    git线上操作
    IDEA快捷方式
    Java 四种线程池
    java 获取当前天之后或之前7天日期
    如何理解AWS 网络,如何创建一个多层安全网络架构
    申请 Let's Encrypt 通配符 HTTPS 证书
    GCE 部署 ELK 7.1可视化分析 nginx
    使用 bash 脚本把 AWS EC2 数据备份到 S3
    使用 bash 脚本把 GCE 的数据备份到 GCS
    nginx 配置 https 并强制跳转(lnmp一键安装包)
  • 原文地址:https://www.cnblogs.com/luqin/p/5221911.html
Copyright © 2011-2022 走看看