JS函数
2021-03-03 11:27
标签:nts 属性 了解 word 交换 嵌套 argument row 扫描 上述两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个 由于JavaScript允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数: 传入的参数比定义的少也没有问题: 此时 要避免收到JS函数
函数定义
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}abs()
函数实际上是一个函数对象,而函数名abs
可以视为指向该函数的变量。var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};;
,表示赋值语句结束。调用函数
abs(10, ‘blablabla‘); // 返回10
abs(-9, ‘haha‘, ‘hehe‘, null); // 返回9abs(); // 返回NaN
abs(x)
函数的参数x
将收到undefined
,计算结果为NaN
。undefined
,可以对参数进行检查:function abs(x) {
if (typeof x !== ‘number‘) {
throw ‘Not a number‘;
}
if (x >= 0) {
return x;
} else {
return -x;
}
}arguments
arguments
,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments
类似Array
但它不是一个Array
:function foo(x) {
console.log(‘x = ‘ + x); // 10
for (var i=0; iarguments.length; i++) {
console.log(‘arg ‘ + i + ‘ = ‘ + arguments[i]); // 10, 20, 30
}
}
foo(10, 20, 30);
arguments
最常用于判断传入参数的个数。
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 []
rest参数只能写在最后,前面用...
标识,从运行结果可知,传入的参数先绑定a
、b
,多余的参数以数组形式交给变量rest
,所以,不再需要arguments
我们就获取了全部参数。
小心你的return语句
function foo() {
return
{ name: ‘foo‘ };
}
?
foo(); // undefined
要小心了,由于JavaScript引擎在行末自动添加分号的机制,上面的代码实际上变成了:
function foo() { return; // 自动添加了分号,相当于return undefined; { name: ‘foo‘ }; // 这行语句已经没法执行到了 }
嵌套函数
function foo() { var x = 1; function bar() { var x = ‘A‘; console.log(‘x in bar() = ‘ + x); // ‘A‘ } console.log(‘x in foo() = ‘ + x); // 1 bar(); } foo();
JavaScript的函数在查找变量时从自身函数定义开始,从“内”向“外”查找。如果内部函数定义了与外部函数重名的变量,则内部函数的变量将“屏蔽”外部函数的变量。
变量提升
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:
语句var x = ‘Hello, ‘ + y;
并不报错,原因是变量y
在稍后申明了。但是console.log
显示Hello, undefined
,说明变量y
的值为undefined
。这正是因为JavaScript引擎自动提升了变量y
的声明,但不会提升变量y
的赋值。
对于上述foo()
函数,JavaScript引擎看到的代码相当于:
function foo() { var y; // 提升变量y的申明,此时y为undefined var x = ‘Hello, ‘ + y; console.log(x); y = ‘Bob‘; }
命名空间
// 唯一的全局变量MYAPP: var MYAPP = {}; // 其他变量: MYAPP.name = ‘myapp‘; MYAPP.version = 1.0; // 其他函数: MYAPP.foo = function () { return ‘foo‘; };
把自己的代码全部放入唯一的名字空间MYAPP
中,会大大减少全局变量冲突的可能。
let
‘use strict‘; function foo() { for (var i=0; i为了解决块级作用域,ES6引入了新的关键字
let
,用let
替代var
可以申明一个块级作用域的变量:‘use strict‘; function foo() { var sum = 0; for (let i=0; i常量
ES6标准引入了新的关键字
const
来定义常量,const
与let
都具有块级作用域:‘use strict‘; const PI = 3.14; PI = 3; // 某些浏览器不报错,但是无效果! PI; // 3.14解构赋值
var [x, y, z] = [‘hello‘, ‘JavaScript‘, ‘ES6‘];如果数组本身还有嵌套,也可以通过下面的形式进行解构赋值,注意嵌套层次和位置要保持一致:
let [x, [y, z]] = [‘hello‘, [‘JavaScript‘, ‘ES6‘]]; x; // ‘hello‘ y; // ‘JavaScript‘ z; // ‘ES6‘解构赋值还可以忽略某些元素:
let [, , z] = [‘hello‘, ‘JavaScript‘, ‘ES6‘]; // 忽略前两个元素,只对z赋值第三个元素 z; // ‘ES6‘如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性:
var person = { name: ‘小明‘, age: 20, gender: ‘male‘, passport: ‘G-12345678‘, school: ‘No.4 middle school‘ }; var {name, age, passport} = person;对一个对象进行解构赋值时,同样可以直接对嵌套的对象属性进行赋值,只要保证对应的层次是一致的:
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如果要使用的变量名和属性名不一致,可以用下面的语法获取:
var person = { name: ‘小明‘, age: 20, gender: ‘male‘, passport: ‘G-12345678‘, school: ‘No.4 middle school‘ }; // 把passport属性赋值给变量id: let {name, passport:id} = person; name; // ‘小明‘ id; // ‘G-12345678‘ // 注意: passport不是变量,而是为了让变量id获得passport属性: passport; // Uncaught ReferenceError: passport is not defined解构赋值还可以使用默认值,这样就避免了不存在的属性返回
undefined
的问题:var person = { name: ‘小明‘, age: 20, gender: ‘male‘, passport: ‘G-12345678‘ }; // 如果person对象没有single属性,默认赋值为true: var {name, single=true} = person; name; // ‘小明‘ single; // true有些时候,如果变量已经被声明了,再次赋值的时候,正确的写法也会报语法错误:
// 声明变量: var x, y; // 解构赋值: {x, y} = { name: ‘小明‘, x: 100, y: 200}; // 语法错误: Uncaught SyntaxError: Unexpected token =这是因为JavaScript引擎把
{
开头的语句当作了块处理,于是=
不再合法。解决方法是用小括号括起来:({x, y} = { name: ‘小明‘, x: 100, y: 200});使用场景
var x=1, y=2; [x, y] = [y, x];//交换变量 var {hostname:domain, pathname:path} = location;//快速获得域名和路径 function buildDate({year, month, day, hour=0, minute=0, second=0}) { return new Date(year + ‘-‘ + month + ‘-‘ + day + ‘ ‘ + hour + ‘:‘ + minute + ‘:‘ + second); } //如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。闭包
函数的返回依然是函数,嵌套函数可以访问外层函数的局部变量,从而携带了状态,模拟对象的效果。
function lazy_sum(arr) { var sum = function () { return arr.reduce(function (x, y) { return x + y; }); } return sum; }坑
function count() { var arr = []; for (var i=1; i上面代码中的
arr
内部的i
会覆盖之前入队的值,因为是同一个引用。返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变(实质是对循环变量进行值复制,让最内层函数指向不同内存):
function count() { var arr = []; for (var i=1; i注意这里用了一个“创建一个匿名函数并立刻执行”的语法:
(function (x) { return x * x; })(3); /* 9,如果这么写:function (x) { return x * x } (3);由于JavaScript语法解析的问题,会报SyntaxError错误 */闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。
‘use strict‘; function create_counter(initial) { var x = initial || 0; return { inc: function () { x += 1; return x; } } }它用起来像这样:
var c1 = create_counter(); c1.inc(); // 1 c1.inc(); // 2 c1.inc(); // 3 var c2 = create_counter(10); c2.inc(); // 11 c2.inc(); // 12 c2.inc(); // 13
JS函数
标签:nts 属性 了解 word 交换 嵌套 argument row 扫描
原文地址:https://www.cnblogs.com/biwangwang/p/14263196.html