JavaScript世界的一等公民
JavaScript世界的一等公民 - 函数
提交新文章
2012年07月11日 09:00 | |
简介
一、JavaScript函数入门级
- // 直接声明函数myfunc
- function myfunc(/* arguments */) {
- }
- // 把匿名函数赋值给本地变量myfunc
- var myfunc = function(/* arguments */) {
- }
// 直接声明函数myfunc
function myfunc(/* arguments */) {
}// 把匿名函数赋值给本地变量myfunc
var myfunc = function(/* arguments */) {
}
注意,上面两种函数声明方式存在细微的差别:第一种方式在声明时就是一个命名的函数,无论是声明在调用之前、调用之后,甚至是不会执行到的位置(例如return语句之后或是永远不会为真的分支里),都在整个作用域可访问;第二种方式是通过把匿名函数赋值给变量的方式,严格意义上说这不是一个函数的声明(function declaration)而是一个函数表达式(function expression),在赋值之前这个函数不能被任何代码访问到,也就是说这个赋值必须在调用之前完成,否则调用时会出现错误:"TypeError: undefined is not a function"。例如:
- myfunc1(); // 能够正常调用,因为myfunc1采用直接声明的方式
- function myfunc1() {
- }
- myfunc2(); // 出错 TypeError: undefined is not a function
- var myfunc2 = function() {
- };
myfunc1(); // 能够正常调用,因为myfunc1采用直接声明的方式function myfunc1() {
}myfunc2(); // 出错 TypeError: undefined is not a functionvar myfunc2 = function() {
};
- function fib(n) {
- if (n == 1 || n == 2) {
- return 1;
- } else {
- return fib(n - 2) + fib(n - 1);
- }
- }
function fib(n) {if (n == 1 || n == 2) {return 1;} else {return fib(n - 2) + fib(n - 1);}
}
- function test() {
- alert(arguments.length);
- }
- test(1); // 1
- test(1, 'a'); // 2
- test(true, [], {}); // 3
function test() {alert(arguments.length);
}test(1); // 1
test(1, 'a'); // 2
test(true, [], {}); // 3
利用arguments可以实现类似C语言printf的功能,也可以用来实现方法的多态。
二、JavaScript函数进阶
- (function() { // 匿名函数
- function log(msg) {
- console.log(msg);
- }
- // 其他代码
- }()); // 立即执行
(function() { // 匿名函数function log(msg) {console.log(msg);
}// 其他代码}()); // 立即执行
以上代码就是一个简单的示例,log函数的作用域被限制在这个匿名函数之内,而匿名函数则因为被外面一对小括号()包括起来,形成一个函数表达式,表达式的值是一个函数,紧接着一对小括号表示立即执行这个函数,让原有的代码正常执行一次。不过,这种方式声明的函数、通过var声明的变量等等都是内部的,不能被任何匿名函数以外的代码访问到。如果你需要对外暴露一些函数作为接口的话有如下几种方法:
- var mylib = (function(global) {
- function log(msg) {
- console.log(msg);
- }
- log1 = log; // 法一:利用没有var的变量声明的默认行为,在log1成为全局变量(不推荐)
- global.log2 = log; // 法二:直接在全局对象上添加log2属性,赋值为log函数(推荐)
- return { // 法三:通过匿名函数返回值得到一系列接口函数集合对象,赋值给全局变量mylib(推荐)
- log: log
- };
- }(window));
var mylib = (function(global) {function log(msg) {console.log(msg);
}log1 = log; // 法一:利用没有var的变量声明的默认行为,在log1成为全局变量(不推荐)global.log2 = log; // 法二:直接在全局对象上添加log2属性,赋值为log函数(推荐)return { // 法三:通过匿名函数返回值得到一系列接口函数集合对象,赋值给全局变量mylib(推荐)log: log
};}(window));
- function negative(n) {
- return -n; // 取n的相反值
- }
- function square(n) {
- return n*n; // n的平方
- }
- function process(nums, callback) {
- var result = [];
- for(var i = 0, length = nums.length; i < length; i++) {
- result[i] = callback(nums[i]); // 对数组nums中的所有元素传递给callback进行处理,将返回值作为结果保存
- }
- return result;
- }
- var nums = [-3, -2, -1, 0, 1, 2, 3, 4];
- var n_neg = process(nums, negative);
- // n_neg = [3, 2, 1, 0, -1, -2, -3, -4];
- var n_square = process(nums, square);
- // n_square = [9, 4, 1, 0, 1, 4, 9, 16];
function negative(n) {return -n; // 取n的相反值
}function square(n) {return n*n; // n的平方
}function process(nums, callback) {var result = [];for(var i = 0, length = nums.length; i < length; i++) {result[i] = callback(nums[i]); // 对数组nums中的所有元素传递给callback进行处理,将返回值作为结果保存}return result;
}var nums = [-3, -2, -1, 0, 1, 2, 3, 4];
var n_neg = process(nums, negative);
// n_neg = [3, 2, 1, 0, -1, -2, -3, -4];
var n_square = process(nums, square);
// n_square = [9, 4, 1, 0, 1, 4, 9, 16];
- function generator() {
- var i = 0;
- return function() {
- return i++;
- };
- }
- var gen1 = generator(); // 得到一个自然数生成器
- var gen2 = generator(); // 得到另一个自然数生成器
- var r1 = gen1(); // r1 = 0
- var r2 = gen1(); // r2 = 1
- var r3 = gen2(); // r3 = 0
- var r4 = gen2(); // r4 = 1
function generator() {var i = 0;return function() {return i++;};
}var gen1 = generator(); // 得到一个自然数生成器
var gen2 = generator(); // 得到另一个自然数生成器
var r1 = gen1(); // r1 = 0
var r2 = gen1(); // r2 = 1
var r3 = gen2(); // r3 = 0
var r4 = gen2(); // r4 = 1
- var elem = document.getElementById('test');
- elem.addEventListener('click', function() {
- alert('You clicked ' + elem.tagName);
- });
var elem = document.getElementById('test');
elem.addEventListener('click', function() {alert('You clicked ' + elem.tagName);
});
这段代码的作用是点击一个结点时显示它的标签名称,它把一个匿名函数注册为一个DOM结点的click事件处理函数,函数内引用了一个DOM对象elem,就形成了闭包。这就会产生一个循环引用,即:DOM->闭包->DOM->闭包...DOM对象在闭包释放之前不会被释放;而闭包作为DOM对象的事件处理函数存在,所以在DOM对象释放前闭包不会释放,即使DOM对象在DOM tree中删除,由于这个循环引用的存在,DOM对象和闭包都不会被释放。可以用下面的方法可以避免这种内存泄露:
- var elem = document.getElementById('test');
- elem.addEventListener('click', function() {
- alert('You clicked ' + this.tagName); // 不再直接引用elem变量
- });
var elem = document.getElementById('test');
elem.addEventListener('click', function() {alert('You clicked ' + this.tagName); // 不再直接引用elem变量
});
闭包还会带来很多类似的内存泄露问题,只有在写代码的时候着重注意一下闭包,尽量避免此类的问题产生。
- function Person(name) {
- this.name = name;
- this.toString = function() {
- return 'Hello, ' + this.name + '!';
- };
- }
- var p = new Person('Ghostheaven');
- alert(p); // Hello, Ghostheaven!
function Person(name) {this.name = name;this.toString = function() {return 'Hello, ' + this.name + '!';};
}var p = new Person('Ghostheaven');
alert(p); // Hello, Ghostheaven!
在以上实例中Person函数作为类的构造函数使用,此时this指向新创建的实例对象,可以为实例增加属性和方法,关于详细的面向对象的JavaScript编程可以参考这篇文章。这里我想要说的是,JavaScript函数作为类构造函数使用时的返回值问题。
- function MyClass(name) {
- this.name = name;
- return name; // 构造函数的返回值?
- }
- var obj1 = new MyClass('foo');
- var obj2 = MyClass('foo');
- var obj3 = new MyClass({});
- var obj4 = MyClass({});
function MyClass(name) {this.name = name;return name; // 构造函数的返回值?
}var obj1 = new MyClass('foo');
var obj2 = MyClass('foo');
var obj3 = new MyClass({});
var obj4 = MyClass({});
- obj1 = MyClass对象
- obj2 = 'foo'
- obj3 = {}
- obj4 = {}
三、JavaScript函数妖怪级
- new Function ([arg1[, arg2[, ... argN]],] functionBody)
new Function ([arg1[, arg2[, ... argN]],] functionBody)
- var func1 = new Function('name', 'return "Hello, " + name + "!";');
- func1('Ghostheaven'); // Hello, Ghostheaven!
var func1 = new Function('name', 'return "Hello, " + name + "!";');
func1('Ghostheaven'); // Hello, Ghostheaven!
- function selfUpdate() {
- window.selfUpdate = function() {
- alert('second run!');
- };
- alert('first run!');
- }
- selfUpdate(); // first run!
- selfUpdate(); // second run!
function selfUpdate() {window.selfUpdate = function() {alert('second run!');};alert('first run!');
}selfUpdate(); // first run!
selfUpdate(); // second run!
这种函数可以用于只运行一次的逻辑,在第一次运行之后就整个替换成一段新的逻辑。
小结
JavaScript世界的一等公民相关推荐
- JavaScript中的一等公民: 函数(Function)
1. 函数的基本使用 使用函数声明或者函数表达式创建一个函数 foo(); //foo bar(); //Uncaught ReferenceError: Cannot access 'bar' be ...
- JavaScript深入浅出第2课:函数是一等公民是什么意思呢?
摘要: 听起来很炫酷的一等公民是啥? <JavaScript深入浅出>系列: JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼? JavaScript深入浅出第2课:函 ...
- JavaScript学习笔记——函数 Part4:向函数传递函数、从函数返回函数(函数是一等公民)
要点 函数是值,这个值就是函数引用 函数是一等公民:函数引用是一等值 可将函数引用赋给变量.含在数据结构(如对象)中.传递给其他函数或从其他函数返回 函数是一等公民 不要再认为函数是特殊的,有别于Ja ...
- 函数式编程 -- 函数是一等公民、高阶函数、闭包
文章内容输出来源:拉勾教育 大前端高薪训练营 前言 学习函数式编程,首先要了解函数式编程相关的概念. 一.函数是一等公民 1. 一等公民的定义 根据维基百科,编程语言中一等公民的概念是由英国计算机学家 ...
- 函数是一等公民,这到底在说什么?
请问下各位大佬,这是什么语法,为什么不需要参数的? 对于有些人来说这根本不是问题,但有些人却想不明白.我提到,在 Go 语言中,函数是一等公民,但对方不清楚这到底在说什么.看来有必要解释下什么是一等公 ...
- python定义公民类_Python-理解函数为”一等公民”
Python中一切皆对象,函数也是对象,也就是说对象能干什么.函数也能干.如拥有原生属性.自定义创建.动态赋值.作为参数传递.作为返回值返回. 作为"一等公民"的函数 一等公民?对 ...
- js系列十七:函数是一等公民
所谓的一等公民,其实就是普通函数,也就是说,函数其实就是没有什么特殊的,我们可以像对待其他数据类型一样对待函数. 1 可以把函数赋值给一个变量 var fn = function () {}; 2 ` ...
- Go 学习笔记(61)— Go 高阶函数、函数作为一等公民(函数作为输入参数、返回值、变量)的写法
函数在 Go 语言中属于"一等公民(First-Class Citizen)"拥有"一等公民"待遇的语法元素可以如下使用 可以存储在变量中: 可以作为参数传递给 ...
- scala 学习笔记(07) 一等公民的函数
在scala中一切皆对象,一切皆函数,函数跟Int,String.Class等其它类型是处于同等的地位,换句话说,使用函数跟使用普通的类型一样,没什么区别,因此: 1.函数可以赋值给变量,可以当参数传 ...
最新文章
- 高招攻略 领英助你清晰解读大数据专业
- sql查询父节点所有子节点id_5招搞定SQL棘手问题,同事看到直呼“内行”
- canvas js 绘图插件_[开盖即食]小程序图表插件eCharts实战
- mysql dms_关于MySQL与DMsql探寻
- 名为 cursor_jinserted 的游标不存在_性能优化技巧 - 程序游标
- 三大主流消息中间件优缺点
- 天津理工计算机通信工程学院,2018年天津理工大学计算机与通信工程学院811信号与系统考研仿真模拟五套题...
- QT QComBox详细用法 自定义QComboBox控件
- 神经网络机器翻译技术
- 高德地图大头针功能_iOS高德地图之自定义大头针and泡泡view
- 威盛wm8880 android4.2系统,还能更低吗? 威盛推出249元平板新芯片组
- 如何用SCRM销售管理系统管理销售和做销售管理
- docker 部署 gitlab gitlab-runner 实现 CI
- 微信分享申请 APPID 时,签名要这样填写
- java - day13 - UnionPay
- AtCoder题解——Beginner Contest 170——F - Pond Skater
- C#生成随机数100次都是一样的数
- 2018最受欢迎开源免费CMS建站系统排行榜
- C# windowsService安装
- 使用springBoot:run命令启动时报错:An exception occurred while running. null