博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript函数(二)
阅读量:6471 次
发布时间:2019-06-23

本文共 3611 字,大约阅读时间需要 12 分钟。

目录

1.函数的声明

2.函数的属性和方法

3.函数的作用域

4.闭包知识点

5.小结


关于函数,可以从以下3个方面去理解:

首先,数据类型上看:函数在JavaScript中是一种数据类型,是对象的一种;
其次,从功能上看:函数本质上是一段反复调用的代码块;
最后,从地位上看:函数在JavaScript中和其他基本数据类型一样,可以作为参数和赋值,是“第一等公民”


1.函数的声明

声明函数的方式有三种:

1.声明式function fn(){  console.log(1)}fn()//1
2.表达式var fn = function(args){    console.log(args)}fn(a)//a
3.构造函数式var fn =  new Function("arg1","arg2","return arg1+arg2")fn(1,2)//3

函数本质上是对象的一种,所以函数名保存的实际上是指向函数对象的指针,第3种构造函数的方法对于理解“函数是对象,函数名是指针”的概念更加直观,但是第3种方法解析效率较低而且书写不简洁,所以一般不用构造函数方法去声明函数;

当声明式和表达式同时声明同一个函数时,表达式会覆盖声明式,原因是函数作为变量在js解析阶段进行变量提升,声明式和表达式都会提升至当前作用域头部,然后表达式会重新为fn赋值,从而覆盖声明式定义的函数;

function fn(){  console.log(1)}var fn = function(){  console.log(2)}fn()//2

关于return语句的理解,如果声明的函数没有return语句,则默认return undefined,否则返回定义的值;

var a  = function(){    console.log(1)}var b = function(){    return 2;}a() === undefined//true

2.函数的属性和方法

函数作为一个对象,同样拥有属性和方法,下面主要归纳一下比较常用和重要的属性和方法:

  • name属性:返回该函数名的字符串;

  • length属性:返回形参的个数,即预期传入参数的个数;

function fn (a,b){    console.log(fn.name)    console.log(fn.length)}fn()//"fn"  //2
  • arguments对象:是包含传入函数实参的类数组对象,只有在函数执行阶段并且存在参数才会有值,未调用函数是为null

function fn (a,b){  console.log(arguments)}fn(1,2)//[1,2]

arguments对象的length属性代表实参的个数,注意和函数的length属性的区别,函数的length代表形参的个数,arguments的length属性代表实参个数;
arguments对象有一个callee属性,返回arguments对象所在的函数指针
可以利用callee实现函数的递归,例如累加或阶乘操作:

function increment(arg){  if(arg === 1){    return 1  }  return arg+arguments.callee(arg-1)}function increMultipler(arg){  if(arg === 1){    return 1  }  return arg*arguments.callee(arg-1)}

这里另外提一个函数的caller属性,该属性保存调用当前函数的函数的引用,注意的是如果在全局作用域下读取该属性,值为null,因为顶层对象在浏览器中为window不是函数;

function outer(){  inner();}function inner(){  console.log(arguments.callee.caller)}outer();

  • this对象:代表函数执行时的环境对象,简单的说就是谁调用了该函数,this的指向是动态的,只有在函数调用时this对象才能确定;

//在浏览器全局环境下,即window对象下var print = function(){      console.log(this) }print()//this指向Window,因为这是Window对象调用了print方法//在特定对象的环境下var o = {    print: function(){      console.log(this)  }}o.print()//this指向o,因为这是o对象调用print方法

函数提供callapplybind3种方法可以改变this对象;

1.call方法function fn(){    return this}var o = {}fn() === this//true,this指向window对象fn.call(o) === o//true,this指向o对象//call方法还可以传入参数;function add(x,y){  return x+y}add.call(null,1,2)
2.apply方法,与call不同的是apply传入的参数为数组var arr = [1,2]function add(x,y){  return x+y}add.apply(null,arr)

实际上,apply和call的区别只在于传递参数的不同,它们真正强大的地方在于能够扩充函数赖以运行的作用域,比如slice函数原本只存在于数组当中,当中通过使用call方法,可以实现不同作用域下调用该方法;

function fn(a,b){      console.log(Array.prototype.slice.call(arguments)) }fn(1,2)//[1,2]

bind方法会创建一个函数实例,并将该函数的this对象绑定到传入该方法的参数;

function fn(){    return this}var o = {}var newFn =fn.bind(o) newFn() === o//true

更多this的相关介绍,详见

3.函数的作用域

作用域指的是变量存在的范围,作用域可分为全局作用域和局部作用域,变量在全局范围可访问到;局部作用域由函数所构造,变量只能在函数内部可访问到;

var a =1//a处于全局作用域function fn(){   var a = 2//a处于局部作用域,外部无法访问;  return a;}a//1fn()//2

值的注意的是,函数执行时所在的作用域是定义时所在的作用域,而不是调用时所在的作用域;

var a = 1;function fn(){  console.log(a)}function fn2(){  var a = 2;  fn()}fn2()//1

4. 闭包知识点

关于闭包的知识点,将会单独开一章节详谈,具体请看《JavaScript闭包(三)》


5.小结

通过《JavaScript函数(二)》,我们大致了解关于函数的知识点如下:

  • 函数本质上是一段反复调用的代码块,是对象的一种,在js中作为“第一等公民”,可以赋值和传参;

  • 函数声明的方法有3种:声明式、表达式和构造函数式;其中构造函数是能够直观理解函数的“函数是对象,函数名是指针”的概念;当表达式和声明式同时声明同名函数时,表达式会覆盖声明式,原因是变量提升的作用;

  • 函数作为对象,同样具有属性和方法;name返回该函数名的字符串,length返回形参的个数;

  • arguments对象是包含传入函数的实参的类数组对象,只有在执行阶段该对象才有值,未调用函数时为null,arguments.length表示实参的个数,arguments.callee返回arguments对象所在的函数的指针;

  • 函数的caller返回调用当前函数的函数的指针,在全局作用域下读取该属性为null;

  • this对象代表当前函数执行时的环境对象,this对象只有在函数执行阶段才能确定;

  • 可以使用call、apply和bind改变this的指向;call和apply的区别在于二者传递的参数不同,call为零散的数据,apply为数组,二者最大的用处是扩展函数的作用域;bind方法可以返回一个函数的实例,并绑定this对象至传入bind的参数;

  • 函数可以开辟一个独立的作用域,这使得js当中经典的闭包得以实现提供可能性;此外,函数执行时所在的作用域是在定义时所在的作用域,而不是调用时所在的作用域;


参考资料

  • 《JavaScript高级程序设计(第3版)》

转载地址:http://jevko.baihongyu.com/

你可能感兴趣的文章
Python基础进阶之路(一)之运算符和输入输出
查看>>
阻塞非阻塞异步同步 io的关系
查看>>
ClickStat业务
查看>>
DMA32映射问题
查看>>
POJ 1269 Intersecting Lines(判断两直线位置关系)
查看>>
spring3.0.7中各个jar包的作用总结
查看>>
Windows 10 /win10 上使用GIT慢的问题,或者命令行反应慢的问题
查看>>
梯度下降(Gradient descent)
查看>>
Windows平台分布式架构实践 - 负载均衡
查看>>
最容易理解的对卷积(convolution)的解释
查看>>
iOS自定制tabbar与系统的tabbar冲突,造成第一次点击各个item图片更换选中,第二次选中部分item图片不改变...
查看>>
SVN服务器使用(二)
查看>>
反射获取内部类以及调用内部类方法
查看>>
App里面如何正确显示用户头像
查看>>
DATAGUARD维护:从库宕机后如何恢复到管理恢复模式
查看>>
U-BOOT之一:BootLoader 的概念与功能
查看>>
我的路上
查看>>
Velocity处理多余空白和多余空白行问题
查看>>
java值传递
查看>>
DB2与oracle有什么区别
查看>>