您的位置:首页 > 移动开发

函数 | arguments | rest | 作用域 | let | 名字空间 | apply | map() | reduce() | filter() | 回调函数

2017-08-31 08:30 741 查看
一 函数

1.函数存在的原因?为了重复处理有相同规律的"行为"。

2.抽象

1 + 2 + 3 + … +100,记做



二 函数的定义和调用

1.

函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,将结果返回。

如果没有return语句,函数执行完毕后也会返回结果,只不过结果为undefined.


2.两种定义函数的方式

function abs(x){
if(x >= 0){
return x;
}else{
return -x;
}
}

//JavaScript的函数也是一个对象,因此,上面定义的abs()函数实际上是一个函数对象,而函数名abs可以视为指向该函数的变量
//因此,诞生了第二种定义函数的方式
var abs = function(x){
if(x >= 0){
return x;
}else{
return -x;
}
};


3.调用函数

abs(5);//5
abs(-6);//6

//JavaScript允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多或少都没有问题
abs(5,'yyc');//5
abs(-6,true,null,2);//6
abs();//NaN
-undefined;//NaN

//为了避免接收到undefined,可以对参数进行检查
function abs(x){
if(x !== 'number'){
throw 'x is not a number!';
}
if(x >= 0){
return x;
}else{
return -x;
}
}
abs();
//VM215:3 Uncaught x is not a number!


4.arguments

1.arguments是一个关键字,只在函数内部起作用。

2.作用:指向当前函数的调用者传入的所有参数。

3.类似Array,但不是一个Array

function foo(x){
console.log(x);//1
for(var i = 0;i < arguments.length;i++){
console.log(arguments[i]);//1 2 3 4 5
}
}
foo(1,2,3,4,5);

4.通过arguments,可以获得调用者传入的所有参数,也就是说,即使函数不定义任何参数,还是可以获得参数的值。
function abs(){
if(arguments.length === 0){
return 0;
}
var x = arguments[0];
return x >= 0 ? x : -x;
}
abs();
//0
abs(5);
//5
abs(-6);
//6

5.argumens主要用来判断传入参数的个数。


5.rest参数—只能写在最后,前面用…标识,避免使用arguments获取所有参数,然后剔除函数定义的参数,获得其他实际传入的参数。

//常规
function foo(a,b){
var i,rest = [];
if(arguments.length > 2){
for(var i = 2;i < arguments.length;i++){
rest.push(arguments[i]);
}
}
console.log('a = ' + a);
//a = 1
console.log('b = ' + b);
//b = 2
console.log(rest);
//[3,4,5]
}
foo(1,2,3,4,5);

//使用rest参数
function foo(a,b,...rest){
console.log('a = ' + a);
//a = 1
console.log('b = ' + b);
//b = 2
console.log(rest);
//[3,4,5]
}
foo(1,2,3,4,5);

function foo(a,b,...rest){
console.log('a = ' + a);
//a = 1
console.log('b = ' + b);
//b = undefined
console.log(rest);
//[]
}
foo(1);

function sum(...rest){
console.log(rest);//[1, 2, 3, 4, 5]
}
sum(1,2,3,4,5);

function sum(...rest){
var sum = 0 ;
for(var i = 0;i < rest.length;i++){
sum += rest[i];
}
return sum;
}
sum(1,2,3,4,5);//15


6.return的一个大坑

1.坑形成的原因:JavaScript引擎有一个在行末自动添加分号的机制。

2.跳下去试试坑
function hole(){
return
{name:'yyc'};
}
hole();//undefined

3.正常方式
function hole(){
return {name:'yyc'};
}
hole();
//{name: "yyc"}

4.保险起见
function hole(){
return {
name: 'yyc'
};
}
hole();
//{name: "yyc"}


三 变量作用域

1.不同函数内部的同名变量相互独立,因为用var申明的变量是有作用域的,当在函数中申明一个变量,该变量的作用域仅为该函数的整个函数体。

2.因为JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数的变量,反之不行!

//内访外----OK
function outer(){
var i = 1;
function inner(){
var y = i +2;
console.log(y);//3
}
inner();
}
outer();

//外访内---No!
function outer(){
var i = 1;
function inner(){
var y = i +2;
}
inner();
console.log(y);//VM297:7 Uncaught ReferenceError: y is not defined
}
outer();


3.如果内部函数和外部函数的变量名重名怎么办?

解决之法:JavaScript的函数在查找变量时,先从自身定义函数开始,由内向外。当内部函数定义了与外部函数重名的变量,优先使用内部函数自己的变量。

function outer(){
var i = 1;
function inner(){
var i = 'yyc';
console.log('内部函数中的i: ' + i);
}
inner();
console.log('外部函数中的i: ' + i);
}
outer();
>>>
内部函数中的i: yyc
外部函数中的i: 1


4.变量提升

function foo(){
var x = 'Hello, ' + y;
console.log(x);
var y = 'yyc';
}
foo();
//Hello, undefined

//其实是这样的
function foo(){
var y;//提升变量y的申明
var x = 'Hello, ' + y;
console.log(x);
y = 'yyc';
}
foo();

//x并没有变化,改变的仅仅是y
function foo(){
var x = 'Hello, ' + y;
console.log(x);
var y = 'yyc';
console.log(x);
}
foo();
>>>
Hello, undefined
Hello, undefined

function foo(){
var x = 'Hello, ' + y;
console.log(x);
var y = 'yyc';
x += y;
console.log(x);
}
foo();
>>>
Hello, undefined
Hello, undefinedyyc

//因此想要得到预期的效果:Hello, yyc:
function foo(){
var y = 'yyc';
var x = 'Hello, ' + y;
console.log(x);
}
foo();
>>>
Hello, yyc


5.全局作用域

1.不在任何函数内定义的变量就具有全局作用域。JavaScript默认有一个全局对象window,全局作用域中的变量实际上被绑定成window的一个属性:
var gv = 'learn JavaScript';
gv;
//"learn JavaScript"
window.gv;
//"learn JavaScript"


6.名字空间

1.存在的原因?当几个不同的JavaScript文件使用了同名的全局变量,或者定义了同名的顶层函数,就会造成命名冲突

2.因此将自己的代码全部放入唯一的命名空间yyc中,会大大减少全局变量冲突的可能
var yyc = {};
yyc.name = 'yyc';
yyc.version = 1.0;
yyc.interest = function(){
return 'reading';
};


7.let

1.存在原因?因为JavaScript只有全局作用域和局部作用域(函数内部),没有块级作用域的概念。

function foo(){
var sum = 0;
for(var i = 1;i < 5;i++){
sum += i;
}
console.log(sum);//10
console.log(i);//5
}
foo();

function foo(){
var sum = 0;
//变量i的生命周期仅存在于for循环中
for(let i = 1;i < 5;i++){
sum += i;
}
console.log(sum);//10
console.log(i);//Uncaught ReferenceError: i is not defined
}
foo();


8.常量

const PI = 3.14;
PI = 3;
PI;//Uncaught TypeError: Assignment to constant variable.


四 方法

1.在一个对象中绑定一个函数,成为这个对象的方法。

var Person = {
name: 'ycc',
birth: 1996,
age: function(){
var y = new Date().getFullYear();
return (y - this.birth);
}
};
Person.age();//21

//this是一个特殊的变量,它始终指向当前对象,这里,也就是Person这个对象。


2.this的一个大坑

function getAge(){
var y = new Date().getFullYear();
return (y - this.birth);
}
var Person = {
name: 'ycc',
birth: 1996,
age: getAge
};
Person.age();//21---这里的this指向的是Person对象,因此this.birth = 1996
getAge();//NaN-----因为this指向的是全局对象,因此this.birth = undefined

//验证一下
var birth = 2017;
function getAge(){
console.log(this.birth);
}
getAge();//2017


3.apply—控制this的指向

//常规
function getAge(){
var y = new Date().getFullYear();
return (y - this.birth);
}
var Person = {
name: 'ycc',
birth: 1996,
age: getAge
};
getAge();
//NaN

//使用apply----arug1代表需要绑定的this变量,null即为调用普通函数 ;argu2代表函数本身的参数
function getAge(){
var y = new Date().getFullYear();
return (y - this.birth);
}
var Person = {
name: 'ycc',
birth: 1996,
age: getAge
};
getAge.apply(Person,[]);
//21

Math.max.apply(null,[1,2,3,4,5]);
//5
Math.max.call(null,1,2,3,4,5);
//5


五 高级函数

1.什么是高阶函数?一个函数作为另一个函数的参数。

function add(a,b,f){
return f(a) + f(b);
}
add(5,-6,Math.abs);//11


2.Map | Reduce



1.将函数f(x) = x * x 作用在一个数组[1,2,3,4,5,6]上。
//常规方式
var arr = [1,2,3,4,5,6];
function powArray(arr){
var result = [];
for(var i = 0;i < arr.length;i++){
result.push(arr[i]*arr[i]);
}
return result;
}
powArray(arr);
//[1, 4, 9, 16, 25, 36]

//map----更优雅的方式----对于Array中的每个元素调用pow函数
function pow(x){
return x*x;
}
var arr = [1,2,3,4,5,6];
arr.map(pow);
//[1, 4, 9, 16, 25, 36]

//将Array的所有元素转化为布尔值
var arr = [null,undefined,0,'',NaN];
arr.map(Boolean);
//[false, false, false, false, false]


3.reduce



[x1,x2,x3,x4].reduce(f) = f(f(f(x1,x2),x3),x4)

Array求和
//常规方式
var arr = [1,2,3,4,5];
function summation(arr){
var sum = 0
for(var i = 0;i < arr.length;i++){
sum += arr[i];
}
return sum;
}
summation(arr);
//15

//reduce方式
var arr = [1,2,3,4,5];
function add(x,y){
return x+y;
}
arr.reduce(add);
//15

var arr = [1,2,3,4];
arr.reduce(function(x,y){
return x*10 + y;
});
//1234


4.***JavaScript进行减法运算时,会将前后的值转换为数值再进行运算,若转化失败,返回NaN

'111'-0;
//111

true- 0;
//1

null - 0;
//0

undefined - 0;
//NaN

'' - 0;
//0

//任务:"13579"---->[1,3,5,7,9]---->13579
var s = '13579';
function string2int(s){
function string2Number(x){
return x-0;
}
var intermediate = s.split('').map(string2Number);
function mul(x,y){
return x*10+y;
}
return intermediate.reduce(mul);
}
string2int(s);
//13579


5.输入:[‘adam’, ‘LISA’, ‘barT’],输出:[‘Adam’, ‘Lisa’, ‘Bart’]。

var arr = ['adam', 'LISA', 'barT'];
function normalize(arr){
function adjust(s){
//除了第一个字母其余全小写
var s1 = s.toLowerCase().slice(1);
var result = s[0].toUpperCase() + s1;
return result;
}
return arr.map(adjust);
}
normalize(arr);
>>>
(3) ["Adam", "Lisa", "Bart"]


6.map & parseInt | Number

var arr = ['1', '2', '3'];
arr.map(parseInt);
>>>
(3) [1, NaN, NaN]

why?
1.map()接收三个参数:element | index | array
2.parseInt()接收两个参数:string | radix [2-36]
3.parseInt()方法用于解析一个字符串,并返回一个整数

//等价于
parseInt('1',0);//1----代表默认进制,也就是十进制
parseInt('2',1);//NaN----radix的范围[2,36]
parseInt('3',2);//NaN----二进制只能包含0或1


7.filter

1.是什么?与map()类似,filter()也接收一个函数。

2.与map()区别:

//map()
var arr = [1,2,3,4,5,6];
arr.map(function(x){
return (x % 2 !== 0);
});
//(6) [true, false, true, false, true, false]

//filter----把传入的函数依次作用于每个元素,根据返回值是true/false来决定保留还是删除该元素。
var arr = [1,2,3,4,5,6];
arr.filter(function(x){
return (x % 2 !== 0);//保留奇数
});
//(3) [1, 3, 5]

3.去掉Array: ['A', '', 'B', null, undefined, 'C', '  '];中的空字符串
var arr = ['A', '', 'B', null, undefined, 'C', '  '];
arr.filter(function(x){
//左边的x先排除掉null、undefined和''纯的空字符串,因为这三兄弟Boolean()一下是false
//右边的表达式将'  '先转换为纯的空字符串,然后再Boolean一下,也是false
return (x && x.trim());
});
//(3) ["A", "B", "C"]


8.回调函数

1.map() & filter() 回调函数大PK

//map() --- element
var arr = ['yyc',2,true,null];
arr.map(function(element,index,array){
console.log(element);
});
>>>
yyc
2
true
null

//map() --- index
var arr = ['yyc',2,true,null];
arr.map(function(element,index,array){
console.log(index);
});
>>>
0
1
2
3

//map() --- array
var arr = ['yyc',2,true,null];
arr.map(function(element,index,array){
console.log(array);
});
>>>
["yyc", 2, true, null]
["yyc", 2, true, null]
["yyc", 2, true, null]
["yyc", 2, true, null]

//filter() --- element
var arr = ['yyc',2,true,null];
arr.filter(function(element,index,array){
console.log(element);
});
>>>
yyc
2
true
null

//filter() --- index
var arr = ['yyc',2,true,null];
arr.filter(function(element,index,array){
console.log(index);
});
>>>
0
1
2
3

//filter() --- array
var arr = ['yyc',2,true,null];
arr.filter(function(element,index,array){
console.log(array);
});
>>>
["yyc", 2, true, null]
["yyc", 2, true, null]
["yyc", 2, true, null]
["yyc", 2, true, null]

//好吧,事实证明,一样样的

删除一个数组中重复的字符串,如:['apple', 'strawberry', 'banana',
'pear', 'apple', 'orange', 'orange', 'strawberry'];

//常规方法
var arr = ['apple', 'strawberry', 'banana',
'pear', 'apple', 'orange', 'orange', 'strawberry'];
function unique(arr){
var result = [];
for(var i = 0;i < arr.length;i++){
if(result.indexOf(arr[i]) === -1){
result.push(arr[i]);
}
}
return result;
}
unique(arr);
>>>
(5) ["apple", "strawberry", "banana", "pear", "orange"]

//使用Set对象----特性:一个Key只能对于一个value
var arr = ['apple', 'strawberry', 'banana',
'pear', 'apple', 'orange', 'orange', 'strawberry'];
Array.from(new Set(arr));
>>>
(5) ["apple", "strawberry", "banana", "pear", "orange"]

//filter & indexOf----因为indexOf总是返回第一个元素的位置
var arr = ['apple', 'strawberry', 'banana',
'pear', 'apple', 'orange', 'orange', 'strawberry'];
arr.filter(function(element,index,array){
return (array.indexOf(element) === index);
});
>>>
(5) ["apple", "strawberry", "banana", "pear", "orange"]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  函数 filter rest map reduce