JavaScript之函数
三、函数
目录:函数的定义和参数获取、变量的作用域 let const详解、方法的定义和参数的获取
1.函数的定义和参数获取
例:创建绝对值函数
1)定义函数
①定义方式一
function abs(x) {
if(x>=0) {
return x;
} else {
return -x;
}
}
一旦1执行到return代表函数结束,返回结果。
如果没有执行到return,函数执行完也会返回结果,结果为undefined。
②定义方式二
var abs = function(x) {
if(x>=0) {
return x;
} else {
return -x;
}
}
function(x){……}这是匿名函数,但是可以把结果赋值给abs。通过abs就可以调用函数,相当于Java的匿名内部类。
2)调用函数
abs(10)
abs(-10)
参数问题:JavaScript可以传任意个参数,也可以不传递参数。
参数进来是否存在的问题如何解决?
假设不存在参数如何规避?
var abs = function(x) {
//手动抛出异常来判断
if(typeof x!=='number') {
throw 'Not a Number';
}
if(x>=0) {
return x;
} else {
return -x;
}
}
3)arguments
arguments是JS免费送的关键字,能获取传递进来的所有参数,是一个数组。
var abs = function(x) {
console.log("x=>"+x);
for(var i=0;i<arguments.length;i++) {
console.log(arguments[i]);
}
if(x>=0) {
return x;
} else {
return -x;
}
}
问题:arguments包含所有的参数,有时候想使用多余的参数来进行附加操作,需要排除已有参数。
4)rest:ES6引入新特性,获取除了已经定义的参数之外的所有的参数。
以前:
if(arguments.length>2) {//如果定义了2个参数
for(var i=2;i<arguments.length;i++) {…}
}
现在:
function f(a,b,…rest) {
console.log("a=>"+a);
console.log("b=>"+b);
console.log(rest);
}
rest参数只能写在最后面,必须用…标识。有点像Java的可变长参数。
2.变量的作用域、let、const详解
1)在JavaScript中,var定义变量实际是有作用域的。
假设在函数体中声明,则在函数体外不可使用(非要想实现可以用闭包)。
例:
function f() {
var x=1;
}
x=x+2;//Uncaught ReferenceError: x is not defined
如果两个函数使用了相同的变量名,只要在函数内部就不冲突。
例:
function f1() {
var x=1;
}
function f2() {
var x='A';
}
内部函数可以访问外部函数的成员,反之则不行。
例:
function f() {
var x=1;
function f3() {
var y=x+1;//2
}
var z=y+1;//Uncaught ReferenceError: y is not defined
}
假设内部函数变量和外部函数变量重名:
例:
function f1() {
var x=1;
function f2() {
var x='A'
console.log('inner'+x);//innerA
}
console.log('outer'+x);//outer1
}
假设在JavaScript中函数查找变量从自身函数开始,由“内”向“外”查找,假设外部存在这个同名的函数变量,则内部函数会自动屏蔽外部函数的变量。
2)提升变量的作用域
例:
function f() {
var x="x"+y;
console.log(x);
var y="y";
}
结果为xundefined。
说明:js执行引擎,自动提升了y的声明,但是不会提升变量y的赋值。
上例等同于:
function f() {
var y;
var x="x"+y;
console.log(x);
y="y";
}
这个是在JavaScript建立之初就存在的特性。
规范:所有的变量定义都放在头部,不要乱发,便于代码维护。
3)全局变量
全局对象window
例:
var x="xxx";
window.alert(window.x);//默认所有的全局变量,都会自动绑定在window对象下
alert()这个函数本身也是一个window变量。
例:
var x="xxx";
window.alert(x);
var old_alert=window.alert;
//old_alert(x);
window.alert=function() {
};
window.alert(123);//123没有弹出,发现alert()失效了
//恢复
window.alert=old_alert;
window.alert(456);//弹出456
JavaScript实际上只有一个全局作用域,任何变量(函数也可以视为变量),假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域都没有找到,报错RefrenceError。
4)规范
例:
//唯一全局变量
var win={ }
//定义全局变量
win.name= "xiaoming";
win.add=function(a,b) {
return a+b;
}
把代码全部放入定义的唯一空间名字中,降低全局命名冲突问题。
jQuery库把所定义的都放到jQuery中,并用简化符$()。
5)局部作用域let
例:
function aa() {
for(var i=0;i<100;i++) {
console.log(i);
}
console.log(i+1);//101
}
问题:i出了这个作用域还可以使用。
ES6中let关键字,解决局部作用域冲突问题。
function aa() {
for(let i=0;i<100;i++) {
console.log(i);
}
console.log(i+1);//Uncaught ReferenceError: i is not defined
}
建议使用let去定义局部作用域的变量。
6)常量const
在ES6之前,怎么定义常量:只有用全部大写字母命名的变量就是常量,建议不要修改这样的值。
例:
var PI='3.14';//可以改变这个值
在ES6引入了常量关键字const
例:
const PI='3.14';
PI='123';//TypeError: Assignment to constant variable
3.方法的定义和参数获取
1)定义方法
方法就是把函数放在对象里面,对象只有两个东西,就是方法和属性。
例:
var ming = {
name: 'xiaoming',
birth: 2001,
//方法
age: function() {
var now = new Date().getFullYear();
return now-this.birth;
}
}
//调用属性
ming.name
//调用方法,一定要带()
ming.age()
this.代表什么?
拆开上面的代码来看。
var ming = {
name: 'xiaoming',
birth: 2001,
//方法
age: getAge
}
function getAge() {
var now = new Date().getFullYear();
return now-this.birth;
}
ming.age();//20
getAge();//NaN,单独使用,使用window对象,没有birth属性
}
this是无法指向的,是默认指向调用它的对象。
2)apply
在js中可以控制this指向。
getAge.apply(ming,[]);//this指向ming,参数为空。