前言

我在上一篇【javascript基础】基本概念中介绍了javascript的一些基本概念,多谢大家的阅读和意见,自己写的东西可以被大家阅读,真心高兴,刚开始发布的时候我一直盯着阅读人数,虽然知道大家可能就是点开一下而已,但是还是给我一些继续写下去的信心。那今天写一些关于javascript函数的一些知识,帮助大家熟悉或者复习一些函数的基本知识。

PS:最近jQuery源码交流群( 239147101)加了不少热新人,希望大家还是以学习为主,尽量少灌水,给大家一个好的提升自己的环境。

函数

函数在任何一种编程语言中都是一个很重要的结构或者组成部分,编程中的复杂结构和功能都会有函数的参与。javascript中的函数是一个对象,函数对象时Function类型的实例,由于Function类型是一个引用类型,那么函数可以拥有自己的方法和属性,同时也因为函数是一个对象,那么函数名是一个指向函数对象的指针,可以被赋值。下面详细介绍函数的各个部分。

创建函数

函数的创建有三种方式,分别为使用Function的构造函数、函数声明、函数表达式,下面分别介绍这三种方法。

Function构造函数

这种方式是直接new出来一个Function 实例,通过使用Function的构造函数进行创建函数。Function构造函数可以接收任意多个参数,但是最后一个参数会被认为是函数体,前面的所以参数被当做被创建出来的函数的参数。

var test = new Function("a","b","return a + b");//参数a和b,函数体return a + b
console.log(test(1,2));//

我们可以看出比较的麻烦,并且《javascript高级程序设计》也不推荐我们使用这种方式,主要是因为浏览器要解析常规的javascript代码之外,还要解析传入的参数字符串,这个类似eval()的解释,影响性能。

函数表达式

这种方式是创建的常见方式之一,具体请看

var test = function(a,b){
return a + b;
}
console.log(test(1,2));

上面的代码就是创建一个函数,使用test()进行调用。其实,上面的代码是先创建了一个匿名的函数,之后把这个匿名的函数赋值给test变量。每个函数有一个name属性,这个属性不是ECMA标准的一部分,但是许多地方可以使用它。我们可以给上面的函数起一个名字,具体下面代码

//函数的名字newName
var test = function newName(a,b){
return a + b;
}
console.log(test.name);//newName //匿名函数
var nTest = function (a,b){
return a + b;
}
console.log(nTest.name);//""

这个属性在后面详细解释吧。

函数声明

这种方式和C语言中的很类似,这种是最常见的一种创建函数的方法。是通过关键字function直接声明,请看

function test(a,b){
return a + b;
}
console.log(test(1,2));//
console.log(test.name);//test

区别

以上介绍了三个创建函数的方式,现在介绍三种的区别,确切的说是后两种的区别,因为Function不推荐使用,性能是一大原因。区别就是使用函数声明这种方式会使函数的声明提前,类似前面我们提到的变量申明的提前。也就是说,使用函数申明方式,我们可以将函数的声明放在调用函数代码的后面,因为解析器会在代码执行之前将函数的声明提升,提到源代码树的顶部,而函数表达式方式则会报错,具体请看

//调用函数
console.log(test(1,2));//
//创建函数(函数申明方式)
function test(a,b){
return a + b;
}
//上面的函数相等于
//创建函数(函数申明方式)
//function test(a,b){
// return a + b;
//}
//console.log(test(1,2));//3 //调用函数
console.log(ntest(1,2));//TypeError: undefined is not a function
//创建函数(函数表达式方式)
var ntest = function (a,b){
return a + b;
}

not重载

javascript语言不像java那些语言有函数重载这一概念,其实函数名就是一个指针,指向一个Function实例的地址,当然只能指向一个函数,当然没有重载的概念了,只有覆盖,后面定义的函数覆盖前面定义的函数,具体请看

function test(a,b){
return a + b;
}
//下面的函数覆盖上面的
function test(a,b){
return a + b + 100;
} console.log(test(0,0));//

也就是说如果一个同名的函数表达式和函数申明的函数在一起,无论位置是怎么样的,最后的函数就会是用函数表达式创建的函数,因为函数申明会提升到顶部嘛,看看下面的代码

var test = function (a,b){
return a + b -100;
} function test(a,b){//会被下面的函数覆盖
return a + b;
} function test(a,b){//会被函数表达式覆盖
return a + b + 100;
} console.log(test(0,0));//-100

内部属性

函数的内部有两个重要的对象:arguments和this。

arguments

arguments是一个类似组对象,包含所以传入函数的所有参数, 写程序或者面试中常问的就是如何将arguments转化完成一个数组,请看

Array.prototype.slice.call(arguments);
Array.prototype.slice.call(arguments,0);
Array.prototype.slice.call(arguments,0,arguments.length);
Array.apply(this, arguments); //没用过
Array.apply(null, arguments); //没用过

arguments有一个length属性,表示函数传入参数的个数,还有一个callee属性,这是一个指针,指向拥有这个arguments的函数,这个主要是在函数内部调用自己时使用,也就是递归时使用。看个例子就明白了

function test(count){
console.log("参数:"+arguments[0]+"个数:"+arguments.length);
if(count <= 0){
console.log("递归"+count+" 结束了");
}else{
console.log("递归"+count);
arguments.callee(--count);//调用自己
}
}
test(3);
/*
参数:3个数:1
递归3
参数:2个数:1
递归2
参数:1个数:1
递归1
参数:0个数:1
递归0 结束了
*/

this

javascript中的this和java中的this差不多,this引用的是函数的执行环境,就是this在不同的执行环境中引用的是不同的对象,执行环境这里还没有说到,以后会详细介绍,这里的this也是简单的介绍一下,我以后会整理一些面试题,帮助大家理解。看例子吧,

//全局变量
var color = "red";//相当于window.color = "red"
//定义一个对象
var obj = {color : "blue"};
function pop(color){
alert(this.color);
}
pop();//相当于window.pop();输入"red"
//obj对象增加一个方法,将pop赋值给它
obj.pop = pop;
obj.pop(); //输出"blue"

解释一下,this这个对象是在函数执行时才绑定的,可以说是一个动态的。pop函数是定义在window下的一个函数,也就是全局作用域的一个函数,当直接执行pop函数时,就是在全局作用域下调用pop时。this引用的是window,this.color就是window.color,输出red。当我们把pop这个函数赋值给obj这个对象并且调用pop的时候,this引用的就是obj这个对象,this.color 就是obj.color,输出blue。

函数属性和方法

这里说一下函数的属性和方法,包括length,name,prototype,apply,call这几个。

length

这个属性比较简单,就是表示定义函数时定义的参数的个数,要和arguments.length区分开,arguments.length表示实际输入的参数个数,看例子

function test(a,b){
console.log("输入的参数个数:"+arguments.length);
console.log("定义的参数个数:"+test.length);
}
test();//0,2
test(1);//1,2
test(1,2)//2,2
test(1,2,3)//3,2
//函数的内部我们可以通过arguments[i],取得输入的参数,假如定义一个参数,输入两个参数,那怎么取得第二个参数呢
function testA(c){
console.log("输入的参数个数:"+arguments.length);
console.log("定义的参数个数:"+test.length);
console.log("第二个参数:"+arguments[1]);
}
testA(1,100);2,2,100
//这里可以遍历取得所有的参数,不讲了

name

这个属性在前面提到了一点,这个就是函数的名字,我们在创建函数的时候说了这个属性,这个属性不是标准属性,但是很多地方就使用这个属性,主要也是在递归调用上使用。name属性是只读属性,不能修改它的值。直接看例子

//修改name属性
function test(){
console.log(test.name);
//修改name属性
test.name = "newName";
console.log(test.name);
}
test();//test,test
//函数内部使用name属性,递归调用
function testD(count){
console.log("参数:"+arguments[0]+"个数:"+arguments.length);
if(count <= 0){
console.log("递归"+count+" 结束了");
}else{
console.log("递归"+count);
testD(--count);//调用自己
}
}
testD(3);
/*
参数:3个数:1
递归3
参数:2个数:1
递归2
参数:1个数:1
递归1
参数:0个数:1
递归0 结束了
*/

name属性的使用和arguments.callee()的效果是一样的,只不过arguments.callee()更方便些,当函数名字更改时程序不用更改。

prototype

函数的prototype属性是一个很重要的属性,特别是在自定义引用类型和实现继承时。我们现在这简单的介绍一下它,因为这个属性足以单独写一篇文章。我们可以认为prototype是一个模板,在new 一个对象时候会参照这个模板,将模板里的属性和方法复制给对象,当然你不定义这个模板,这个模板不存在方法和属性。简单例子

function People(name){
this.name = name;
}
//prototype中的属性
People.prototype.home = "jilin";
var hainan = new People("hainan");
console.log(hainan.home);//jilin

先简单介绍到这,后面单独详细说。

call和apply

这两个方法作用是一样的,就是改变this作用域的值,在特定的作用域中调用自己,也就是设置this的指向,不同点在于参数接收方式不同。apply方法需要两个参数,第一个是指定的作用域,就是要把this指向的对象,第二个是参数数组,函数调用需要的参数,这个参数数组也可以是arguments这个伪数组。call的第一个参数也是给this绑定的值,其他的参数个数不定,其他的参数就是函数调用需要的参数,和apply不同,你要一个一个的都列举出来。看例子

function sum(a,b){
return a + b;
}
//arguments参数
function callSum1(a,b){
return sum.apply(this,arguments);
}
//数组参数
function callSum2(a,b){
return sum.apply(this,[a,b]);
}
//列举所有参数
function callSum3(a,b){
return sum.call(this,a,b);
}
console.log(callSum1(1,2));
console.log(callSum2(1,2));
console.log(callSum3(1,2));

上面是传递参数的例子,再看看改变this指向的例子

//全局变量
var color = "red";//相当于window.color = "red"
//定义一个对象
var obj = {color : "blue"};
function pop(color){
alert(this.color);
}
pop();//相当于window.pop();输入"red"
pop.call(this);//red
pop.call(obj);//blue

解释一下,pop.call(this)这句代码改变了this的指向,因为是在全局中调用的函数,this指向window,输出window.color。pop.call(obj)这句代码将this指向了obj,所以输出obj.color。

小结

把函数这部分的基础和大家说了一下,自己讲代码敲了一遍实验了一下,有些东西看着容易懂,写起来还是挺困难的,希望大家也要多写写吧,我一直以为作文就不好,这是难为大家了。要放假了,有点想家了,想吃家里的酸菜了。

【javascript基础】2、函数的更多相关文章

  1. (Frontend Newbie)JavaScript基础之函数

    函数可以说是任何一门编程语言的核心概念.要能熟练掌握JavaScript,对于函数及其相关概念的学习是非常重要的一步.本篇从函数的基本知识.执行环境与作用域.闭包.this关键字等方面简单介绍Java ...

  2. JavaScript基础学习-函数及作用域

    函数和作用域是JavaScript的重要组成部分,我们在使用JavaScript编写程序的过程中经常要用到这两部分内容,作为初学者,我经常有困惑,借助写此博文来巩固下之前学习的内容. (一)JavaS ...

  3. JavaScript 基础回顾——函数

    在JavaScript中,函数也是一种数据类型,属于 function 类型,所以使用Function关键字标识函数名.函数可以在大括号内编写代码并且被调用,作为其他函数的参数或者对象的属性值. 1. ...

  4. Javascript 基础--JS函数(三)

    一.基本概念:未完成某一个功能的代码(语句,指令)的集合. 二.函数的调用方式: 2.1.函数名(传递参数1,传递参数2)   基本语法 function 函数名(参数列表){ //代码; retur ...

  5. javascript基础(五)函数

    原文http://pij.robinqu.me/ 通过call和apply间接调用函数(改变this) call 和 apply带有多个参数,call和apply把当前函数的this指向第一个参数给定 ...

  6. javascript基础知识-函数

    1.javascript中函数有两种定义方式: 函数语句定义和表达式定义 //函数有定义 function test(){ console.log("This is a function&q ...

  7. JavaScript基础——创建函数

    JavaScript的最重要的一个部分是制作其他代码可以重用的代码.要做到这一点,你可以把代码组织成执行特定任务的函数.函数是结合在一个单一的块中,并给予一个名称的一系列代码语句.然后,你就可以通过引 ...

  8. JavaScript基础之函数与数组

     函数    函数的基本概念 为完成某一功能的程序指令(语句)的集合,称为函数.有的程序员把函数称为方法,希望大家不要被这两个名词搞晕了. 函数分为:自定义函数.系统函数(经常查看js帮助手册). j ...

  9. javascript基础知识--函数定义

    函数声明式 function funname( 参数 ){ ...执行的代码 } 声明式的函数并不会马上执行,需要我们调用才会执行:funname(); * 分号是用来分隔可执行JavaScript语 ...

  10. javascript基础之函数

    javascript的函数定义与python有很大的区别,的记住格式就好,下面请看代码 // 函数 // 简单定义 function func() { console.log('hello word' ...

随机推荐

  1. what is archeage honor weapons?

    in my opinion,there are many kinds of weapons in archeage online, those include basic weapons and ma ...

  2. HTC A510C电信手机刷机过程

    HTC A510C电信手机刷机过程记录 Writed by Peter Hu(2014.6.7) ON WIN7_64 刷机需要的步骤: 1)  将S-ON加密保护式去掉,改成S-OFF模式,这样才能 ...

  3. sorttable

    http://rubaxa.github.io/Sortable/Sortable.js http://rubaxa.github.io/Sortable/Sortable.min.jshttp:// ...

  4. Rhel6-moosefs分布式存储配置文档

    MFS 特性: 1. Free(GPL) 2. 通用文件系统,不需要修改上层应用就可以使用 3. 可以在线扩容,体系架构可伸缩性极强. 4. 部署简单. 5. 高可用,可设置任意的文件冗余程度(提供比 ...

  5. Java read txt file

    package com.Yang; import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;i ...

  6. 使用GnuRadio+OpenLTE+SDR搭建4G LTE基站(上)

    0×00 前言 在移动互联网大规模发展的背景下,智能手机的普及和各种互联网应用的流行,致使对无线网络的需求呈几何级增长,导致移动运营商之间的竞争愈发激烈.但由于资费下调等各种因素影响,运营商从用户获得 ...

  7. HTMl5-canvas 入门级复习

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Java实现Restful框架Jersey学习

    Java与REST的邂逅(一):浅谈Jersey及JAX-RS Java与REST的邂逅(二):JAX-RS核心Annotation Java与REST的邂逅(三):浅谈Jersey MVC

  9. java 读写JSON(一)

    算是第一次正式接触Json,没有深入研究,先贴上java的代码,日后才说! package priv.chenhy.datehandle; import java.io.BufferedReader; ...

  10. linux系统io的copy

    #include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h&g ...