JavaScript——函数
一、函数的定义
定义一个函数:
方式一
function 函数名(参数){
逻辑语句;
}
例如:绝对值函数
function abs(x){
if(x>=0){
return x;
}else{
return -x;
}
}
一旦执行到 return 代表函数结束,返回结果!
如果没有执行 return ,函数执行完也会返回结果,结果就是 undefined
方式二
变量类型 函数名称 = function(参数){
逻辑语句;
}
var abs = function(x){
if(x>=0){
return x;
}else{
return -x;
}
}
function(x){ …. } 这是一个匿名函数。但是可以把结果赋值给 abs ,通过abs 就可以调用函数!
方式一和方式二等价!
二、调用函数
在javaScript 函数中可以传任意个参数,也可以不传递参数,不会报错!
如何规避不存在的参数?
var abs = function(x){
//手动抛出异常来判断
if (typeof x!== 'number') {
throw 'Not a Number';
}
if(x>=0){
return x;
}else{
return -x;
}
}
arguments
arguments是一个JS免费赠送的关键字,
代表,传递进来的所有的参数,是一个数组!
var abs = function(x){
console.log("x=>"+x);
for (var i = 0; i<arguments.length;i++){
console.log(arguments[i]);
}
if(x>=0){
return x;
}else{
return -x;
}
}
由上图就可以看出来,多个参数传递进去都是存在的,并且也都存储在arguments数组中!
问题: arguments 包含所有的参数,我们有时候想使用多余的参数来进行附加操作。需要排除已有参数,这种操作会带来弊端,为了解决这种弊端,ES6 引入了新特性(rest)。
rest
在未引入rest之前,获取除了已经定义的参数之外的所有参数使用下面的方法
if (arguments.length>2){
for (var i = 2; i<arguments.length;i++){
//...
}
}
现在,
function aaa(a,b,...rest) {
console.log("a=>"+a);
console.log("b=>"+b);
console.log(rest);
}
注意:rest 参数只能写在最后面,必须用 … 标识。
三、变量的作用域
function cm() {
var x = 1;
x = x + 1;
}
x = x + 2;
报错了,这就说明,在javascript中, var 定义变量实际是有作用域的。
因此在函数体中声明的变量,在函数体外不可以使用。
function cm() {
var x = 1;
x = x + 1;
}
function cm2() {
var x = 'A';
x = x + 1;
}
以上运行结果说明,函数具有高度独立性!!!
function cm() {
var x = 1;
function cm2() {
var y = x + 1;
}
}
没有报错,只是不存在返回值而已;
<script>
function cm() {
var x = 1;
function cm2() {
var y = x + 1; // 2
}
var z = y + 1;
}
</script>
此时报错了,说明内部函数可以访问外部函数的成员,反之则不行!
假设,内部函数变量和外部函数的变量重名
<script>
function cm() {
var x = 1;
function cm2() {
var x = 'A';
console.log('inner'+x);
}
console.log('outer'+x);
}
cm();
</script>
<script>
function cm() {
var x = 1;
function cm2() {
var x = 'A';
console.log('inner'+x);
}
console.log('outer'+x);
cm2();
}
cm();
</script>
因此,在JavaScript 中,函数查找变量是从自身函数开始,由 ‘’内‘’ 向 ‘’外‘’ 查找 。 假设外部存在这个同名的函数变量,则内部函数会屏蔽外部函数的变量!
提升变量的作用域
例一
<script>
function cm() {
var x = "x" + y;
console.log(x);
var y = 'y';
}
</script>
例二
<script>
function cm2() {
var y;
var x = "x" + y;
console.log(x);
y = 'y';
}
</script>
以上两个例子说明 ; js 执行引擎,自动提升了y的声明,但是不会提升变量y的赋值;
function cm() {
var x = 1,
y = x + 1,
z,i,a; //undefined
//之后可以随意对以上变量进行使用
}
养成规范: 所有的变量定义都放在函数的头部,不要乱放,以便于代码维护;
全局函数
-
全局变量
<script> var x = 1; function f() { console.log(x); } f(); console.log(x); </script>
-
全局对象window
全局变量都会绑定在window下
<script>
var x = 'xxx';
alert(x);
alert(window.x); // 默认所有的全局变量,都会自动绑定在 window对象下;
</script>
alert() 这个函数本身也是一个 window
变量;
<script>
var x = 'xxx';
window.alert(x);
</script>
再
<script>
var old_alert = window.alert;
old_alert(x);
</script>
再
<script>
var old_alert = window.alert;
old_alert(x);
window.alert = function () {
};
window.alert(123);
</script>
此时你会发现 alert() 失效了
再
<script>
var old_alert = window.alert;
old_alert(x);
window.alert = function () {
};
// 发现 alert() 失效了
window.alert(123);
//恢复
window.alert = old_alert;
window.alert(456);
</script>
以上测试说明:
Javascript 实际上只有一个全局作用域, 任何变量(函数也可以视为变量),假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域也没有找到,就会报错 RefrenceError
(引用异常)。
如:
<script>
window.alert(x);
</script>
因此提出了JS中的规范。
规范
由于我们所有的全局变量都会绑定到我们的 window 上。如果不同的js 文件,使用了相同的全局变量,就会冲突如果能够减少冲突?
<script>
// 唯一全局变量
var cm = {};
// 全部绑定到唯一的全局变量
cm.name = 'kuangshen';
cm.add = function (a,b) {
return a + b;
}
</script>
把自己的代码全部放入自己定义的唯一空间名字中, 以降低全局命名冲突的问题
正如jQuery一样
局部作用域 let
问题
<script>
function aaa() {
for (var i = 0; i < 3; i++) {
console.log(i)
}
console.log(i+1);
}
</script>
i 出了这个作用域还可以使用!!!
这和我们之前学的不一样呀,我们并不想让i 出了这个作用域还可以使用。于是ES6就引入了 let 关键字,解决局部作用域冲突问题!
此时
<script>
function aaa() {
for (let i = 0; i < 3; i++) {
console.log(i)
}
console.log(i+1);
</script>
以上便达到了我们的要求。
因此,建议大家都使用 let
去定义局部作用域的变量!
常量 const
在ES6 之前,定义常量采用强行洗脑方式,即:用全部大写字母命名的变量就是常量;建议不要修改这样的值。
var PI = '3.14';
console.log(PI);
PI = '213'; //其实是可以改变这个值的,只要不被洗脑
console.log(PI);
这样定义常量的方法一点都不严谨,也很滑稽。
为此, ES6 引入了常量关键字 const
<script>
const PI = '3.14'; // 只读变量
console.log(PI);
PI = '123';
console.log(PI);
</script>
这样定义常量的方法,就不会有被随意修改的风险了。
四、方法
方法的定义
方法:就是放在对象里面的函数。
对象只有两个东西 : 属性和方法。
<script>
var person = {
name: '张三',
bitrh: 2000,
// 方法
age: function () {
// 今年 - 出生的年
var now = new Date().getFullYear();
return now-this.bitrh;
}
}
//属性
console.log(person.name);
//方法,一定要带 ()
console.log(person.age());
</script>
探讨:this.代表什么?
拆开上面的代码看看
function getAge() {
// 今年 - 出生的年
var now = new Date().getFullYear();
return now-this.bitrh;
}
var person = {
name: '张三',
bitrh: 2000,
age: getAge
}
console.log(person.name);
console.log(person.age());
此时的getAge()是window对象调用的,但是window对象并没有这个方法,因此结果为NaN。
这就更进一步说明了,明确对象的重要性(即,遵守规范的重要性)。
以上运行结果说明:this是无法指向的,是默认指向调用它的那个对象!
apply()
在JS中,控制this指向的一种方法。
<script>
function getAge() {
// 今年 - 出生的年
var now = new Date().getFullYear();
return now-this.bitrh;
}
var person = {
name: '张三',
bitrh: 2000,
age: getAge
};
var xiaoming = {
name: '小明',
bitrh: 2001,
age: getAge
};
console.log(getAge.apply(xiaoming,[]));// this,指向了 xiaoming,参数为空
</script>
通过给apply()传递参数(其所指向的对象和所需的参数),控制this的指向,完成一定的功能。