码迷,mamicode.com
首页 > Web开发 > 详细

JS函数

时间:2018-08-26 14:46:42      阅读:238      评论:0      收藏:0      [点我收藏+]

标签:函数声明   问题   数列   获取   mat   空间   允许   higher   ref   

函数定义和调用

  • 调用函数

由于JavaScript允许传入任意个参数而不影响调用,因此传入的参数个数和定义的参数个数不一致也没有问题,虽然函数内部并不需要这些参数:

var abs = function (x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
};
abs(10); // 返回10
abs(-9); // 返回9
abs(10, ‘blablabla‘); // 返回10
abs(-9, ‘haha‘, ‘hehe‘, null); // 返回9
abs(); // 返回NaN

要避免收到undefined,可以对参数进行检查:

function abs(x) {
    if (typeof x !== ‘number‘) {
        throw ‘Not a number‘;
    }
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}
  • arguments

 它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。

实际上arguments最常用于判断传入参数的个数

function foo(a, b, c) {
    if (arguments.length === 2) {
        console.log(2);
    }
    if(arguments.length ===3){
        console.log(3);
    } 
}
foo(1,2);
foo(1,2,3);
  • rest

ES6标准引入了rest参数,来获取额外的参数。

rest参数只能写在最后,前面用...标识(扩展运算符将一个数组,变为参数序列),从运行结果可知,传入的参数先绑定ab,多余的参数以数组形式交给变量rest

function foo(a, b, ...rest) {
    console.log(‘a = ‘ + a);
    console.log(‘b = ‘ + b);
    console.log(rest);
}

foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]

foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
  • 变量提升

‘use strict‘;

function foo() {
    var x = ‘Hello, ‘ + y;
    console.log(x);
    var y = ‘Bob‘;
}

foo();
结果:Hello, undefined

JavaScript引擎自动提升了变量y声明,但不会提升变量y的赋值。

  • 全局作用域

window

JavaScript实际上只有一个全局作用域。任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找,最后如果在全局作用域中也没有找到,则报ReferenceError错误。

  • 名字空间

// 唯一的全局变量MYAPP:
var MYAPP = {};

// 其他变量:
MYAPP.name = ‘myapp‘;
MYAPP.version = 1.0;

// 其他函数:
MYAPP.foo = function () {
    return ‘foo‘;
};

把自己的代码全部放入唯一的名字空间MYAPP中,会大大减少全局变量冲突的可能。

  • 局部作用域

function foo() {
    for (var i=0; i<100; i++) {
        //
    }
    i += 100; // 仍然可以引用变量i
console.log(i);
}
foo();
结果: 200

为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:

function foo() {
    for (let i=0; i<100; i++) {
        //
    }
    i += 100; // 仍然可以引用变量i
console.log(i);
}
foo();
结果:Uncaught ReferenceError: i is not defined
  • 解构赋值

ES6解构赋值

  • 方法

var xiaoming = {
    name: ‘小明‘,
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了

以上代码,在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是xiaoming这个变量。

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: ‘小明‘,
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25, 正常结果
getAge(); // NaN

以上方法,如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window。在strict模式下让函数的this指向undefined

注意,要保证this指向正确,必须用obj.xxx()的形式调用!

apply

要指定函数的this指向哪个对象,可以用函数本身apply方法,

它接收两个参数,第一个参数就是这个对象将代替Function类里this对象,第二个参数是Array,表示函数本身的参数。

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: ‘小明‘,
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空

apply()类似的方法是call(),唯一区别是:参数列表不同

apply()把参数打包成Array再传入;

call()把参数按顺序传入。

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
  • 高阶函数

高阶函数英文叫Higher-order function:一个函数就可以接收另一个函数作为参数

function add(x, y, f) {
    return f(x) + f(y);
}
var x = add(-5, 6, Math.abs); // 11
console.log(x);  11

1.map/reduce

由于map()方法定义在JavaScript的Array中,我们调用Arraymap()方法,传入我们自己的函数,就得到了一个新的Array作为结果:

function pow(x) {
    return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]

注意:map()传入的参数是pow,即函数对象本身。不是pow()。

Array的reduce()把一个函数作用在这个Array[x1, x2, x3...]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算

var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
    return x + y;
}); // 25
第一步:(1,3)第二步:(4,5)第三步:(9,7)第四步:(16,9)

要把[1, 3, 5, 7, 9]变换成整数13579,reduce()也能派上用场:

var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
    return x * 10 + y;
}); // 13579filter

2.filter

filter也是一个常用的操作,它用于把Array的某些元素过滤掉,然后返回剩下的元素。

Arrayfilter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。

例如,在一个Array中,删掉偶数,只保留奇数,可以这么写:

var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
    return x % 2 !== 0;
});
r; // [1, 5, 9, 15]

3.sort

// 看上去正常的结果:
[‘Google‘, ‘Apple‘, ‘Microsoft‘].sort(); // [‘Apple‘, ‘Google‘, ‘Microsoft‘];

// apple排在了最后:
[‘Google‘, ‘apple‘, ‘Microsoft‘].sort(); // [‘Google‘, ‘Microsoft", ‘apple‘]

// 无法理解的结果:
[10, 20, 1, 2].sort(); // [1, 10, 2, 20]

第二个排序把apple排在了最后,是因为字符串根据ASCII码进行排序,而小写字母a的ASCII码在大写字母之后。(A十进制表示65,a十进制表示97)

第三个排序结果是什么鬼?简单的数字排序都能错?

这是因为Arraysort()方法默认把所有元素先转换为String再排序,结果‘10‘排在了‘2‘的前面,因为字符‘1‘比字符‘2‘的ASCII码小。(0十进制表示48)

要按数字大小排序,我们可以这么写:

通常规定,对于两个元素xy,如果认为x < y,则返回-1,如果认为x == y,则返回0,如果认为x > y,则返回1

var arr = [10, 20, 1, 2];
arr.sort(function (x, y) {
    if (x < y) {
        return -1;
    }
    if (x > y) {
        return 1;
    }
    return 0;
});
console.log(arr); // [1, 2, 10, 20]

最后友情提示,sort()方法会直接Array进行修改,它返回的结果仍是当前Array

var a1 = [‘B‘, ‘A‘, ‘C‘];
var a2 = a1.sort();
a1; // [‘A‘, ‘B‘, ‘C‘]
a2; // [‘A‘, ‘B‘, ‘C‘]
a1 === a2; // true, a1和a2是同一对象
  • 闭包

函数声明和函数表达式

1、Function Declaration(函数声明)必须以“function”开头。

ECMA 5(13.0)定义语法:

function Identifier ( FormalParameterList[opt] ) { FunctionBody }

函数名在自身作用域和父作用域内是可获取的

function bar() {
 return 3;
}
  
bar() //3
bar //function

2、Function Expression(函数表达式)将函数定义为表达式语句(通常是变量赋值)的一部分。

函数名(如果有的话)在作用域外是不可获取的

//anonymous function expression
var a = function() {
 return 3;
}
  
//named function expression
var a = function bar() {
 return 3;
}
  
//self invoking function expression
(function sayHello() {
 alert("hello!");
})();

 小测试题目:

function foo(){
 function bar() {
 return 3;
 }
 return bar();
 function bar() {
 return 8;
 }
}
alert(foo());//8
//Function declaration和function variable(函数变量)通常会被 JavaScript 解释器移(‘hoisted‘)到当前作用域顶部

=>

function foo(){
 //define bar once
 function bar() {
 return 3;
 }
 //redefine it
 function bar() {
 return 8;
 }
 //return its invocation
 return bar(); //8
}
alert(foo());
function foo(){
 var bar = function() {
 return 3;
 };
 return bar();
 var bar = function() {
 return 8;
 };
}
alert(foo());// 3
//等号左边的Variable Declaration 会被提升,但是等号右边的 Assignment Expression(赋值表达式)不会

=>

//**Simulated processing sequence for Question 2**
function foo(){
 //a declaration for each function expression
 var bar = undefined;
 var bar = undefined;
 //first Function Expression is executed
 bar = function() {
 return 3;
 };
 // Function created by first Function Expression is invoked
 return bar();
 // second Function Expression unreachable
bar = function() {
 return 8;
 };
}
alert(foo()); //3
alert(foo()); //3
function foo(){
 var bar = function() {
 return 3;
 };
 return bar();
 var bar = function() {
 return 8;
 };
}

//函数声明foo()被提升了,函数表达式var bar = function() {return 8;};没有被提升
=>
function foo(){
 var bar = function() {
 return 3;
 };
 return bar();
 var bar = function() {
 return 8;
 };
}
alert(foo()); //3
function foo(){
 return bar();
 var bar = function() {
 return 3;
 };
 var bar = function() {
 return 8;
 };
}
alert(foo());//Uncaught TypeError: bar is not a function
//函数没有提升,变量有提升
=>
//**Simulated processing sequence for Question 4**
function foo(){
 //a declaration for each function expression
 var bar = undefined;
 var bar = undefined;
 return bar(); //TypeError: "bar not defined"
 //neither Function Expression is reached
}
alert(foo());

函数声明和函数表达式的区别:

函数声明和函数表达式不同之处在于:

一、Javascript引擎在解析javascript代码时会‘函数声明提升’(Function declaration Hoisting)当前执行环境(作用域)上的函数声明,

而函数表达式必须等到Javascirtp引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式;

fnName();
function fnName(){
    ...
}
//正常,因为‘提升‘了函数声明,函数调用可在函数声明之前

fnName();
var fnName=function(){
    ...
}
//报错,变量fnName还未保存对函数的引用,函数调用必须在函数表达式之后

二、函数表达式后面可以加括号立即调用该函数,函数声明不可以,只能以fnName()形式调用 。

(function(a){
    console.log(a);   
})(123);
//function外面加括号表示函数表达式

 

JS函数

标签:函数声明   问题   数列   获取   mat   空间   允许   higher   ref   

原文地址:https://www.cnblogs.com/chrisghb8812/p/9537238.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!