资讯专栏INFORMATION COLUMN

JavaScript函数(二)

用户84 / 2549人阅读

摘要:目录函数的声明函数的属性和方法函数的作用域闭包知识点小结关于函数,可以从以下个方面去理解首先,数据类型上看函数在中是一种数据类型,是对象的一种其次,从功能上看函数本质上是一段反复调用的代码块最后,从地位上看函数在中和其他基本数据类型一样,可

目录 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的相关介绍,详见【what"s this???】 3.函数的作用域

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

var a =1//a处于全局作用域

function fn(){
   var a = 2//a处于局部作用域,外部无法访问;
  return a;
}
a//1
fn()//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版)》

《JavaScript标准参考教程》——阮一峰

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86582.html

相关文章

  • 使用javascript实现排序叉树(1)

    摘要:使用实现排序二叉树排序二叉树的定义二叉树的基础上,左节点比父节点要小,右节点比父节点要大的二叉树,叫排序二叉树。下期内容实现排序二叉树的中序前序后续遍历实现二叉树的节点查找功能实现排序二叉树的删除节点功能应用排序二叉树实现一个小游戏 使用javascript实现排序二叉树(1) 排序二叉树的定义: 二叉树的基础上,左节点比父节点要小,右节点比父节点要大的二叉树,叫排序二叉树。 show...

    Caicloud 评论0 收藏0
  • 谈谈javascript语法里一些难点问题(

    摘要:讲作用域链首先要从作用域讲起,下面是百度百科里对作用域的定义作用域在许多程序设计语言中非常重要。原文出处谈谈语法里一些难点问题二 3) 作用域链相关的问题 作用域链是javascript语言里非常红的概念,很多学习和使用javascript语言的程序员都知道作用域链是理解javascript里很重要的一些概念的关键,这些概念包括this指针,闭包等等,它非常红的另一个重要原因就...

    Enlightenment 评论0 收藏0
  • JavaScript 设计模式():策略模式

    摘要:策略模式实现的也是类似的场景。第二个部分是环境类不变,接收客户的请求,随后把请求委托给某一个策略类。参考文章设计模式设计模式与开发实践设计模式系统讲解与应用本文首发,期待作者以乐之名本文原创,有不当的地方欢迎指出。 showImg(https://segmentfault.com/img/bVbugi7?w=800&h=600); 策略模式:定义一系列的算法,把它们一个个封装起来,并且...

    荆兆峰 评论0 收藏0
  • 进击JavaScript之()词法作用域与作用域链

    摘要:一作用域域表示的就是范围,即作用域,就是一个名字在什么地方可以使用,什么时候不能使用。概括的说作用域就是一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量。 一、作用域 域表示的就是范围,即作用域,就是一个名字在什么地方可以使用,什么时候不能使用。想了解更多关于作用域的问题推荐阅读《你不知道的JavaScript上卷》第一章(或第一部分),从编译原理的角度说明什么是作用域。概...

    denson 评论0 收藏0
  • 细数 JavaScript 实用黑科技()

    摘要:前言书接上文细数实用黑科技一本文介绍独孤九剑和两篇最高内功心法。可以将变量转换为布尔值。可以把任何类型的值转换为布尔值,并且只有当这个变量的值为的时候才会返回,其他情况都返回。同样的,函数体内部声明的函数,作用域绑定函数体内部。 showImg(https://segmentfault.com/img/remote/1460000016507838); 前言 书接上文:细数 JavaS...

    马忠志 评论0 收藏0
  • JavaScript学习总结()数组和对象部分

    摘要:属性是一个值或一组值以数组或对象的形式,是对象的成员。可以使用内置构造函数和创建包装对象。因此下面的代码将会使人很迷惑结果结果,此数组长度为应该尽量避免使用数组构造函数创建新数组。给数组对象添加返回数组中最大元素值的方法。 对象部分 Object类型 Object 是一个无序的集合,可以存放任意类型对象,所有其他对象都继承自这个对象。创建Object类型有两种,一种是使用new运算符,...

    Lsnsh 评论0 收藏0

发表评论

0条评论

用户84

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<