1、函数的基础操作
函数指实现某一个功能的方法,也叫子程序,OOP中的方法
JS中函数有两部分:创建函数和执行函数
创建的时候函数被保存成字符串没有实际意义;执行的时候才实现它真正的意义。
多次用到的功能就可以封装成一个函数,提高开发效率;页面代码的冗余度减少了,代码重复利用率也提高了:低耦合高内聚
2、函数核心操作原理
创建函数
:
- 声明函数(跟变量声明一样的操作)
- 浏览器开辟一个内存空间(分配一个16进制的地址),保存函数体中的代码
执行函数
:
- 函数执行的时候,浏览器首先会开辟一个新的
私有作用域
来执行之前编写的代码- 形参赋值
- 私有作用域中的变量提升
- 把之前存储的字符串格式的代码自上而下执行
- 私有作用域销毁(私有作用域中有被外界引用的部分时不销毁)
闭包
:
函数执行会形成一个私有作用域,把私有变量保护起来不受外界干扰
栈内存和堆内存
:
栈内存又叫作用域,提供一个JS代码执行的环境
堆内存保存引用数据类型需要存储的内容(相当于一个仓库)
3、形参和实参
形参:执行函数的时候需要执行者传递进来的值
实参:执行者执行的时候传递给形参的具体值
function sum(num1, num2){ //num1, num2相当于在当前作用域下已经声明(var)
var total = num1 + num2;
console.log(total);
}
sum(10); // 只传递了num1,num2没传递就默认为undefined
// 在可能出现不传值的情况下可以设置默认值
function sum(num1, num2){ //num1, num2相当于在当前作用域下已经声明(var)
// 容错处理
// num1 === undefined ? num1= 0 : null;
// typeof(num2) === 'undefined' : num2=0 : null; // 项目中常用
// 逻辑或的方式
num1 = num1 || 0;
num2 = num2 || 0;
var total = num1 + num2;
console.log(total);
}
sum(10); // 只传递了num1,num2默认0
4、arguments实参集合
不知道具体传递参数的数量时,无法设置形参的个数,就需要使用函数内置的实参集合arguments
1、arguments只有函数才有
2、不管执行函数时是否传递实参,arguments都是存在的,不传递实参的时候arguments为空集合,传递的时候arguments包含所有传递的实参
arguments是一个类数组集合,有length属性,根据下标获取实参信息arguments.calee 存储的是当前函数本身
arguments.calee.caller 存储的是当前函数的宿主函数,没啥用基本
严格模式下不许使用以上两个属性
5、JS中的返回值return
闭包机制使得私有作用域会保护里面的私有作用域
return 返回的都是值,若函数中没有return或者return;,结果都是undefined,return后面的代码不执行。
function sum() {
var total = null;
for (let i = 0; i < arguments.length; i++) {
var cur = arguments[i];
!isNaN(cur) ? total += cur : null;
}
return total;
//此处不是把total这个变量返回,而是返回total中存储的值 <=> 60
}
console.log(sum(10, 20, 30)); // 60
6、匿名函数
没有名字的函数
- 函数表达式, 把一个没有名字的函数赋值给一个变量或者某个元素的点击事件
oBox,onclick = function(){
// do something
}
- 自执行函数,前面的符号;,-,+,~,!都可以
;(function (n){
// do something
// n是形参
})(10);
// 以下都是自执行函数,符号只是控制语法的规范
~(function (n){})(10);
-(function (n){})(10);
+(function (n){})(10);
!(function (n){})(10);
函数本身也有一些属性
length
:形参的个数
name
:函数名
prototype
:类的原型,在原型上定义的方法都是当前类实例的公有方法
__proto\__
:把函数当做一个普通对象,指向Function
这个类的原型
函数在JS中是最复杂也是最重要的
一个函数存在多面性:
1、它本身是一个普通的函数,执行的时候行程私有的作用域(闭包),经历形参赋值,变量提升,代码执行,执行完成后栈内存销毁或者不销毁(当函数内的某一部分被外界变量接收时不销毁)。
2、它也可以是一个类,拥有自己的实例,有一个prototype
属性是自己的原型,它的实例都指向这个原型。
3、普通对象,是Function
这个类的一个实例,实例都是对象数据类型,作为对象可以有自己的一些私有属性,也可以通过__proto\__
属性找到Function.prototype
。
三者之间没有必然联系
function Fn(){
var num = 500;
this.x = 100;
}
Fn.prototype.getX = function(){
console.log(this.x);
}
Fn.aaa = 10000;
var f = new Fn; // 此时Fn中的this是实例f
console.log(f.num); // undefined
console.log(f.aaa); // undefined
var res = Fn();
console.log(res); // undefined 此时Fn中的this是window
Function
类的原型Function.prototype
是函数数据类型的值,但是相关操作和其他函数的原型一样
网友评论