ECMAScript的函數是對象,函數名是指針數組
建立:瀏覽器
函數聲明法:安全
- function sum (num1, num2) {
- return num1 + num2;
- }
函數表達式法:app
- var sum = function(num1, num2) {
- return num1 + num2;
- };
函數表達式法:這種不推薦,由於這種語法會致使解析兩次代碼(第一次解析常規ECMAScript代碼,第二次解析傳入構造函數中的字符串),從而影響性能ide
- var sum = new Function("num1", "num2", "return num1 + num2"); //不推薦
同時使用函數聲明和函數表達式:這種語法會在Safari出錯函數
- var sum = function sum () {}
因爲函數名只是指針,因此以下:性能
- function sum(num1, num2){
- return num1 + num2;
- }
- alert(sum(10,10)); //20
- var anotherSum = sum;
- alert(anotherSum(10,10)); //20
- sum = null;
- alert(anotherSum(10,10)); //20
函數名是指針,因此沒有重載:this
- function addSomeNumber (num) {
- return num + 100;
- }
- function addSomeNumber (num) {
- retrun num + 200;
- }
- var result = addSomeNumber(100); //300
上面代碼其實是:spa
- function addSomeNumber (num) {
- return num + 100;
- }
- addSomeNumber = function (num) {
- retrun num + 200;
- }
- var result = addSomeNumber(100); //300
建立第二個函數時,改變了addSomeNumber的指向prototype
函數聲明與函數表達式的一個區別:
解析器會率先讀取函數聲明,並使其在執行任何代碼前可用;而函數表達式,必須等到解析器執行到所在行,才能被解釋執行
- alert(sum(10,10)); //20
- function sum(num1, num2){
- return num1 + num2;
- }
若是改爲以下,就會報錯
- alert(sum(10,10)); //causes an error
- var sum = function(num1, num2){
- return num1 + num2;
- };
把函數當值使用:
將一個函數做爲另外一個函數的結果返回
- function callSomeFunction(someFunction, someArgument){
- return someFunction(someArgument);
- }
- function add10(num){
- return num + 10;
- }
- var result1 = callSomeFunction(add10, 10);
- alert(result1); //20
- function getGreeting(name){
- return "Hello, " + name;
- }
- var result2 = callSomeFunction(getGreeting, "Nicholas");
- alert(result2); //Hello, Nicholas
從一個函數中返回另外一個函數,如給對象數組排序:(默認狀況下,sort()會調用toString()方法)
- function createComparisonFunction(propertyName) {
- return function(object1, object2){
- var value1 = object1[propertyName];
- var value2 = object2[propertyName];
- if (value1 < value2){
- return -1;
- } else if (value1 > value2){
- return 1;
- } else {
- return 0;
- }
- };
- }
- var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];
- data.sort(createComparisonFunction("name"));
- alert(data[0].name); //Nicholas
- data.sort(createComparisonFunction("age"));
- alert(data[0].name); //Zachary
函數內部屬性:
函數內部有兩個特點的對象 arguments 和 this
arguments:是一個類數組對象,包含傳入函數的全部參數
callee:是arguments的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數
下面是一個經典的階乘例子:
- function factorial(num){
- if (num <= 1) {
- return 1;
- } else {
- return num * arguments.callee(num-1)
- }
- }
- var trueFactorial = factorial;
- factorial = function(){
- return 0;
- };
- alert(trueFactorial(5)); //120
- alert(factorial(5)); //0
this:引用的是函數據以執行的環境對象(當在網頁的全局做用域中調用函數時,this對象引用的就是window)
- window.color = "red";
- var o = { color: "blue" };
- function sayColor(){
- alert(this.color);
- }
- sayColor(); //red
- o.sayColor = sayColor;
- o.sayColor(); //blue
caller:這個屬性中保存着調用當前函數的函數的引用,若是在全局做用域中調用當前函數,它的值爲null(Opera9.6版以前不支持該屬性)
- function outer(){
- inner();
- }
- function inner(){
- alert(inner.caller);
- }
- outer(); //function outer(){
- // inner();
- //}
下面這種寫法與上面同理,只是達到了更好的鬆耦合,這樣函數名稱能夠變更而不用改變內部代碼
- function outer(){
- inner();
- }
- function inner(){
- alert(arguments.callee.caller);
- }
- outer(); //function outer(){
- // inner();
- //}
注意:
1.這嚴格模式下,訪問 arguments.callee 會致使錯誤。
2.ECMAScript5 還定義了 arguments.caller 屬性,但在嚴格模式下也會致使錯誤,而在非嚴格模式下這個屬性始終是undefined。定義這個屬性是爲了分清 arguments.caller 和 函數的caller屬性。以上都是爲了增強這門語言的安全性,這樣第三方代碼就不會在相同的環境裏窺視其餘代碼了。
3.在嚴格模式下,不能給函數的caller屬性賦值,不然會出錯。
函數屬性和方法:
因爲在ECMAScript中,函數是對象,因此函數有屬性和方法
length:表示函數但願接收的命名參數的個數
- function sayName(name){
- alert(name);
- }
- function sum(num1, num2){
- return num1 + num2;
- }
- function sayHi(){
- alert("hi");
- }
- alert(sayName.length); //1
- alert(sum.length); //2
- alert(sayHi.length); //0
prototype:第6章
apply():用途是在特定的做用域中調用函數,實際上等於設置函數體內this對象的值?
需傳入2個參數:該運行函數的做用域(this)、參數數組
- function sum(num1, num2){
- return num1 + num2;
- }
- function callSum1(num1, num2){
- return sum.apply(this, arguments); //因爲在全局做用域中調用的,因此this指的是window對象
- }
- function callSum2(num1, num2){
- return sum.apply(this, [num1, num2]);
- }
- alert(callSum1(10,10)); //20
- alert(callSum2(10,10)); //20
注意:在嚴格模式下,未指定環境對象而調用函數,則this值不會轉型爲window。除非明確把函數添加到某個對象 或者 調用apply()或call(),不然this值將是undefined
call():用途是在特定的做用域中調用函數?
傳入參數:該運行函數的做用域(this)、逐一列出參數
- function sum(num1, num2){
- return num1 + num2;
- }
- function callSum(num1, num2){
- return sum.call(this, num1, num2);
- }
- alert(callSum(10,10)); //20
apply()和call()真正的用武之地是擴充函數賴以運行的做用域,以下:
- window.color = "red";
- var o = { color: "blue" };
- function sayColor(){
- alert(this.color);
- }
- sayColor(); //red
- sayColor.call(this); //red
- sayColor.call(window); //red
- sayColor.call(o); //blue
使用apply()或call()來擴充做用域的最大的好處,就是對象不須要與方法有任何耦合關係(這跟以前那個版本比(講this時),省下不少多餘的步驟)
bind():把this值與該函數綁定
- window.color = "red";
- var o = { color: "blue" };
- function sayColor(){
- alert(this.color);
- }
- var objectSayColor = sayColor.bind(o);
- objectSayColor(); //blue
把o與objectSayColor的this綁定,因此調用時返回的是blue,而不是red,第22章
支持bind()的瀏覽器有IE9+、Firefox 4+、Chrome……
每一個函數繼承的toLocaleString()、toString()、valueOf()都返回的函數的代碼,因瀏覽器而異。