3.1 函数的定义和调用
定义方式一 (建议使用)
//定义绝对值函数
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
-
一旦执行到 return 时,函数就执行完毕,并将结果返回。
-
如果没有 return 语句,函数执行完毕后也会返回结果,只是结果为 undefined 。
定义方式二
//function (x) { ... } 是一个匿名函数,它没有函数名。但这个匿名函数赋值给了变量abs,通过变量abs就可以调用该函数。
var abs = function(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
方式一与方式二完全等价,注意:方式二需要在函数体末尾加一个分号,表示赋值语句结束。
调用函数
abs(-5); // > 5
abs(5); // > 5
参数问题:JavaScript 可以传任意个参数,也可以不传参数
//假设不存在参数,如何规避?
var abs = function (x) {
if (typeof x!== 'number'){
//手动抛出异常
throw 'Not a number!';
}
if (x >= 0) {
return x;
} else {
return -x;
}
};
arguments
JavaScript免费赠送的关键字,代表传递进来的所有参数是一个数组
var abs = function (x) {
console.log('x=>' + x);
for (var i=0; i<arguments.length; i++) {
console.log('arg ' + i + ' = ' + arguments[i]);
}
if (x >= 0) {
return x;
} else {
return -x;
}
};
问题:arguments
包含所有的参数,我们有时候想使用多余的参数来进行附加操作,需要排除已有的的参数。
rest
以前:
if (arguments.length>2){
for (var i=2; i<arguments.length; i++) {}
}
ES6 的新特性~ rest
,获取除了已经定义的参数之外的所有参数
function aaa(a,b,...rest){
//rest参数只能写在最后面,必须用...标识
console.log("a=>"+a);
console.log("b=>"+b);
console.log(rest);
}
aaa(1,1,1,1,1)
> a=>1
> b=>1
> (3) [1, 1, 1]
3.2 变量的作用域
在JavaScript中,var定义的变量实际上是由作用域的
-
假设在函数体中声明,则在函数体外不可以使用(非要实现的话,需要使用
闭包
)'use strict'; function a(){ var x = 1; x = x + 1; } x = x + 2; //Uncaught ReferenceError: x is not defined
-
如果两个函数使用了相同的变量名,只要在函数内部,就不冲突
function a1(){ var x = 1; x = x + 1; } function a2(){ var x = 1; x = x + 1; }
-
内部函数可以访问外部函数的成员,反之则不行
function a1(){ var x = 1; function a2(){ var y = x + 1; //2 } var z= y + 1; // Uncaught ReferenceError: z is not defined }
-
假设内部函数与外部函数的变量重名
function a1(){ var x = 1; function a2(){ var x = 'a'; console.log('内部:'+x); } console.log('外部:'+x); a2(); //内部:a } a1(); //外部:1
-
假设在JavaScript中函数查找变量从自身函数开始,从“内”向“外”查找。如果内部函数定义了与 外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量。
提升变量的作用域
function a(){
var x = 'x' + y;
console.log(x);
var y = 'y';
} //Uncaught ReferenceError: x is not defined
说明:JavaScript执行引擎,自动提升了y的声明,但不会提升变量y的赋值,这个是在JavaScript建立之初就存在的特性。
function a(){
//var x,y,z...;
//养成规范:所有的变量定义都放在函数的头部,不要乱放,便于代码维护
var x = 'x' + y,
y = 'y',
z,a,b,c; //undefined
}
全局作用域
var x = 1;
function f(){
console.log(x);
}
console.log(x);
-
全局对象 window
-
var x = 'xxx'; alert(x); //直接调用alert() window.alert(x); //alert()本身也是一个window变量,可以通过window对象来调用 alert(window.x); //默认所有的全局变量,都会绑定在window对象下,可以通过window对象来调用
-
玩一下:发现JavaScript实际上只有一个全局作用域。任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找,最后如果在全局作用域中也没有找到,则报 ReferenceError 错误。
'use strict'; window.alert('调用window.alert()'); // 把alert保存到另一个变量: var old_alert = window.alert; // 给alert赋一个新函数: window.alert = function () {} alert('无法用alert()显示了!'); // 恢复alert: window.alert = old_alert; alert('又可以用alert()了!');
-
规范:
-
由于我们所有的全局变量会绑定到 window 上。如果不同的JavaScript文件使用了相同的全局变量,就会发生冲突。
-
减少冲突:把自己的代码全部放入自己定义的唯一名字空间中,降低全局命名冲突的问题
//唯一全局变量 var JiangApp = {}; //定义全局变量 JiangApp.name = 'jiang'; JiangApp.add = function (a,b){ return a + b; }
-
局部作用域
let
(建议使用)
function a(){
for (i = 0; i < 100; i++) {
console.log(i);
}
console.log(i+1); // 101 i出了这个作用域还可以使用
//ES6 引入let关键字,解决局部作用域冲突的问题
function a(){
for (let i = 0; i < 100; i++) {
console.log(i);
}
console.log(i+1); // Uncaught ReferenceError: z is not defined
常量
const
-
在 ES6 之前,定义常量的方法:只要用全部大写字母命名的变量就是常量,建议不要修改这样的值
-
在 ES6 引入了常量关键字
const
const PI = 3.14; PI = 3; //Uncaught TypeError: Assignment to constant variable. PI; // 3.14
3.3 方法
定义方法
方法就是把函数放在对象的内部,对象只有两个东西:属性和方法
var me = {
name:'jiangjiang',
birth:2002,
age: function (){
var now = new Date().getFullYear();
return now-this.birth; //this默认指向调用它的那个对象
}
}
//调用属性
me.name; //'jiangjiang'
//调用方法:一定要带()
me.age(); //21
拆开写:
function getAge() {
var now = new Date().getFullYear();
return now - this.birth;
//此处this是无法改变指向的,默认指向调用它的那个对象
}
var me = {
name: 'jiangjiang',
birth: 2002,
age: getAge
};
//调用
me.age(); // 21, 正常结果
getAge(); // NaN
apply 在Js中可以控制this的指向
getAge.apply(me,[]); //this指向了me这个对象,参数为空
// 21, 正常结果