JavaScript学习(二) 函数

9,函数

9.1,函数的定义

方式一:

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

方式二:

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

JavaScript的函数也是一个对象,上述定义的abs()函数实际上是一个函数对象,而函数名abs可以视为指向该函数的变量

方式二相当于function (x) { ... }是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量abs,所以,通过变量abs就可以调用该函数。

9.2,函数的参数

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

abs(10, '1'); // 返回10
abs(-9, '1', '2', null); // 返回9

传入的参数比定义的少也没有问题:

abs();//NaN
//此时abs(x)函数的参数x将收到undefined,计算结果为NaN。

arguments

针对参数传递的随意性,arguments在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数(包括有效的参数)

function abs(x) {
    if(arguments.length===2){
        console.log("没想到我是第二个参数吧"+arguments[1]);
    }
    if(x>0){
        return x;
    }else{
        return -x;
    }
}
abs(1,null);//输出:没想到我是第二个参数吧null

rest

ES6标准引入了rest参数,可以获取多余的参数

rest参数只能写在最后,前面用...标识,从运行结果可知,传入的参数先绑定ab,多余的参数以数组形式交给变量rest,所以,不再需要arguments我们就获取了全部参数。

如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。

//使用严格检查模式
'use strict'

function abs(x,...rest) {
    console.log("没想到我是第二个参数吧"+rest[0]);
    console.log("没想到我是第三个参数吧"+rest[1]);
    if(x>0){
        return x;
    }else{
        return -x;
    }
}
abs(1,null,true);//没想到我是第二个参数吧null 没想到我是第三个参数吧true

return

有坑 不要分行写 JavaScript引擎有一个在行末自动添加分号的机制

9.3,变量作用域与解构赋值

var 的作用域

函数体内独立性

如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量:

function f() {
    var x =1;
    console.log(x);
}
console.log(x);  //ReferenceError: x is not defined

如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响:

function f1() {
    var x =1;
    console.log(x);  //1
}

function f2() {
     var x=2;
     console.log(x); //2
}

函数嵌套,由内而外

由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行:

function foo() {
    var x = 1;
    function bar() {
        var y = x + 1; // bar可以访问foo的变量x!
    }
    var z = y + 1; // ReferenceError! foo不可以访问bar的变量y!
}

加入内层函数与外层函数发生了重名,则会遵循由内而外的机制,内层函数变量,会屏蔽外层的变量

9.4,变量提升

约定规范:在函数内部首先申明所有变量

所有的变量命名都会被自动提取到函数头部

9.5,全局作用域

不在任何函数内定义的变量就具有全局作用域。实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性:

var x =1;
console.log(window.x);//1

其实在9.1中方式二定义的函数,就是把abs变量绑定到了window的属性上了。

9.6,名字空间

因为全局定义的变量,会被自动绑定到window对象上,所以很容易存在命名冲突,因此自定义全局命名空间,就能够避免名字冲突的问题

//定义自己的命名空间
var mynamespace ={

};
//把所有的全局属性绑定到自己定义的命名空间中,调用时带上命名空间
mynamespace.ele1=1;
mynamespace.ele2=2;

console.log(mynamespace.ele1);//1

9.7,局部作用域

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

总结:JS中作用域有:全局作用域、函数作用域。没有块作用域的概念。ECMAScript 6(简称ES6)中新增了块级作用域。
块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。

function f3() {
    var x=1;
    //函数体作用域
    for(let x=1;x<5;x++){
        //块级作用域
        console.log(x);
    }
    console.log(x);
}
f3();   //1,2,3,4,1


{
    //块级作用域
    let x=1;
    console.log(x);//1
}
console.log(x);//ReferenceError: x is not defined

9.8,常量

由于varlet申明的是变量,如果要申明一个常量,在ES6之前是不行的,我们通常用全部大写的变量来表示“这是一个常量,不要修改它的值”:(约定俗成)!!!

ES6则引入新的关键字:const

//定义常量
const PI =3.14;
PI=5;//不能再次赋值

9.9 ,顶层对象

在浏览器环境指的是window对象,在 Node 指的是global对象。

ES5 中,顶层对象的属性与全局变量是等价的;ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
ES6中:

var、function声明的全局变量,依旧是顶层对象的属性;
let、const、class声明的全局变量,不属于顶层对象的属性。

9.10,解构赋值

从ES6开始,JavaScript引入了解构赋值,可以同时对一组变量进行赋值。

可以使用解构赋值,直接对多个变量同时赋值

//解构赋值-数组  变量取值由位置决定
var [x,y,z]=[1,2,true,false];//多余的值会被忽略
console.log('x:'+x+' y:'+ y +' z:'+z);//x:1 y:2 z:true

var [x1,y1,z1]=[,,true,false];//可以省略某些值的赋值,以逗号为分割
console.log('x1:'+x1+' y1:'+ y1+' z1:'+z1);//x:undefined y:undefined z:true

//注意,对数组元素进行解构赋值时,多个变量要用[...]括起来。
// 如果数组本身还有嵌套,也可以通过下面的形式进行解构赋值,注意嵌套层次和位置要保持一致:
let [x2, [y2, z2]] = ['hello', ['JavaScript', 'ES6']];
x2; // 'hello'
y2; // 'JavaScript'
z2; // 'ES6'


//变量要与属性同名
//如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性:
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school'
};
var {name, age, passport} = person;
console.log(name);
console.log(age);
console.log(passport);


//对一个对象进行解构赋值时,同样可以直接对嵌套的对象属性进行赋值,只要保证对应的层次是一致的:
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school',
    address: {
        city: 'Beijing',
        street: 'No.1 Road',
        zipcode: '100001'
    }
};
var {name, address: {city, zip}} = person;
name; // '小明'
city; // 'Beijing'
zip; // undefined, 因为属性名是zipcode而不是zip
// 注意: address不是变量,而是为了让city和zip获得嵌套的address对象的属性:
//address; // Uncaught ReferenceError: address is not defined

//解构赋值还可以使用默认值,这样就避免了不存在的属性返回undefined的问题:
//默认值生效的条件是,对象的属性值严格等于undefined;解构失败,变量的值等于undefined
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678'
};

// 如果person对象没有single属性,默认赋值为true:
var {name, single=true} = person;

// 声明变量:
// var x4, y4;
// 解构赋值:
var {x4, y4} = { name: '小明', x: 100, y: 200};
// 语法错误: Uncaught SyntaxError: Unexpected token
// //js引擎会将{}理解为代码块


//字符串

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
let {length : len} = 'hello';
len // 5   类似数组的对象都有一个length属性

//数值和布尔值
// 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象;
// undefined、null无法转为对象,会报错。
var {toString:num}=123;
console.log(num===Number.prototype.toString);//true
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
9.10.1,解构赋值的应用

交换两个变量xy的值,可以这么写,不再需要临时变量:

var x=1, y=2;
[x, y] = [y, x]

快速获取当前页面的域名和路径:

var {hostname:domain, pathname:path} = location;

如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。例如,下面的函数可以快速创建一个Date对象:

function buildDate({year, month, day, hour=0, minute=0, second=0}) {
    return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}
buildDate({ year: 2017, month: 1, day: 1 });
// Sun Jan 01 2017 00:00:00 GMT+0800 (CST)

使用解构赋值可以减少代码量,但是,需要在支持ES6解构赋值特性的现代浏览器中才能正常运行。目前支持解构赋值的浏览器包括Chrome,Firefox,Edge等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值