定义函数
方式一定义函数:
function abs(x){
if (x >= 0) {
return x;
} else{
return -x;
}
}
console.log(abs(-5));
上述函数的定义:
function指出这是一个函数定义;
abs是函数的名称;
(x)括号内列出函数的参数,多个参数以,分隔;
{ … }之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
方式二定义函数
var abs = function(x){
if (x >= 0) {
return x;
} else{
return -x;
}
}
//调用方式
console.log(abs(-58));
//传入为空时,输出NaN
console.log(abs());
为了避免发生undefined,可以对参数进行检查
function abs(x) {
//判断x是否为number类型
if (typeof x !== 'number') {
//抛出异常
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
arguments(用于判断传入参数的个数)
JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array:
function foo(x){
console.log('x = '+ x );
for (var i = 0; i < arguments.length; i++) {
console.log('arg'+i+'='+arguments[i]);
}
}
console.log(foo(10,20,30,1));
function foot(a,b,c){
if(arguments.length == 3){
c = b;
console.log("c="+c);
b = null;
}else{
throw '参数太多了';
}
}
console.log(foot(1,2,3));
rest
只能写在最后,前面用…标识,这是ES6标准引入的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 []
在JavaScript引擎在行末自动添加分号的机制所以一般写成
function foo() {
return { // 这里不会自动加分号,因为{表示语句尚未结束
name: 'foo'
};
}
名字空间:
全局变量会绑定到window上,不同的js文件如果使用了相同的全局变量或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。
减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。例如:
//定义唯一全局变量MAPP
var MAPP = {};
//其他变量
MAPP.name = 'myapp';
MAPP.version = 1.0;
MAPP.age = 18;
//其他函数
MAPP.foo = function(){
return 'foot';
};
console.log(MAPP);
把自己的代码全部放入唯一的名字空间MAPP中,会大大减少全局变量冲突的可能。
局部作用域
由于js的变量作用域实际上是函数内部,我们在for循环等语句块中是无法定义具有局部作用域的变量的:
function foo(){
//使用var定义的全局变量可以在其他地方使用
for (var i = 0; i < 100; i++) {
//
i += 10;
}
console.log(i);
}
console.log(foo());
为了解决这个问题,ES6引入 了新的关键字let,用let替代var来定义块级作用域:
function foo(){
//使用var定义的全局变量可以在其他地方使用
for (let i = 0; i < 100; i++) {
//
i += 10;
}
console.log(i);
}
console.log(foo());
这样就是真正的全局变量只能局部进行使用!
ES6标准引入const来定义常量,const与let都具有块级作用域
const PI = 3.14;
console.log(PI);
解构赋值
ES6开始,JavaScript引入了解构赋值,可以同时对一组变量进行赋值
传统方式如何将数组元素赋值给多个变量
var array = ['hello','java','sfasfs'];
var x = array[0];
var y = array[1];
var z = array[2];
console.log(x,y,z);
ES6的解构赋值,直接 对多个变量同时赋值
var [x,y,z] = ['hello','java','sfasfs'];
console.log('x='+x+',y='+y+',z='+z);
当然位置可以保持一致也可以忽略某些元素
var [, ,z] = ['hello','java','sfasfs'];
console.log(z);
如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性:
var person = {
name:'小明',
age:20,
gender:'male',
passport:'G-123456',
school:'No.4 middle school'
};
var {name,age,passport} = person;
console.log('name = ' + name + ', age = ' + age + ', passport = ' + passport);
直接嵌套对象属性进行赋值,必须保证对应的层次是一致性的:
var person = {
name:'小明',
age:20,
gender:'male',
passport:'G-123456',
school:'No.4 middle school',
address:{
city:'GS',
street:'No.1 Road',
zipcode:'101010'
}
};
var {name,age,address:{city,zipcode}} = person;
console.log('name = ' + name + 'city=' + city);
解构赋值还可以使用默认值,这样就避免了不存在的属性返回undefined的问题:
var person = {
name:'小明',
age:20,
gender:'male',
passport:'G-123456',
school:'No.4 middle school',
address:{
city:'GS',
street:'No.1 Road',
zipcode:'101010'
}
};
var {name,age,address:{city,zipcode}} = person;
//single事先在对象中没有定义,如果要加就要赋值
var {name,age,passport,single=true} = person;
console.log('single='+single);
有时候,如果变量已经被声明了,再次赋值的时候,正确的写法也会报语法错误
var x, y;
// 解构赋值:
{x, y} = { name: '小明', x: 100, y: 200};
正确的做法是:(用小括号括起来就可以解决了!)
({x, y} = { name: '小明', x: 100, y: 200});
解析赋值的应用场景:
1.交换两个元素的值
var x = 1,y = 2;
console.log('原来的值 :x='+x+',y='+y);
[x,y] = [y,x];
console.log('交换后的值 :x='+x+',y='+y);
2.快速获取当前页面的域名和路径
var {hostname:domain, pathname:path} = location;
如果一个函数接收一个对象作为参数 ,那么 ,可以使用解构直接把对象的属性绑定到变量中,例如 :
function buildDate({year,month,day}){
return new Date(year + '-' + month + '-' + day);
}
console.log(buildDate({year:2020,month:5,day:1}));
方法
在一个对象中绑定函数,称为这个对象的方法
在JavaScript中定义一个对象:
var XM = {
name:'hk',
brith:1999
};
console.log(XM);
然后在对象中定义一个函数
var XM = {
name:'hk',
brith:1999,
age:function(){
var y = new Date().getFullYear();
return y - this.brith;
}
};
console.log(XM.age());
在一个方法内部,this是一个特殊变量,它始终指向当前对象,也就是XM这个变量,所以,this.birth可以拿到XM的birth属性。
var XM = {
name:'hk',
brith:1999,
age:function(){
//在方法内部一开始就捕获this然后使用
var that = this;
function getAgeFromBirth(){
var y = new Date().getFullYear();
return y - that.brith;//这里使用的是that而不是this
}
return getAgeFromBirth();
}
};
console.log(XM.age());
apply
虽然在一个独立的函数调用中,根据是否是strict模式,this指向undefined或window,不过,我们还是可以控制this的指向的!
var XM = {
name:'hk',
birth:1999,
age:getAge
};
function getAge(){
var y = new Date().getFullYear();
return y - this.birth;
}
//25
onsole.log(XM.age());
//this指向XM,参数为空
console.log(getAge.apply(XM,[]));
另一个与apply()类似的方法是call(),唯一的区别是:
- apply()把参数打包成Array再传入
- call()把参数按顺序传入
比如调用Math.max(3,4,5),分别用apply()和call()实现如下 :
console.log(Math.max.apply(null,[3,5,6]));
console.log(Math.max.call(null,3,5,6));
装饰器
利用apply(),我们还可以动态改变函数的行为。
JavaScript的所有对象都是动态的,如果我们想统一下代码一共调用了多少次parseInt(),可以把所有的调用都找出来,然后手动加上count += 1,不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt():
var count = 0;
var oldParseInt = parseInt;//保存原函数
window.parseInt = function(){
//计数
count += 1;
return oldParseInt.apply(null,arguments);//调用原函数
};
parseInt('10');
parseInt('20');
parseInt('30');
parseInt('20');
parseInt('30');
console.log('count = ' + count);//3