三、函數
目錄:函數的定義和參數獲取、變量的作用域 let const詳解、方法的定義和參數的獲取
1.函數的定義和參數獲取
例:創(chuàng)建絕對值函數
1)定義函數
①定義方式一
function abs(x) {
if(x>=0) {
return x;
} else {
return -x;
}
}
一旦1執(zhí)行到return代表函數結束,返回結果。
如果沒有執(zhí)行到return,函數執(zhí)行完也會返回結果,結果為undefined。
②定義方式二
var abs = function(x) {
if(x>=0) {
return x;
} else {
return -x;
}
}
function(x){……}這是匿名函數,但是可以把結果賦值給abs。通過abs就可以調用函數,相當于Java的匿名內部類。
2)調用函數
abs(10)
abs(-10)
參數問題:JavaScript可以傳任意個參數,也可以不傳遞參數。
參數進來是否存在的問題如何解決?
假設不存在參數如何規(guī)避?
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執(zhí)行引擎,自動提升了y的聲明,但是不會提升變量y的賦值。
上例等同于:
function f() {
var y;
var x="x"+y;
console.log(x);
y="y";
}
這個是在JavaScript建立之初就存在的特性。
規(guī)范:所有的變量定義都放在頭部,不要亂發(fā),便于代碼維護。
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沒有彈出,發(fā)現alert()失效了
//恢復
window.alert=old_alert;
window.alert(456);//彈出456
JavaScript實際上只有一個全局作用域,任何變量(函數也可以視為變量),假設沒有在函數作用范圍內找到,就會向外查找,如果在全局作用域都沒有找到,報錯RefrenceError。
4)規(guī)范
例:
//唯一全局變量
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中l(wèi)et關鍵字,解決局部作用域沖突問題。
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,參數為空。