犀牛笔记--函数

  1 1.函数作为参数传给其他函数:
  2     data.sort(function(a,b){return a-b})
  3     //关于数组的sort函数,其回调函数返回负值,a在b之前
  4     //正值,b在a之前
  5
  6 2.函数定义好后立即调用
  7     var temp=(function(x){return x*x})(10);
  8
  9     function foo(){};//函数声明,可以提前
 10     var foo=function(){};//表达式定义函数,不能提前
 11
 12 3.JAVASCRIPT的函数可以嵌套在其他函数里面
 13     function hy(a,b){
 14         function square(x){return x*x;}
 15         return Math.sqrt(square(a)+square(b));
 16     }
 17
 18 4.函数声明语句并非真正的语句,他们可以出现在全局代码里,或者内嵌在其他函数内,
 19 但是它们并不能出现在循环,条件判断或者try/catch语句中。
 20 但函数定义表达式可以出现在javascript的任何地方
 21
 22 5.jquery的方法链式调用原理
 23     $(":header").map(function(){return this.id;}).get().set();
 24     当方法不需要返回值时,建议将其返回值定为return this;
 25     这样就可以实现方法的链式调用。
 26
 27 6.嵌套函数中this的指向问题
 28  var o={
 29            m:function(){
 30                var This=this;
 31                f();
 32
 33                function f(){
 34                    console.log(this);
 35                    console.log(This);
 36                }
 37            }
 38         };
 39     o.m();
 40 以上示例中,对象o内定义了函数m(),在函数m()内定义函数f()并调用
 41 在f内的this并不指向调用外层函数的上下文,而是指向全局对象
 42 其返回值:
 43
 44             Window Html001.html//严格模式下返回undefined
 45             Object { m=function()}
 46
 47 7.构造函数的调用
 48 如果在函数或者方法调用前带有关键字new,就形成了构造函数调用
 49 var o=new Object();
 50 var o=new Object;//没有形参时可以省略掉Object后面的括号
 51 一旦使用了new关键字调用构造函数,构造函数内的this就会指向new出来的新对象
 52         var o={
 53            m:function(){
 54                var This=this;
 55                f();
 56
 57                function f(){
 58                    //console.log(this);
 59                    console.log(This===o);
 60                }
 61            }
 62         };
 63         new o.m();//函数内部this不指向上下文,也就是不指向o
 64
 65 8.间接调用,call()与aplly()
 66 允许函数显示的指定函数运行的域,也就是规定this的指向
 67 foo.call(obj1,args1...);
 68 foo.apply(obj2,arg[...]);
 69
 70 9.函数调用的形参与实参
 71 function foo(arg1,arg2,arg3....){}
 72
 73 foo(arg1);
 74 如果函数调用时传入的实参比函数定义时的形参数要少,则多的形参被定义为undefined
 75 这个特性可用来实现类似函数重载的功能
 76
 77 function getPropertyName(o,/*可选参数,数组a*/arr) {
 78     // body...
 79     var arr=arr||[];//undefined在逻辑运算中返回false,若调用时a不存在,则将arr赋予新的空数组[]
 80     for(var p in o) arr.push(p);
 81         return arr;
 82 }
 83 getPropertyName(o);
 84 getPropertyName(o,myArray);
 85
 86 设计原则:
 87     当使用这种可选参数来创建函数时,满足原则1.可选参数放在参数列表最后。2./**/用注释说明可选参数
 88         3.调用函数时,可选参数位置最好显式的传入null作为占位符。
 89
 90 function foo(arg1,arg2,arg3....){}
 91
 92 foo(arg1);
 93 再回到这个函数调用例子,当实参列表超过形参列表时,函数内部无法显式获得超过部分的引用
 94 此时可用arguments类数组来调用,事实上arguments[]数组内存储着传进来的所有实参
 95 arguments也包含着length属性;
 96
 97 实参对象的应用实例:
 98         (function (x,y,z){
 99             if(arguments.length!=3){
100                 throw new Error(
101                         "该函数必须传入3个参数"
102                 );
103             }
104             console.log(x+y+z);
105         }(1,2));
106         运行结果:Error: 该函数必须传入3个参数
107     用于验证实参列表个数,只有在实参数目为3时,才执行函数。
108 /**
109 复习:类数组对象
110     js的数组有四大特性:
111         1.有新元素加入数组时,自动更新length
112         2.设置length为一个较小值时将截断数组
113         3.从Array.prototype继承一些方法
114         4.其类属性为“Array”
115
116     这四个特性让数组与类数组对象区分开来
117     而像arguments这样的类数组对象,可以理解为其属性名刚好为从0开始的非负整数序列
118     且有个length属性记录它的属性长度
119
120     而区别在于length没有数组的特性1,2.
121     且没有从Array.prototype继承方法
122
123     但是可以利用call临时继承调用
124     var a={"0":"a","1":"b","2":"c"};
125
126     Array.prototype.join.call(a,"+") //"a+b+c"
127
128     Array.map(function(x){return x*x}) //ecma5,不修改原数组,返回一个数组副本,其中的每一项都是
129                                         参数内函数的返回值。
130
131 */
132 细说实参对象arguments://该对象的可枚举属性仅有实参
133     属性callee与caller
134             callee:指代当前正在执行的函数
135             caller:调用当前正在执行的函数的函数//!--暂时无法理解这句话--!
136
137             callee可用在匿名函数中实现递归
138             function (x) {
139                 // body...
140                 if(x<1)return 1;
141                 return x*arguments.callee(x-1);//此处的arguments.callee()就是在调用函数本身
142             }
143
144 10.将对象属性用作实参,减少记忆参数列表顺序,在参数列表巨大的情况下
145     function arrayCopy(a,a_start,b,b_start,length) {//该函数将a数组从a_start处复制length个元素至b数组中起始位置b_start位置
146                     // 要记忆这些形参的顺序实在不容易
147                 }
148
149     function easyCopy(argument) {
150                     // body...
151                     arrayCopy(arguments.from,
152                             arguments.from_start||0,
153                             arguments.to,
154                             arguments.to_start||0,
155                             arguments.length
156                         )
157                 }
158     //在调用easyCopy时,只需传入一个匿名对象就可以了
159     a=[1,2,3,4];
160     b=[];
161     easyCopy(
162         {from:a,to:b,length:4}//传入匿名对象
163         );
164
165 11.作为值的函数
166     在js中,函数也可以作为--实参,传入别的函数参数列表;
167     看如下一个函数的定义
168         function square(x) {return x*x}
169     这个定义创建一个新的函数对象,并将其值赋给square;
170     var s=square;//现在s和square指代同一个函数
171
172     类似数组的sort()方法,接受一个函数
173     写法Array.sort(function (a,b) {return a-b;
174         // body...
175     })
176     或者Array.sort(bj);//bj指代一个函数
177
178 12.自定义函数属性
179     js中函数是对象,所以可以定义函数的属性,用于计数之类的工作
180     比如要计算一个函数的调用次数,又不想定义一个全局变量
181     则可以:
182     foo.times=0;
183     function foo(argument) {
184         // body...
185         foo.times++;
186     }//还有更多用途,
187
188     //定义缓存
189     foo.times=0;//判断if语句执行次数的标记
190         function foo(x){
191             if(x<1&&x!=Math.round(x)) throw new Error("foo()函数参数为大于1的正整数");
192             if( !(x in foo)){
193                 foo.times++;
194                 console.log(foo.times);
195                 foo[x]=x*foo(x-1);//将已经计算出来的值存储进foo[]类数组之中
196             }
197             return foo[x];
198         }
199         foo[1]=1;
200
201         foo(11);
202         foo(10);//从返回结果可以看到,此处并没进入if判断中,减少了很多次运算
203         foo(12);
204         foo(0.6);//验证数值输入的正确性
205
206             代码运行返回结果:
207                     1
208                     Html001.html (第 23 行)
209                     2
210                     Html001.html (第 23 行)
211                     3
212                     Html001.html (第 23 行)
213                     4
214                     Html001.html (第 23 行)
215                     5
216                     Html001.html (第 23 行)
217                     6
218                     Html001.html (第 23 行)
219                     7
220                     Html001.html (第 23 行)
221                     8
222                     Html001.html (第 23 行)
223                     9
224                     Html001.html (第 23 行)
225                     10
226                     Html001.html (第 23 行)
227                     11
228                     Html001.html (第 23 行)
229                     Error: foo()函数参数为大于1的正整数
230
231 13.作为命名空间的函数
232     类似jquery这样的库的做法
233     a.(function (argument) {
234         // body...
235     }())
236     b.(function (argument) {
237         // body...
238     })();
239     定义一个匿名函数并立即调用,在匿名函数内的变量就不会污染全局命名空间
240     对于包裹function的圆括号的解释:
241         function前面没有圆括号时,js会将function解释为函数声明语句,这样就无法立即执行
242         而加上圆括号,或是其他运算符,则会被解释为函数定义表达式。
243
244 14.闭包
245     js中,函数的执行依赖于变量作用域,这个作用域是在函数定义时创建的,而不是在函数执行时。
246     例子1:
247         var scope="global scope";
248         function checkscope() {
249             // body...
250             var scope="local scope";
251             function f() {
252                 // body...
253                 return scope;
254             }
255             return f();//f在checkscope内部执行时很容易理解,它寻找f的作用域,在checkscope函数内找到scope就返回了
256         }
257         checkscope();
258     例子2:
259         var scope="global scope";
260         function checkscope() {
261             // body...
262             var scope="local scope";
263             function f() {
264                 // body...
265                 return scope;
266             }
267             return f;
268         }
269         checkscope()();    //在全局执行chechscope内部的函数f;因为闭包的存在,f()也是在其作用域链内寻找scope
270                         //这个作用域链在函数定义之初就开始存在
271
272     例子3:
273     foo.times=0;
274     function foo(argument) {
275         // body...
276         foo.times++;
277     }//这是12小结的一个例子,foo.times来记录函数foo的调用次数
278     下面用闭包来改写它。
279         var times=(function () {
280                 var count=0;
281                 return function(){
282                     return count++;
283                 }
284         }())//当外层作为命名空间的函数返回之后,除了timer(),任何函数或语句都访问不到其内部的count
285             //而又因为times在外部使用其作用域链上的count,所以count会作为一个变量一直存在内存
286             //times()每次调用都访问的是内存中已经存在的count;故可以充当计数器
287         function foo(argument) {
288         // body...
289             times();
290         }
291
292
293     例子4:
294     function counter(){
295         var count=0;
296         return {
297             count:function(){return ++count;},
298             reset:function(){return count=0;}
299         }//返回一个包含两个方法的匿名对象
300     }
301
302     var obj1=counter();
303     var obj2=counter();//obj1和obj2接受到的是不同的Object。所以他们的count互不干涉
304      console.log(obj1.count());
305      console.log(obj1.count());
306      console.log(obj1.count());
307
308      例子5://ECMA5中的变体
309      function counter(n){
310          return {
311              get count(){
312                  return ++n;
313              },
314              set count(m){
315                  if (m<=n) {throw Error("您设置的n太小了")}
316                  return n=m;
317              }
318          }
319      }
320      var obj=counter(100);
321      console.log(obj.count);
322      console.log(obj.count);
323      console.log(obj.count);
324      console.log(obj.count=200);
325      console.log(obj.count);
326      console.log(obj.count);
327          利用setter和getter来定义计数器count,给予计数器设置初值和临时更改的方法
328          而count则是obj的私有属性,且通过赋值修改必须遵循get方法设置的条件
329
330      例子6://闭包实现私有属性的经典做法
331           function addPrivateProperty(o,name,predicate) {
332             // body...
333             var value;
334             o["get"+name]=function () {
335                 return value;
336             };
337             o["set"+name]=function(v){
338                 if (predicate&&!predicate(v)) {throw new Error("数据未通过predicate函数合法性验证")}
339                 value=v;
340             }
341         }
342
343         var o={};
344         addPrivateProperty(o,"Name",function(v){return typeof v=="string";});
345         addPrivateProperty(o,"Age");//未进行合法性验证
346
347         o.setName("wangjue");
348         o.setAge(18);
349         console.log(o.getName());
350         console.log(o.getAge());
351         为何能够不断添加属性,是因为每个属性的set和get方法组--存在于不同的作用域链,
352         可以利用如下例子进行例证:
353         function constfunc(v){
354             var value;
355             return function(){
356                 value=v;
357                 return value;};
358
359         }
360         var fun1=constfunc("arr1");
361         var fun2=constfunc();//发现只要传递的参数不一样,就会创建新的闭包
362
363         console.log(fun1());//=>arr1
364         console.log(fun2());//=>undefine    value并未共享
365
366
367      例子7:
368          function constfunc(v) {
369              // body...
370              return function(){return v;};
371          }//一个总是返回v的函数
372          for(var i=0;i<10;i++) fun[i]=constfunc(i);
373          fun[5]();//=》返回值为5
374
375          上述代码循环创建了很多闭包
376
377      总结性语言:多个嵌套函数并不会将作用域链上的私有成员复制一份,他们是共享的。
378
379      例子8:
380          嵌套函数内,也就是闭包,无法访问外部函数的arguments和this
381          function foo(arg1,arg2) {
382              // body...
383              var self=this;
384              var outArguments=arguments;
385
386              return function () {
387                  return self+outArguments.toString(" ");
388              }
389          }
390          前文已经提过,嵌套函数内部使用this,指代的是全局环境window,或者undefined
391          //闭包  end
392
393 15.函数的属性,方法和构造方法
394     在js中,函数是特殊的对象,故其也有对象的一些性质
395         所以其也拥有属性和方法,能够用Function()构造函数创建。
396
397     (1)length:函数对象也拥有一个length属性,其值为函数声明时的形参列表的表长。
398                 //一个检测实参与形参是否数量相等的函数
399                 function check(argument) {
400                     // body...
401                     if(argument.length!=argument.callee.length) throw new Error("传入参数数量不对")
402                 }
403
404                 function test(arg1,arg2) {
405                     // body...
406                     check(arguments);
407                     return arg1+arg2;
408                 }
409
410                 test(1,2);
411
412     (2)prototype每一个函数都有一个原型属性
413     (3)call(),与aplly()方法
414
415     (4)bind(); //ECMA5中新增的方法,f.bind(obj);将函数f绑定至obj上
416         兼容性解决:
417             function bind(f,o) {
418                 // body...
419                 if(f.bind) return f.bind(o);
420                 else{
421                     return f.apply(o,arguments);
422                 }
423             }//这里的自定义bind()函数就是将f绑定至o下,且立即执行
424
425         function f(argument) {
426             // body...
427         }
428         f.bind(o,agr1,arg2);//bind除第一个参数外,后面的几个参数都将传入f,参与函数调用
429
430     (5)toString()//返回函数的完整源码
431
432     (6)Function()构造函数;
433
434
435 16.函数式编程
436     类似数组的reduce(),map()之类的方法就是函数式编程的例子
437
438
439 17.高阶函数,所谓高阶函数就是操作函数的函数,其传入函数作为参数,返回值也是函数
440
441 18.记忆函数
442     //闭包的实例
443         function memorize(foo){
444             var cache={};
445             return function () {
446                 // body...
447                 var key=arguments.length+Array.prototype.join.call(arguments,",");//作为缓存的键
448                 if(key in cache)  return cache[key];//若在cache中找到了key,则直接返回内存中的值
449                 else {
450                     cache[key]=foo.apply(this,arguments);//内存中没有,则赋值。
451                     return counter[key];//
452                 }
453             }
454         }
455
456         //当我们使用一个递归函数时,往往要使用记忆功能
457         var factorial=memorize(function (n) {
458             // body...
459             return n<=1?1:n*factorial(n-1);
460         })
461         factorial(5);
时间: 2024-08-08 11:12:29

犀牛笔记--函数的相关文章

0715-----C++Primer听课笔记-----------函数指针 、单例模式

1.函数指针 1.1 普通成员函数指针包含类名信息以及const属性,指向具体函数是必须加上&符号. #include <iostream> using namespace std; class Test{ public: void setValue(const string &s, int a){ s_ = s; a_ = a; } void print() const{ cout << s_ << endl << a_ <<

c语言笔记————函数的作业

#include <stdio.h>#include <stdlib.h>#include <string.h>void maoPao( float num[]){ for (int i =0; i<10-1; i++) {        for (int k=0; k<10-1-i; k++) {            if (num[k]>num[k+1]) {                num[k]=num[k]+num[k+1];     

php课外笔记--函数可变参数列表的实现

php课外笔记--函数可变参数列表的实现 php的函数方面非常强大,但对于一些php新手来说,理解有部分困难,不能完全熟练的掌握. php培训教程中,介绍一部分函数可变参数列表的实现方法: PHP函数可变参数列表的实现方法主要是利用func_get_args().func_num_args().func_get_arg()这三个系统函数来实现的,其中func_get_args()函数以数组的形式获得参数列表,具体用法参看手册. PHP函数可变参数列表代码如下: < ?php    /*   函数

F# 学习笔记(函数基础)

因为只是笔记,所以只记录自己觉得要注意与需要理解的地方,其他就不记了 函数定义上F#有自己的写法: [<EntryPoint>] let main argv = let f1 = fun x -> x * x - 2 * x let f2 x = let x1 = x - 2 x * x1 printfn "%i" (f2 10) printfn "%i" (f1 10) 0 f1是很好理解的,因为基本上现在支持lambda表达式的基本都是第一种写

C#学习笔记---函数 的理解及总结(入门级)

*内容可能会有不到位的地方,希望小伙伴们顺便找出来,共同在IT这个“坑“里越陷越深,做一个有深度的程序”猿“:深夜发博只图进步与...你懂得!! 1)函数: 主要的功能就是为了让代码结构更加良好.函数是——实现相对独立功能的程序代码模块(程序段).函数的四要素:函数名,输入,输出,运算 *有的函数没有输入,函数名后的小括号中可以不写东西,但必须要有小括号.*有的函数没有返回,在函数名的左侧不要写数据类型了,写void即可.(只是输出要显示,不往“Main”的函数里代入.直接输出用void) 函数

Python学习笔记-函数篇

定义 返回单值 def my_abs(x): if x >= 0: return x else: return -x 返回多值 返回多值就是返回一个tuple import math def move(x, y, step, angle=0): nx = x + step * math.cos(angle) ny = y - step * math.sin(angle) return nx, ny 空函数 def nop(): pass 指定默认参数 必选参数在前,默认参数在后.默认参数需指向不

GO学习笔记 - 函数名前面是否有输入参数肯定是不一样的!!

在刚接触GO语言时候,我相信你也会有这种困惑,为什么有的函数名前面有输入参数,而一些却没有,它们是否有差别?确实有差别,没有输入参数,是一般的函数:有输入参数,是结构的方法,输入参数叫做"方法接收者"!GO语言没有类,方法都定义在结构上了!! 官方教程: 函        数:https://tour.go-zh.org/basics/4 结构体方法:https://tour.go-zh.org/methods/1 实例代码: main.go : 引入了"sunylat/de

Lua学习笔记--函数初探

感觉学习语言的话,函数是个重头戏.来看一下Lua的函数是神马样纸的东东! 一.简单的函数例子 --一个简单的函数:阶乘 function factorial(num) if num == 0 then return 1 else return num * factorial(num - 1) end end 恩,这就是个函数.function关键字,说明这是个函数,然后是函数名,后面跟的是参数列表,使用括号括起来.函数的结尾需要一个end关键字,表明函数结束了. 下面看以下怎么调用: --一个简

F# 学习笔记(函数基础3)

递归函数: 在F#中一般不允许调用自身,而只能通过关键字rec来声明其为递归函数: 最大公约数的应用,使用辗转相除法: [<EntryPoint>] let main argv = let rec gcd(a,b) = if a = 1 then b elif b = 1 then a elif a = b then b else if a > b then gcd(a-b, b) else gcd(a,b-a) (72,54) |> gcd |> printfn "