JavaScript 函数

一.函数的理解

有人把函数比作现实中的菜谱,这个比喻很形象。函数就是预先定义好的代码段,里面规定了一些步骤。在被调用后,将会按照预设的步骤执行,直到碰到返回语句或步骤结束。

二.function的定义方式

1.直接声明:

function myfunc(/arguments/){
} 或者
var myfunc=function(/arguments/){
}
这两种定义的区别:第一种方式在声明时是一个命名的函数,无论在调用之前、调用之后,甚至是不会执行到的位置(例如return语句之后或者永远不会为真的分支里),都在整个作用域可访问;第二种方式是通过把匿名函数赋值给变量的方式,严格意义上说这个只是一个函数表达式,在赋值之前这个函数不能被任何代码访问到,可以理解为必须先赋值,后调用。

例子:
var inner;
function outer(){
    //inner=10;   
    return inner;
    function inner() {
 }
/*    var inner=function() {

 }*/
}
console.log(typeof outer());  

return 前面如果inner没有赋值时,这个console输出结果是function。
若函数改成 var inner=function,console输出结果为undefined.如果return前面inner 有赋值(10),console输出结果是 number。

小注:定义后myfunc只是指向函数地址,如果要执行函数必须在调用时加上一对小括号,比如:myfunc();

JavaScript 函数的递归调用
比如:

function myfunc(n){
 if(n==1){
         return 1;
     }else{
         return myfunc(n-1); 
         //或者 return arguments.callee(n-1);
    } 
}
console.log(myfunc(3));//输出结果都为1;

在“use strict” 严格模式下,callee 会报TypeError错误。

小知识点扩展:arguments对象是比较特别的一个对象,实际上是当前函数的一个内置属性,里面存储了函数实参的值,比如{“0”,”第一个参数值”}

例子:
function myfunc(n){
    console.log(arguments);// 结果:{"0",1}
}
myfunc(1);
实参论证:
function f(a, b, c) {
    console.log(arguments.length);   // result: "2"
    a = 100;
    console.log(arguments[0]);       // result: "100"
    arguments[0] = "qqyumidi";
    console.log(a);                  // result: "qqyumidi"
    console.log(c);                  // result: "undefined"
    c = 2012;
    console.log(arguments[2]);       // result: "undefined"
}
f(1, 2);

2 匿名函数

在JavaScript可以声明一个没有名称的函数,称为匿名函数(Anonymouse Function)。匿名函数好处:由于没有名称,且有自己的作用域,内嵌的函数作用范围也只在这个匿名函数内,不会引入新的变量污染上下文环境。
JS库使用的原理:JavaScript 运行时有一个特殊的全局环境(global object),这个对象上面存放全局的函数和变量,在实际项目中会经常使用若干个第三方的库或js文件,如果众多的js中有些函数声明同名,则会造成代码执行混乱。比如:先后引入两个js文件,分别定义自己的函数log作为内部使用,第二个引入的函数会覆盖掉第一个定义并且不会抛出任何 错误,在后续调用时就有可能造成错误。若使用匿名函数将整个js内的逻辑包装起来,这样库以库之间就不会受到干扰。
例子:

(function () {
    function  log(msg) {
        console.log(msg);
    }

    console.log(1);
}());//只运行一次,结果输出1;
// 另外一些匿名函数写法
+function(){}(); //声明前面加一元操作符+ !~号,直接把声明变成函数表达式。后面加(),就能直接运行。 不推荐这样写。function(){})()function(){}();
~function(){}();

如果带参数的匿名函数,可以这样写:
(function(x,y){return x-y})(2,3) //2,3就时调用时,传递给匿名函数的实参

上面代码只能运行一次,无法被调用访问。下面有3种方法作为接口,供外部调用。

 var mylib = (function(global) {
    function log(msg) {
        console.log(msg);
    }
    log1 = log;  // 法一:利用没有var的变量声明的默认行为,在log1成为全局变量(不推荐)

    global.log2 = log;  // 法二:直接在全局对象上添加log2属性,赋值为log函数(推荐),js全局对象用global,浏览器全局对象用widndow.

    return {  // 法三:通过匿名函数返回值得到一系列接口函数集合对象,赋值给全局变量mylib(推荐)
        log: log
    };
}(global));

log1(1);
log2(2);
mylib.log(3);

知识拓展:

异步加载机制;
commonJS 推出的AMD规范,全称是Asynchronous Module Definition,即异步模块加载机制。从它的规范描述页面看,AMD很短也很简单,但它却完整描述了模块的定义,依赖关系,引用关系以及加载机制。从它被requireJS,NodeJs,Dojo,jquery使用也可以看出它具有很大的价值,没错,JQuery也采用了AMD规范。
 AMD规范只有一个API,即define 函数:
 define([module-name?],[array-of-dependencies?],[module-factory-or-object]);
 其中:
 module-name:模板标识,可以省略。
 array-of-dependencies:所依赖的模块,可以省略。
 module-factory-or-object:模块的实现,或者一个JavaScript对象
define 可以定义一个模块:
例子: define(“alpha”,[“require”,”exports”,”beta”],function(require,exports,beta){
exports.veb=function(){
return beta.verb();
//或者:
return require(“beta”).verb();
}
})
define 定义一个对象:
例子:
define({
provinces:[{name:’上海’,ares:[‘浦东新区’,’徐汇区’]}]
});
define 定义一个函数:
例子:
define(function(){
var p=require(‘china’);//用require 引入直接需要的名叫china.js 的模块
})

vue 框架库的定义方式:

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global.Vue = factory());
}(this, (function () { 'use strict';
                                return Vue$3;
                                })));

typeof exports === ‘object’ && typeof module !== ‘undefined’ 这两句判断应该是判断是不是后端nodejs;
typeof define === ‘function’ && define.amd 这两句判断是不是已经定义了异步amd。
(global.Vue = factory()) 当前面两个都没有时,在全局对象里边增加一个Vue参数,指向factory() 函数。 factory是形参,实参是后面的(function(){ ‘use strict’;… }) 。

闭包(Closure)

闭包:在JavaScript中,在内嵌函数中使用外部函数作用域内的变量,就是使用了闭包。
闭包有时会导致内存泄漏:

var elem = document.getElementById('test'); 
 elem.addEventListener('click', function() { 
   alert('You clicked ' + elem.tagName); 
 });

内嵌匿名函数调用了外层函数的DOM对象(elem),这种由匿名函数组成的闭包现象,即使删掉DOM对象(elem),内存里面的闭包也不会释放。
解决这个问题:用this替代DOM(elem),this指向的是DOM元素本身,JS不认为是调用外层函数变量,因此不会形成闭包。
代码如下:

var elem = document.getElementById('test'); 
 elem.addEventListener('click', function() { 
   alert('You clicked ' + this.tagName); // 不再直接引用elem变量 
 });

3、类构造函数:

JavaScript的函数如果是类构造函数,直接用new创建类的实例就好了。
var myfunc= new Function(“参数1”,“参数2”,“函数体;return返回值”);

例子:
function Flyername){
    this.name=name;
    this.toString=function(){
        return 'Hello,' +this.name+'!';
    }
}
var plane= new Flyer('boeing 747');
console.log(plane.toString());//输出:Hello,boeing 747!

JavaScript函数作为类构造函数使用时如果加了返回值,会出现一些问题。

 function MyClass(name) { 
   this.name = name; 
   return name;  // 构造函数的返回值? 
 } 

function MyClass(name) {
    this.name = name;
    return name;  // 构造函数的返回值?
}
var obj1 = new MyClass('foo'); // 创建一个MyClass的对象实例
console.log(obj1);// obj1 指向的是实例对象的地址
var obj2 = MyClass('foo');// 当普通函数调用
console.log(obj2);// 返回 foo值
var obj3 = new MyClass({}); // 创建了一个实例,同时给obj3返回了一个指向空对象的地址。
console.log(obj3); //输出空对象
var obj4 = MyClass({}); //当普通函数调用
console.log(obj4);//返回{};

所以不建议在构造函数里边用return。

三、Function 类

JavaScript 内部类Function,用function关键字声明一个函数其实是创建Function类对象的一种简写形式,所有的函数都拥有Function类所有的方法,例如call、apply、bind 等 。
new Function([arg1[,arg2[,arg3[,…argN],]functionBody)
其中 arg1~argN 是字符串格式的参数,functionBody 也是字符串。Function的构造函数会把最后一个参数当做函数体,前面的都当中参数处理。
例子:

 var func1=new Function('name','return "Hello,"+name+"!";');
 func1('Ghostheaven');

自更新函数
函数内部再次重新定义函数本身
例子:

function selfUpdate() {
    window.selfUpdate = function() { //window用global替换这里会报错
        console.log('second run!');
    };
    console.log('first run!');
}
selfUpdate(); // first run!
selfUpdate(); // second run! 这种函数可以用于只运行一次的逻辑,在第一次运行之后就整个替换成一段新的逻辑。

参考文章:
http://www.cnblogs.com/lwbqqyumidi/archive/2012/12/03/2799833.html
http://www.jb51.net/article/57482.htm
http://blog.csdn.net/xiebaochun/article/details/42172643
http://www.jb51.net/article/62261.htm
http://blog.csdn.net/xiangyong58/article/details/50569071

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值