函数

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 < arguments.length ; 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 < arguments.length ; 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.length; i += 1) {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.length; i += 1) {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 返回一个字符串

转载:http://pij.robinqu.me/JavaScript_Core/JavaScript_Basics/Function.html

Javascript语法基础 - Javascript核心(一)相关推荐

  1. 读书笔记(06) - 语法基础 - JavaScript高级程序设计

    写在开头 本篇是小红书笔记的第六篇,也许你会奇怪第六篇笔记才写语法基础,笔者是不是穿越了. 答案当然是没有,笔者在此分享自己的阅读心得,不少人翻书都是从头开始,结果永远就只在前几章. 对此,笔者换了随 ...

  2. JavaScript 逆向 ( 一 ) --- JavaScript 语法基础

    js 逆向:https://www.cnblogs.com/wuxianyu/category/1940304.html js逆向2:https://www.cnblogs.com/wuxianyu/ ...

  3. Javascript语法基础之按钮点击事件

    Hello everyone,This is Kaylee. 这是一篇简单的JS语法基础内容,是在我学习过程中,比较难以记忆的知识点,我将搭配案例详解展示给大家,通过这种方式可以加深记忆,方便应用. ...

  4. 【JavaScript总结】JavaScript语法基础:JS编码

    运算符 数学:+. -. *. / 逻辑:>. < .>= .<=. == . !=.&&.|| . === .!==(完全等于) 对象相关 new delet ...

  5. 【JavaScript总结】JavaScript语法基础:数据类型

    ------>数据类型有哪些? ->基本类型:数字类型,布尔类型,字符串类型 ->引用类型:对象类型,函数类型 ->空类型:null 和 undefined ->运算符: ...

  6. JavaScript 语法基础

    2019独角兽企业重金招聘Python工程师标准>>> •JavaScript是浏览器端脚本语言,是一种基于对象(Object)和事件驱动(Event Driven)的脚本语言. • ...

  7. JavaScript语法基础:JS运算符

    第1关:JavaScript知识训练-运算符 1.在JavaScript中,两个整数进行除(/)运算,其结果也为整数. B. 错误 2.x={x:1};y={y:1};z=1;n='1'下面结果为tr ...

  8. 【JavaScript总结】JavaScript语法基础:JS高级语法

    作用域链: 1.JS中只有函数能够限定作用域的范围: 2.变量处理在制定的函数范围内,还有一个特殊的作用域,就是没有用var 声明的全局作用域 3.js中的作用域链是为了清晰的表示出所有变量的作用范围 ...

  9. 【JavaScript总结】JavaScript语法基础:DOM

    ->DOM的理解:文档对应dom树 ->有了DOM能做什么:DOM的操作 html文档做为DOM树模型,DOM树的节点就是对象.对象会触发事件来执行一些事件代码. C#中的事件是一个委托变 ...

最新文章

  1. mysql服务启动很久_Mysql服务启动问题
  2. get方法报空指针_C++基础教程之指针拷贝详解
  3. oracle获取SID
  4. 根据线程名获取线程及停止线程
  5. ORA-28000 the account is locked的解决办法
  6. [多线程系列]多线程之java线程池架构分析
  7. 想不明白:为什么龙芯取消了MIPS版OpenJDK8开源
  8. Java动态so库修改,Adnroid so文件动态调试技巧
  9. 千锋重庆IT学习之微信API接口文档
  10. 算法图解————K 近邻算法
  11. 面试案例-String Interpolation的实现(Java实现)
  12. 怎么测试网站访问速度?
  13. 编辑中的word变成只读_word只读模式怎么改 word保存文件提示此文件为只读无法保存修改方法...
  14. Gameplay Ingredients
  15. 想在社会上混 就记住这20句
  16. 直方图中bins应如何理解及处理
  17. php 直接显示缩略图,PHP自动生成缩略图函数的源码示例
  18. PNG图片转换word文档,不用下载软件,免费完成
  19. 三极管的工作条件及工作状态的判断
  20. iOS-苹果开发者账号申请之邓白氏编码申请

热门文章

  1. Bsie(鄙视IE)
  2. Linux 字符集问题
  3. mysqldump 也可使用where条件导出的
  4. 海明码知识透析--网工必备
  5. 可视化报表Superser
  6. 使用数据分析工具的注意事项
  7. Python生成二维码-qrcode
  8. 盐城大数据产业园人才公寓_盐城市大数据产业园获评大众创业万众创新示范基地...
  9. 西门子1500和300哪个贵_西门子S7-1500凭什么秒杀S7-300-400?
  10. java退出函数_如何更新线上的 Java 服务器代码