函数

函数声明
1、function命令

function print(s) {
  
}

使用print()这种形式,就可以调用相应的代码

2、函数表达式

var f = function f() {};

f()

f只在函数体内部可用,指代函数表达式本身,其他地方都不可用。

3、Function构造函数

var add = new Function(
  'x',
  'y',
  'return x + y'
);

Function构造函数接受三个参数,除了最后一个参数是add函数的“函数体”,其他参数都是add函数的参数。

可以传递任意数量的参数给Function构造函数,只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。

Function构造函数可以不使用new命令,返回结果完全一样。

第一等公民
JavaScript语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。

函数名的提升
avaScript引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。
如果采用赋值语句定义函数,JavaScript就会报错。

如果同时采用function命令和赋值语句声明同一个函数,最后总是采用赋值语句的定义。

var f = function() {
  console.log('1');
}

function f() {
  console.log('2');
}

f() // 1

不能在条件语句中声明函数
根据ECMAScript的规范,不得在非函数的代码块中声明函数,最常见的情况就是if和try语句。

if (false) {
  function f() {}
}

f() // 不报错

要达到在条件语句中定义函数的目的,只有使用函数表达式。

if (false) {
  var f = function () {};
}

f() // undefined

函数的属性和方法
1、name属性

function f1() {}
f1.name // 'f1'

var f2 = function () {};
f2.name // ''
匿名函数的name属性总是为空字符串;

var f3 = function myName() {};
f3.name // 'myName'
返回函数表达式的名字(真正的函数名还是f3,myName这个名字只在函数体内部可用)。

2、length属性
length属性返回函数预期传入的参数个数,即函数定义之中的参数个数。

function f(a, b) {}
f.length // 2

3、toString()
返回函数的源码,函数内部的注释也可以返回。

var multiline = function (fn) {
  var arr = fn.toString().split('\n');
  return arr.slice(1, arr.length - 1).join('\n');
};

function f() {/*
  这是一个
  多行注释
*/}

multiline(f);
// " 这是一个
//   多行注释"

变相实现多行字符串

函数作用域
在函数外部声明的变量就是全局变量(global variable),它可以在函数内部读取。
在函数内部定义的变量,外部无法读取,称为“局部变量”(local variable)。
函数内部定义的变量,会在该作用域内覆盖同名全局变量。
对于var命令来说,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量。

if (true) {
  var x = 5;
}
console.log(x);  // 5

变量x在条件判断区块之中声明,结果就是一个全局变量,可以在区块之外读取。

函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。

函数的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。
如果函数A调用函数B,函数B不会引用函数A的内部变量。

传递方式
函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。这意味着,在函数体内修改参数值,不会影响到函数外部。
如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。

如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。
var obj = [1, 2, 3];

function f(o){
  o = [2, 3, 4];
}
f(obj);

obj // [1, 2, 3]

某些情况下,如果需要对某个原始类型的变量,获取传址传递的效果,可以将它写成全局对象的属性。

var a = 1;

function f(p) {
  window[p] = 2;
}
f('a');

a // 2

同名参数
如果有同名的参数,则取最后出现的那个值。

function f(a, a) {
  console.log(arguments[0]);
}

f(1) // 1

要获得第一个a的值,可以使用arguments对象。

arguments对象
arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
正常模式下,arguments对象可以在运行时修改。
严格模式下,arguments对象是一个只读对象,修改它是无效的,但不会报错。
可以通过arguments对象的length属性,判断函数调用时到底带几个参数。

虽然arguments很像数组,但它是一个对象。但是,可以通过apply方法,把arguments作为参数传进去,这样就可以让arguments使用数组方法了。

可以通过arguments.callee,达到调用函数自身的目的。

闭包
闭包就是能够读取其他函数内部变量的函数。
闭包使得内部变量记住上一次调用时的运算结果。
闭包的另一个用处,是封装对象的私有属性和私有方法。

立即调用的函数表达式

(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();

任何让解释器以表达式来处理函数定义的方法,都能产生同样的效果

var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
!function(){ /* code */ }();
new function(){ /* code */ }

eval命令
eval命令的作用是,将字符串当作语句执行。

eval('var a = 1;');
a // 1

eval没有自己的作用域,都在当前作用域内执行,因此可能会修改当前作用域的变量的值
调用eval(expression),这叫做“直接使用”,这种情况下eval的作用域就是当前作用域。除此之外的调用方法,都叫“间接调用”,此时eval的作用域总是全局作用域

利用Function函数生成一个函数,然后调用该函数,也能将字符串当作命令执行。

var jsonp = 'foo({"id": 42})';

var f = new Function( "foo", jsonp );
// 相当于定义了如下函数
// function f(foo) {
//   foo({"id":42});
// }

new Function()的写法也可以读写全局作用域

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 在js中,函数本身属于对象的一种,因此可以定义、赋值,作为对象的属性或者成为其他函数的参数。函数名只是函数这个对象...
    bjhu电net阅读 526评论 0 5
  • 函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。 上面代码检查函数l...
    呼呼哥阅读 3,351评论 0 1
  • 小时候 长大是一个梦 像五彩斑斓的彩虹 充满了无限种可能 长大后 童年是一个梦 那无拘无束的时光 是永远回不去的简...
    上官飞鸿阅读 332评论 30 22
  • 之前在跟一朋友聊天,聊到我们的经历,聊到各自现在的情况,感觉很是亲切,也感慨万千。 自学校毕业之后,便跻身中...
    潇洒的转身阅读 245评论 0 0
  • 不知道怎么加的小川叔公众号了,反正习惯每天点开看看了。 努务赚钱,我想不管是姑娘还是人妇,是小伙还是孩他爸都应该做...
    花开十三月阅读 187评论 0 0