热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

函数Javascript语法基础Javascript核心

原文:http:pij.robinqu.meJavaScript_CoreJavaScript_BasicsFunction.html源代码:https:github.comRob

原文: http://pij.robinqu.me/Javascript_Core/Javascript_Basics/Function.html

源代码: https://github.com/RobinQu/Programing-In-Javascript/blob/master/chapters/Javascript_Core/Javascript_Basics/Function.md

本文存在批注,但该网站的Markdown编辑器不支持,所以无法正常展示,请到原文参考。

函数

Javascript中,要记住函数是first-class citizen。

定义

  • 函数声明语句

    function plus(x ,y) {
    }

  • 函数定义表达式

    var plus = function (x, y) {
    }

函数调用

  • 作为函数调用

    function a(){};
    a();

  • 作为方法调用

    a={};
    a.x = function(){};
    a.x();

  • 通过call和apply间接调用函数(改变this)

call 和 apply带有多个参数,call和apply把当前函数的this指向第一个参数给定的函数或对象中,并传递其余所有的参数作为当前函数的参数。

var O = function () {
this.foo = 'hello';
this.hello = function () {
return 'world';
}
};
var fn = function () {
console.log('call', this);
};
var o = new O();
fn.call(o);//此时fn的this指向o

call和apply的不同之处,在于call传递的参数是作为arguments依次传入的,例如

fn.call(o, 1, 2, 3);
而apply传递的参数是以一个数组的方式传入的,例如
fn.apply(o, [1, 2, 3]);

参数

当传入参数少于函数声明的参数时,留空的参数的值是undefined

Javascript允许传入参数的个数大于声明时制定的参数个数。可以用arguments来访问这些参数

function f(){
var i;
for( i = 0; i console.log(arguments[i]);
}
}
f(1,2,3,4,5,6);

函数通过取得arguments的长度得到传入参数的个数,使用一个循环获取每一个参数。

arguments还有两个属性,calleecaller
callee表示正在执行的function对象,
caller表示调用当前function的function

例如

function f(){
console.log(arguments.callee);//[Function: f]
console.log(arguments.callee.caller);[Function: g]
var i;
for( i = 0; i console.log(arguments[i]);
}
}
function g(){
f(1,2,3,4,5,6);
}
g();

callee 的重要用法之一是在匿名函数中实现递归

var result = function (x) {
if (x <= 1) return 1;
return x * arguments.callee(x - 1);
}(3);
console.log(result);

上例使用了一个匿名函数和callee实现了一个阶乘。

作为值的函数

Javascript中的函数可以作为值来传递

function square(x) {
return x * x;
}
var s = square;
s(4);

作为命名空间的函数

(function() {
}());

闭包

Javascript函数对象的内部状态不仅包含着函数的代码逻辑,还引用当前的作用域链。函数对象通过作用域链相互关联起来,函数体内部变量包含在函数作用域内,这就叫闭包。

例如

var scope = 'global scope';
function checkscope() {
var scope = 'local scope';
function f() {
return scope;
}
return f;
}
checkscope()();

这段checkscope声明了一个局部变量,定义了一个函数f,函数f返回了这个局部变量的值,最后返回了这个函数f。在定义函数f的作用域外调用f,得到的返回仍然是函数f创建时所在的作用域的局部变量scope。

又例如

var counter = (function() {
var count = 0;
return function () {
return count++ ;
}
}());

代码定义了一个立即执行函数并返回给counter,这个函数定义了一个局部变量count,返回了一个子函数,该子函数每次调用,都会吧count加一并返回。

闭包的注意事项

观察下面的示例:

var add_the_handlers = function (nodes) {
var i;
for (i = 0; i nodes[i].Onclick= function (e) {
alert(i);
};
}
};

这个函数期望的结果,是在运行的时候为每个node在onclick的时候alert出各自的序号,但是实际运行的结果却不同:所有的node在单击的时候alert出来的数字总是同一个。

这是因为alert所在的匿名函数的闭包中存放的i是第一行的i,而不是在循环中获得的i的当前值。

所以如果希望达到预期结果,应该在循环中创建多个闭包,在闭包中存放当前循环的i的值:

var add_the_handlers = function (nodes) {
var i;
for (i = 0; i nodes[i].Onclick= function (i) {
return function(e){
alert(e);
};
}(i);
}
};

这里使用一个立即执行函数并传递当前的i的值,返回一个新生成的函数。在这个新生成的函数的闭包中就保存了当前的i的值。

函数中的this对象

在一个对象中的this始终引用当前对象,但是在函数中,特别是在闭包中,this有一些特殊的行为。

函数中的this对象始终绑定在函数运行时的上下文环境上。所以在普通模式下调用一个全局函数,this始终指向window(客户端),在严格模式下调用一个全局函数,this始终是undefined

示例

var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function () {
return function () {
return this.name;
};
},
getName : function () {
return this.name;
}
};
console.log(object.getNameFunc()());
console.log(object.getName());

getNameFunction()返回了一个匿名函数,这个匿名函数在调用的时候,上下文是window(浏览器中),所以在浏览器中输出的是the Window

而getName()调用的时候上下文是object,所以成功输出object的name

其实以上代码中
object.getNameFunc()()
等效于
var fnc = object.getNameFunc();//这时候的fnc已经脱离了object对象
fnc();

所以如果想要getNameFunction()正确返回Object的Name,需要在返回的匿名函数的闭包中保存在函数声明时的this,

getNameFunc: function () {
var that = this;
return function () {
return that.name;
};
},

这样就可以了。。

函数柯里化

函数柯里化是指,把接受多个参数的函数转换成接受一个单一参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

示例

var add1 = add.curry(1);
console.log(add1(2));

其中,add是接受两个参数的函数,add调用了curry返回一个只接受一个参数的新函数,之后调用add1便等效于调用add(1, 2);

Javascript并不原生支持curry,可以用prototype来模拟

Function.prototype.curry = function () {
var slice = Array.prototype.slice,
args = slice.apply(arguments),
that = this;
return function () {
return that.apply(null, args.concat(slice.apply(arguments)));
};
};
function add(n1, n2) {
return n1 + n2;
}
var add1 = add.curry(1);
console.log(add1(2));

curry创建了一个新函数,在新函数的闭包中保存了原先传递的参数。

函数的属性和方法

  • length 函数的length表示函数实参的数量,是只读的
  • prototype 指向一个该函数的原型对象的引用
  • toString 返回一个字符串

推荐阅读
  • 本文探讨了使用JavaScript在不同页面间传递参数的技术方法。具体而言,从a.html页面跳转至b.html时,如何携带参数并使b.html替代当前页面显示,而非新开窗口。文中详细介绍了实现这一功能的代码及注释,帮助开发者更好地理解和应用该技术。 ... [详细]
  • C++ 开发实战:实用技巧与经验分享
    C++ 开发实战:实用技巧与经验分享 ... [详细]
  • Golomb 编码是一种高效的变长编码技术,专门用于整数的压缩。该方法通过预定义的参数 \( M \) 将输入整数分解为商 \( q \) 和余数 \( r \) 两部分。具体而言,输入整数除以 \( M \) 得到商 \( q \) 和余数 \( r \),其中商 \( q \) 采用一元编码表示,而余数 \( r \) 则使用二进制编码。这种编码方式在数据压缩和信息传输中具有显著的优势,特别是在处理具有特定概率分布的数据时表现出色。 ... [详细]
  • jQuery Flot 数据可视化插件:高效绘制图表的专业工具
    jQuery Flot 是一款高效的数据可视化插件,专为绘制各种图表而设计。该工具支持丰富的图表类型和自定义选项,适用于多种应用场景。用户可以通过其官方网站获取示例代码和下载资源,以便快速上手和使用。 ... [详细]
  • 【前端开发】深入探讨 RequireJS 与性能优化策略
    随着前端技术的迅速发展,RequireJS虽然不再像以往那样吸引关注,但其在模块化加载方面的优势仍然值得深入探讨。本文将详细介绍RequireJS的基本概念及其作为模块加载工具的核心功能,并重点分析其性能优化策略,帮助开发者更好地理解和应用这一工具,提升前端项目的加载速度和整体性能。 ... [详细]
  • 深入解析:Synchronized 关键字在 Java 中对 int 和 Integer 对象的作用与影响
    深入探讨了 `Synchronized` 关键字在 Java 中对 `int` 和 `Integer` 对象的影响。尽管初看此题似乎简单,但其实质在于理解对象的概念。根据《Java编程思想》第二章的观点,一切皆为对象。本文详细分析了 `Synchronized` 关键字在不同数据类型上的作用机制,特别是对基本数据类型 `int` 和包装类 `Integer` 的区别处理,帮助读者深入理解 Java 中的同步机制及其在多线程环境中的应用。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • 在 Axublog 1.1.0 版本的 `c_login.php` 文件中发现了一个严重的 SQL 注入漏洞。该漏洞允许攻击者通过操纵登录请求中的参数,注入恶意 SQL 代码,从而可能获取敏感信息或对数据库进行未授权操作。建议用户尽快更新到最新版本并采取相应的安全措施以防止潜在的风险。 ... [详细]
  • 本文将继续探讨 JavaScript 函数式编程的高级技巧及其实际应用。通过一个具体的寻路算法示例,我们将深入分析如何利用函数式编程的思想解决复杂问题。示例中,节点之间的连线代表路径,连线上的数字表示两点间的距离。我们将详细讲解如何通过递归和高阶函数等技术实现高效的寻路算法。 ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • REST与RPC:选择哪种API架构风格?
    在探讨REST与RPC这两种API架构风格的选择时,本文首先介绍了RPC(远程过程调用)的概念。RPC允许客户端通过网络调用远程服务器上的函数或方法,从而实现分布式系统的功能调用。相比之下,REST(Representational State Transfer)则基于资源的交互模型,通过HTTP协议进行数据传输和操作。本文将详细分析两种架构风格的特点、适用场景及其优缺点,帮助开发者根据具体需求做出合适的选择。 ... [详细]
  • 微信平台通过盛派SDK(sdk.weixin.senparc.com)允许服务号和订阅号使用appId和token读取关注用户的个人信息。然而,这一过程需严格遵守隐私保护和数据安全的相关规定,确保用户数据的安全性和隐私性。 ... [详细]
author-avatar
葬宝御用小奶瓶2004
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有