JavaScript中的函数

1. 函数的定义

  • 两种定义形式:

    • 通过函数定义表达式来定义
    • 通过函数声明语句来定义

函数声明语句定义一个函数

//计算阶乘的递归函数

function factorial(x){
if (x<=1) return 1;
return x*factotial(x-1);
}

函数定义表达式定义一个函数

var s= function sum(x,y){
return x+y;
}

tips:以表达式方式定义的函数(特别适合用来定义那些只会用到一次的函数),函数名是可选的,
也就可以直接写成这样

var s= function(x,y){
return x+y;
}

2.函数命名

  • 函数的名称通常是动词或者以动词为前缀的词组 如:funciton saveMessage(){}
  • 函数名的第一个字符通常为小写
  • 当我们命名的函数名比较长时,一种是驼峰式命名 如:function readSystemFile(){}
    另一种是以下划线分割单词,如:function make_products_iPhones(){}
  • 有一些函数是用作内部函数或者私有函数的,通常以一条下划线为前缀。 如: _login()

3.函数的调用

  • 普通的函数调用

example:

printprops({x:1})
var total = distance(0,1,2)+ distance(3,4,5)
var probability = factorial(5)/factoral(10)
  • 对象方法的调用

概念:如果函数表达式是一个属性访问表达式(即该函数是一个对象的属性或者数组的一个函数),
那么该调用表达式就是一个方法调用表用表达式。
example:

//定义一个对象
var person = {
name: lihua ,
age: 18 ,
sex: 女 ,
send: function(){//返回 person的name、age、sex
this.message = this.name + this.age + this.age;
}
};
person.send();//这条语句就是函数的方法调用
person.message; //得到name、age、sex相关信息

tips:
1.函数返回的值倘若是因为解释器到达结尾,返回值就是undefined;倘若函数返回是因为解释器执行到一条return语句,
则返回return语句后面的值;如果return语句后面没有值则返回undefined。
2.在ECMAScript3和在非严格模式下的ECMAScript5的函数调用规定中,this的值(调用上下文)的值是全局对象,但是在
严格模式下this的值却是undefined,因此可也用this来判断当前环境是否为严格模式,此外ECMAScript2015 (简称es6)严格模式请参考以下地址。
ECMAScipt的第六个版本  https://developer.mozilla.org/zh-CN/
3.方法调用和普通的函数调用的一个重要区别就是:调用上下文(即this的值),通常this关键字指向成为调用上下文的对象,
属性访问表达式:对象名.方法名(通常使用.运算符访问属性)或者"[]"进行属性访问操作。(this关键字的相关内容是十分重要的)
更多this相关内容请参看此链接

  • 构造函数的调用

构造函数就是用来初始化先创建的对象,通常使用关键字new来调用构造函数,当使用new关键字来调用构造函数的时候就会自动
创建一个新的的空对象,而构造函数只需要初始化这个新对象的状态(属性和方法),调用构造函数的话,新的对象的原型(prototype)等于
构造函数的原型(prototype)属性,由此引出一个特性:通过同一个构造函数创建的所有对象都继承同一个相同的对象。

凡是没有形参的构造函数都可以省略圆括号,以下两行代码是等价的。
var fn = new Object();
var fn = new Object;

tips:
1.构造函数通常不使用return关键字,进行初始化新对象,执行完函数体,就调用构造函数表达式的计算结果作为新对象的值,显示返回。
2.倘若构造函数使用return语句返回一个对象,那么调用表达式的值就是这个对象,而不是this指向的对象。
3.构造函数里没有显式调用return时,默认是返回this对象,也就是新创建的实例对象。
4.return的是五种简单数据类型:String,Number,Boolean,Null,Undefined。这种情况下,忽视return值,依然返回this对象

  • 间接调用
    JavaScript中的函数也是对象,所以函数对象也可以包含方法。函数的间接调用用到的call()和apply()方法。
    这两个方法都能显示指定调用所需的this的值,这就引出一个特性:任何函数都可以作为对象的方法来调用,
    哪怕这个函数不是那个对象的方法。(这也就是在实际开发中我们也会常用这两个方法的原因之一)

1.call()方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表) this的值并不一定就是该函数执行真正的this值,在非严格模式下,倘若this的值指向nullundefined的话
会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。
2.apply()方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
为this指定一个对象,使用apply时只需要写一次这个方法然后再另一个对象中继承它,继而不用在这个新的对象重新来写它。

tips:call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。

4.函数中的形参与实参

  • 可选的形参
  • 可变长的实参列表:实参对象 arguments 它是一个类数组对象,通过数字下表就能够访问传入函数的实参值,它包含length属性,让函数可以操作任意数量的实参。
  • callee和caller属性
    callee属性指代当前正在执行的函数,caller指代调用当前正在执行的函数的函数,它可以访问栈。而callee可以来递归调用自身。

5.函数的闭包(!important)

  • 概念:通俗地讲函数的闭包就是在一个函数内部定义另一个函数,而这个内部的函数(子函数)可以调用包裹它的函数(父函数等、"爷爷、太爷爷...")的变量。
    也可以认为闭包就是能够读取其他函数内部变量的函数。
  • 变量作用域:
    全局变量:任何函数内部都可以访问全局作用域
    局部变量:在函数外部无法读取变量

tips
javascript是没有像Java、C++那样用一对“{}”括起来的块级作用域,但是在es6中可以使用let关键字实现块级作用域。

  • 词法作用域:变量的作用域是在定义时决定而不是执行时决定,也就是说词法作用域取决于源码,通过静态分析就能确定,因此词法作用域也叫做静态作用域。
    with和eval除外,所以只能说JS的作用域机制非常接近词法作用域(Lexical scope)。
var scope = "global scope";
function checkScope(){
var scope = "local scope";
function f(){return scope;}
return f();
}
checkScope(); //输出可以得到 local scope
  • 闭包的用途
    i. 读取函数内部的变量、函数嵌套函数
    ii. 让这些变量的值始终保持在内存中(全局变量的值不会在被函数调用过后自动清除,由GC回收)
    iii. 避免全局变量的污染、让私有成员存在

  • 闭包的注意事项
    i. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露
    解决方法是,在退出函数之前,将不使用的局部变量全部删除。
    ii. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),
    把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
    以下例子来检验自己是否已经掌握了闭包的运行机制。
    example 0ne:

  var name = "The Window";

  var object = {
    name : "My Object",     getNameFunc : function(){
      return function(){
        return this.name;
      };     }   };   alert(object.getNameFunc()());

example Two:

  var name = "The Window";

  var object = {
    name : "My Object",     getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };     }   };   alert(object.getNameFunc()());

6.函数的属性、方法以及构造函数

  • length属性
    argument.length属性表示传入函数的实参的个数,而函数本身的length属性则有不同含义,它表示函数定义时的实际形参个数。
  • prototype(原型)属性
    这个属性指向对象的引用,而这个对象就被称为原型对象(prototype object),每个函数都包含这个属性,都包含不同的原型对象;
    在JavaScript中每个函数都有一个特殊的属性叫作原型(prototype)
function doSomething(){}
console.log(doSomething.prototype);
-----------------------------------
结果: 这就是 原型对象
{
constructor: ƒ doSomething(), //构造函数
/* 这些又是这个构造函数里面的方法或者属性
arguments: null
caller: null
length: 0
name: "doSomething"
prototype: {constructor: ƒ} 构造函数的原型属性
__proto__: ƒ ()*/ __proto__: { //原型属性
constructor: ƒ Object(),
hasOwnProperty: ƒ hasOwnProperty(),
isPrototypeOf: ƒ isPrototypeOf(),
propertyIsEnumerable: ƒ propertyIsEnumerable(),
toLocaleString: ƒ toLocaleString(),
toString: ƒ toString(),
valueOf: ƒ valueOf()
}
}
-------------------------------
function doSomething(){}
doSomething.prototype.eat = "food" //doSomething函数的原型(prototype)属性对象添加eat的属性
var doSomeInstancing =new doSomething() //创建doSomething函数的实例 通过new关键字来调用该函数,它返回这个函数的实例化对象给doSomeInstancing
doSomeInstancing.prop = "add value"; //给对象doSomeInstancing添加一个“name为prop值为add value”的属性
console.log(doSomeInstancing); //输出这个doSomeIntancing对象 结果现实这个对象有两个属性,一个是:prop: "add value" 另一个是:__proto__: Object
console.log(doSomething.prototype); //输出doSomething.prototype的值是一个对象{eat: "food",constructor: ƒ doSomething(), __proto__: Object
显然doSomeInstancing.__proto__属性与doSomething.prototype(构造函数的原型属性的值是相同)它们的值是相等的。(可以通过===来判断 __ptototype__为隐式原型)
  • call()、apply()和bind()方法 在前面的函数的间接调用中已经介绍了call()以及apply(),在这里就不再叙说,就详细介绍ECMAScript5新增的bind()方法

bind()方法中的bind翻译过来就是捆绑、绑定之意,作用就是将函数绑定至某个对象中,倘若一个函数调用了bind()方法并传入一个对象作为参数,那么这个方法将返回新的函数。

function f(y){return this.x+y;} //待绑定的函数
var o = {x :1};//将要被绑定的对象
var g = f.bind(o); //将函数f绑定至对象o 相当于var o={x:1, f:function f(y){return this.x+y;}}
console.log(g(2)); //通过g(y)调用o.f(y) 输出3

bind()方法除了除了第一个实参之外,传入bind()的实参也会绑定至this.这种应用是一种常见的函数式编程技术,被称为柯里化(currying)

var sum = function(x,y){return x+y;}
var succ = sum.bind(null,1);
succ(2)
    • toString()方法
      该方法返回字符串
    • Function()构造函数
    • 高阶函数
      • 记忆(memorization)

JavaScript篇 深入理解JavaScript函数的更多相关文章

  1. JavaScript大杂烩1 - 理解JavaScript的类型系统

    随着硬件水平的逐渐提高,浏览器的处理能力越来越强大,本人坚信,客户端会越来越瘦,瘦到只用浏览器就够了,服务端会越来越丰满:虽然很多大型的程序,比如3D软件,客户端仍然会存在,但是未来的主流必将是浏览器 ...

  2. 深入理解JavaScript系列+ 深入理解javascript之执行上下文

    http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html http://blog.csdn.net/hi_kevin/article/d ...

  3. JavaScript之深入理解【函数】

    一 参考文献 <JavaScript忍者秘籍>   二 函数特征总结 1. 函数是[第一型对象(first-class object)]:可以像这门语言的其它对象一样使用 函数可以共处,可 ...

  4. JavaScript大杂烩2 - 理解JavaScript的函数

    JavaScript中的字面量 书接上回,我们已经知道在JavaScript中存在轻量级的string,number,boolean与重量级的String,Number,Boolean,而且也知道了之 ...

  5. 【JavaScript】深入理解JavaScript之强大的原型和原型链

    由于JavaScript是唯一一个被广泛使用的基于原型继承的语言,所以理解两种继承模式的差异是需要一定时间的,今天我们就来了解一下原型和原型链. AD: hasOwnProperty函数: hasOw ...

  6. 高质量的javascript代码 -- 深入理解Javascript

    一. 编写高质量的javascript代码基本要点a) 可维护的代码(Writing Maintainable Code)i. 可读(注释)ii. 一致(看上去是同一个人写的)iii. 已记录b) 最 ...

  7. JavaScript大杂烩6 - 理解JavaScript中的this

    在JavaScript开发中,this是很常用的一个关键字,但同时也是一个很容易引入bug的一个关键字,在这里我们就专门总结一下页面中可能出现的this关键字(包括几种在其他页面文件中出现的this) ...

  8. JavaScript大杂烩4 - 理解JavaScript对象的继承机制

    JavaScript是单根的完全面向对象的语言 JavaScript是单根的面向对象语言,它只有单一的根Object,所有的其他对象都是直接或者间接的从Object对象继承.而在JavaScript的 ...

  9. JavaScript大杂烩3 - 理解JavaScript对象的封装性

    JavaScript是面向对象的 JavaScript是一种基于对象的语言,你遇到的所有东西,包括字符串,数字,数组,函数等等,都是对象. 面向过程还是面向对象? JavaScript同时兼有的面向过 ...

随机推荐

  1. 每日分享!JavaScript的鼠标事件(11个事件)

    鼠标的11个事件 具体的事件解释如下: click:按下鼠标(通常是按下主按钮)时触发. dblclick:在同一个元素上双击鼠标时触发. mousedown:按下鼠标键时触发. mouseup:释放 ...

  2. redis的bigkey扫描脚本

    众所周知,redis里面的大key存在是非常危险的一件事情.因为最近的工作转移到中间件相关的工作,因此关注了一下bigkey的扫描方法.首先介绍一下阿里云提供的扫描脚本: 具体可见:https://y ...

  3. NET 泛型,详细介绍

    今天的文章是因为再给一个朋友讲这个的时候随手记录下整理出来的.说白了就是把前辈们曾经给我吹过的我又吹了出去. 泛型:是C# FrameWork 2.0 时代 加入进来的,可以说对与Net开发人员来说泛 ...

  4. 软件开发架构介绍||OSI七层协议之物理层、数据链路层、网络层、传输层(mac地址、ip协议、断开协议、tcp协议之三次握手四次挥手)

    一.网络编程 软件开发架构 C/S架构 C:客户端 想体验服务的时候才会去找服务端体验服务 S:服务端   24小时不间断的提供服务,即时监听,随时待命 B/S架构 B:浏览器    想体验服务的时候 ...

  5. openlayers4 入门开发系列之船讯篇

    前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...

  6. 【译】MongoDb vs Mysql—以NodeJs为例

    亲爱的读者,您可能想知道为什么要写关于MongoDb和MySql这篇文章.那是因为我与NodeJs开发人员讨论在应用程序中使用哪种数据存储作为主要的数据存储方式. 我看过很多评论都在争论这个问题. 有 ...

  7. windows update error 0x8024401c

    Error 0x8024401c 以管理员身份运行-命令提示符 执行以下3条命令 net stop wuauserv reg delete HKEY_LOCAL_MACHINE\SOFTWARE\Po ...

  8. Kali Linux 渗透测试手册(1.1)安装虚拟机

    翻译来自:掣雷小组 成员信息: thr0cyte, Gr33k, 花花, 小丑, R1ght0us, 7089bAt, 一.配置KALI Linux和渗透测试环境 在这一章,我们将覆盖以下内容: 在W ...

  9. 最短路问题之Bellman-ford算法

    题目: 最短路:给定两个顶点,在以这两个点为起点和终点的路径中,边的权值和最小的路径.考虑权值为点之间的距离. 单源最短路问题,Bellman-ford算法 思路:每次循环检查所有边,可优化. 应用于 ...

  10. 距离度量以及python实现(一)

    1. 欧氏距离(Euclidean Distance)        欧氏距离是最易于理解的一种距离计算方法,源自欧氏空间中两点间的距离公式. (1)二维平面上两点a(x1,y1)与b(x2,y2)间 ...