javascript函数:
第一种:
function 函数名(参数列表){
}
第二种:
var s = function(x){
}
其中function(x)是一个匿名函数,后续再调用这个函数的时候直接通过变量s来调用函数
JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array:
注意:javascript引擎在行末自动关机添加分号的机制
javascript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量
反过来,外部函数不可以访问内部函数定义的变量
javascript函数在查找变量的时候,从内向外查找
javascript的函数的定义有个特点,它会先扫描整个函数的语句,把所有申明的变量提升到函数顶部:
function foo() {
var x = 'Hello, ' + y;
console.log(x);
var y = 'Bob';
}
foo();
虽然是strict模式,但语句var x = 'Hello, ' + y;并不报错,原因是变量y在稍后申明了。但是console.log显示Hello, undefined,说明变量y的值为undefined。这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。
对于上述foo()函数,JavaScript引擎看到的代码相当于:
function foo() {
var y; // 提升变量y的申明,此时y为undefined
var x = 'Hello, ' + y;
console.log(x);
y = 'Bob';
}
javascript有一个默认的全局对象window,全局作用域的变量实际上是被绑定到window上的一个属性
减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。例如:
// 唯一的全局变量MYAPP:
var MYAPP = {};
// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 其他函数:
MYAPP.foo = function () {
return 'foo';
};
把自己的代码全部放入唯一的名字空间MYAPP中,会大大减少全局变量冲突的可能。
许多著名的JavaScript库都是这么干的:jQuery,YUI,underscore等等。
javascript引入了解构赋值,可以同时对一组变量进行赋值
在一个对象中绑定函数,称之为这个函数的方法
在一个方法内部,this是一个特殊的变量,他始终指向当前对象
要保证this指向正确,必须用obj.xxx()的形式调用!
修复的办法也不是没有,我们用一个that变量首先捕获this:
var xiaoming={
name:'小明',
birth:1998,
age:function(){
var that = this ;//在方法内部一开始就捕获this
function getAgeFromBirth(){
var y = new Date().getFullYear();
return y - that.birth;//用that而不是this
}
return getAgeFromBirth();
}
};
用var that = this;,你就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中。
以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数。
apply()把参数打包成Array再传入;
call()把参数按顺序传入。
闭包:闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。
例如:
(function (x){
return x*x;
})(3);
箭头函数:相当于匿名函数,并且简化了函数的定义
x=>x*x
这个箭头函数相当于
function(x){
return x*x;
}
有两种形式:除了像上边那个省略
如果包含多条语句,这时候就不能省略{...}和return
如果参数不是一个,就需要用括号()括起来
如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:
// SyntaxError:
x => { foo: x }
因为和函数体的{ ... }有语法冲突,所以要改为:
// ok:
x => ({ foo: x })
箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。
现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:
回顾前面的例子,由于JavaScript函数对this绑定的错误处理,下面的例子无法得到预期结果:
var obj = {
birth: 1998,
getAge: function () {
var b = this.birth; // 1998
var fn = function () {
return new Date().getFullYear() - this.birth; // this指向window或undefined
};
return fn();
}
};
现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:
var obj = {
birth: 1998,
getAge: function () {
var b = this.birth; // 1998
var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
return fn();
}
};
obj.getAge(); // 30
由于箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数的时候,
无法对this进行绑定,即传入的第一个参数被忽略
generator(生成器)是ES6标准引入的新的数据类型
函数在执行过程中,如果没有遇到return语句(函数末尾如果没有return,就是隐含的return undefined;),控制权无法交回被调用的代码。
generator跟函数很像,定义如下:
function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}
generator和函数不同的是,generator由function*定义(注意多出的*号),并且,除了return语句,还可以用yield返回多次
例:著名的费波纳次数列
0 1 1 2 3 5 8 13 21 .....
可以用generator来写
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
调用generator对象有两个方法,一是不断地调用generator对象的next()方法:
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}
next()方法会执行generator的代码,然后,每次遇到yield x;就返回一个对象{value: x, done: true/false},然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了。如果done为true,则value就是return的返回值。
当执行到done为true时,这个generator对象就已经全部执行完毕,不要再继续调用next()了。