- 函数基础与种类、型实参及映射、变量类型
函数 x,y 任意一个 x 的值 都会有一个确定的 y x 自变量
函数值是确定的
函数式编程
function test(a, b, c){
//执行语句
}
耦合 : 重复的代码太多了,代码的重复度太高了
高内聚:强功能性,高独立性
低耦合:把重复的代码提取出来 -> 模块的单一责任制
解耦合:使用函数可以很好的进行解耦合
1. 最基本的函数写法 -> 函数声明 函数只有被调用的时候执行 function text(参数){ 函数的多个执行语句; }
2. 函数名的命名规则 不能数字开头 字母 _ $ 包含数字 驼峰命名法 复合单词 myWonder
3. 函数声明的方式
1) function text(参数){
函数的多个执行语句;
}
2)匿名函数表达式 函数字面量
var test = function test1(参数){ ->匿名函数
函数的多个执行语句;
}
声明了一个函数test1
将test1这个函数赋值给test
test函数执行的时候会默认忽略test1
test1 函数内部可以适应test1()进行实行
函数有个属性 console.log(test.name)// test1
4. 函数的组成部分
function 函数名 参数(可选) 返回值(可选) return
var a = Number(window.prompt(“a”));
var b = Number(window.prompt(“b”));
占位符 -> 形参
function test(a,b,c){
console.log(a ,b,c)
}
//形参和实参数量可不等
//实际参数 -> 实参 参数没有数据类型
test(1,2);
function test(a, b){ - #立即执行函数、闭包深入、逗号运算符
函数基础与种类、型实参及映射、变量类型
函数 x,y 任意一个 x 的值 都会有一个确定的 y x 自变量
函数值是确定的
函数式编程
function test(a, b, c){
//执行语句
}
耦合 : 重复的代码太多了,代码的重复度太高了
高内聚:强功能性,高独立性
低耦合:把重复的代码提取出来 -> 模块的单一责任制
解耦合:使用函数可以很好的进行解耦合
1. 最基本的函数写法 -> 函数声明 函数只有被调用的时候执行 function text(参数){ 函数的多个执行语句; }
2. 函数名的命名规则 不能数字开头 字母 _ $ 包含数字 驼峰命名法 复合单词 myWonder
3. 函数声明的方式
1) function text(参数){
函数的多个执行语句;
}
2)匿名函数表达式 函数字面量
var test = function test1(参数){ ->匿名函数
函数的多个执行语句;
}
声明了一个函数test1
将test1这个函数赋值给test
test函数执行的时候会默认忽略test1
test1 函数内部可以适应test1()进行实行
函数有个属性 console.log(test.name)// test1
4. 函数的组成部分
function 函数名 参数(可选) 返回值(可选) return
var a = Number(window.prompt(“a”));
var b = Number(window.prompt(“b”));
占位符 -> 形参
function test(a,b,c){
console.log(a ,b,c)
}
//形参和实参数量可不等
//实际参数 -> 实参 参数没有数据类型
test(1,2);
function test(a, b){
console.log(test.length);// 获取形参的长度
console.log(arguments.length) // 获取实际参数的长度
}
test(1, 2, 3)
5. 函数内部有个arguments储存实参 一个函数被调用时,累加他的实参 循环在arguments中储存的实参
function sum(){
var a = 0;
for (var i = 0; i < arguments.length; i++){
a += arguments[i];
}
console.log(a);
}
sum(1,2,3,4,5,6);
在函数内部是可以改变实参
当我们在实参中传了值的可以在函数中进行修改,如果说没有在实参中传递 是undefined,是不能进行
传递的
实参和形参不是同一个变量,但是存在映射关系,当形参进行改变的时候,实参也会跟着改变,但如果
没有实参,就没有映射关系
function test(a,b){
a = 3;
console.log(arguments[0]);
}
test(1,2)
6. return 每个函数最后一定是return,如果没写,js会隐式的加上 ,return之后的语句是不会执行的
1. 终止函数的执行
2. 返回一个东西
3. 没有写return 默认返回undefined
7. 函数就是一个功能段或者程序段,被封装的过程
实现一个固定的功能或者程序,在这个封装体中需要一个入口和一个出口,入口就是参数,出口就是 返
回
# 参数默认值、递归、预编译、暗示全局变量
(1)参数默认值
初始化函数 默认值:undefined
function test(a, b){
console.log(a);
console.log(b);
}
test(1);
设置参数默认值
1. 方法1 不兼容低版本浏览器
function test(a = 1, b ){
console.log(a);
console.log(b);
}
test(undefined,2);
2. 方法2
function test(a, b){
var a = arguments[0] || 1;
var b = arguments[1] || 2;
console.log(a + b)
}
test(0, 6)
3. 方法3
function test(){
var a ,b;
if(typeof (arguments[0]) !== “undefined”){
a = arguments[0];
}else {
a = 1
}
}
(2)递归
递归, 函数自己调用自己 慎用
1. 找到一个规律 n! = nf(n-1)
2. 找到一个出口
var num = parseInt(window.prompt(‘请输入一个整数’))
function fatch(n){
if (n === 1){
return 1;// 出口 结束递归
}
return n fatch(n-1);//规律
}
(3)预编译
1. 预编译过程
1.通篇的检查语法错误
1.5 预编译的过程
2.解释一行执行一行
test();
function test(){
console.log(1);
}
console.log(a);
var a;
// 函数声明整体提升,变量只有声明是提升的,赋值是不提升的
console.log(a)
function a(a){
var a = 10;
var a =function(){
}
}
var a = 1;
2. 函数执行之前进行的步骤
1. 创建 AO对象 -> AO activation object 活跃对象, 函数上下文
2. 寻找函数中的形参和变量声明
3. 将实参赋值给形参
4. 寻找函数体内函数声明 赋值函数体
5. 执行
function test(a,b){
console.log(a); // 1
c = 0;
var c;
a = 5;
b = 6;
console.log(b);// 6
function b(){};
function d(){};
console.log(b);// 6
}
test(1,2);
// AO = {
// a:undefined
// -> 1
// ->5,
// b:undefined
// -> 2
// ->function b(){}
// -> 6,
// c:undefined
// -> 0 ,
// d:function d(){},
// }
3. 全局上下文
1. 创建 GO对象 -> 全局上下文 ===window
2. 寻找变量声明
3. 寻找函数声明
4. 执行
练习
var a = false + 1;//number(false) = 0+1
console.log(a);//1
var b = false == 1;
console.log(b);//false
if (typeof(a) && (-true) + (+undefined) + “”){
console.log(‘通过了’)
}else{
console.log(“没通过”)
}
// // typeof(a) ->”undefined” -> true
// // (-true) + (+undefined) + “” =>-1+NaN+””->”NaN”->true
if(1 + 5 “3” === 16){
console.log(“通过了”);
}else{
console.log(“没通过”)
}
console.log(1 + 5 “3”)//16
console.log(!!’ ‘ + !!’’ - !!false ||’为通过’)//1
window.a || (window.a = “1”);
console.log(window.a);//‘1’
(4)暗示全局变量
1. 暗示全局变量的问题 imply global variable
2. 在全局上的时候 无论是var a = 1;或者a = 1都是放在window对象上的
# 作用域、作用域链、预编译、闭包基础
为什么了解AO GO:为了解决作用域、作用域链相关所产生的一切问题 AO -> function 相当于独立的仓
库 互相不影响
(1)作用域
1. 对象
函数也是一种对象类型、引用类型、引用值
function test(a, b){
}
可以访问的属性 test.length test.name test.protoytpe
对象 -> 有些属性使我们无法访问的
Js引擎内部固有的隐式属性
2. [[scope]] 域
1. 函数创建时,生成的的一个JS内部的隐式属性,只能JS引擎读取
2. 函数用来存储作用域链的容器,作用域链(AO、GO)
AO:函数的执行期上下文
GO:全局的执行期上下文
函数执行完成后,AO是被销毁的,
如果再次执行这个函数的时候会重新生成一个全新的AO,
AO 是一个即时的存储容器
(2)作用域链
function a(){
function b(){
var b = 2;
}
var a = 1;
b();
}
var c = 3;
a();
页面打开的时候全局已经在执行,在执行的前一刻会生成GO -> 函数声明已经定义 全局执行的时候函数表达式
才赋值
1. 当函数 a 被定义的时候,
系统生成一个[[scope]]属性,[[scope]]中保存该函数的作用域链
在作用域链的第0位保存当前环境下的全局执行上下文GO
GO 中保存全局下的所有对象,其中包含函数a 和全局变量c = 3
2. 当函数 a 函数被执行时(前一刻,预编译的时候)
系统生成一个[[scope]]属性,保存该函数的作用域链
作用域链的顶端(第0位)保存a 函数生成的函数执行期上下文 AO
GO 被保存到 作用域链的第1位
查找变量是从a 函数的作用域从顶端往下依次查找
3. a 在执行的同时函数 b 函数被定义时,
在a函数环境下,b 函数在定义的时候和a 函数被执行的时候作用域链是相同的
4. 当函数 b 函数被执行时(前一刻,预编译的时候)
系统生成一个[[scope]]属性,保存该函数的作用域链
第 0 位保存自身的AO,a 函数的AO和全局的Go依次向下排列
5. 当函数 b 函数执行结束的时候
b 函数的AO 被销毁,回归b 被函数定义的时候的[[scope]]
6. 当函数a 执行结束的时候
函数a 的 AO 被销毁 同时 b 函数的[[scope]]也销毁了
a 函数 回归 a函数 被定义的时候
function a(){
function b(){
function c(){
}
c();
}
b();
console.log(b)
}
a();
// 1. a 定义:a.[[scope]] -> 0 : GO
// 2. a 执行:a.[[scope]] -> 0 : a.ao 1 : Go
// 3. b 定义:b.[[scope]] -> 0 : a.ao 1 : Go
// 4. b 执行:b.[[scope]] -> 0 : b.ao 1 : a.ao 2 : Go
// 5. c 定义:c.[[scope]] -> 0 : b.ao 1 : a.ao 2 : Go
// 6. c 执行:c.[[scope]] -> 0 : c.ao 1 : b.ao 2 : a.ao 3. Go
// 7. c 销毁:c.[[scope]] -> 0 : b.ao 1 : a.ao 2 : Go
// 7. b 销毁:b.[[scope]] -> 0 : a.ao 1 : Go
// 7. a 销毁:a.[[scope]] -> 0 : GO
(3)闭包基础
function test1(){
var c = 3;
function test2(){
var b = 2;
console.log(a);
}
var a = 1;
return test2;
}
var c = 3;
var test3 = test1();
test3();
1. 闭包
当内部函数被返回到外部并保存时,一定会产生闭包
闭包会产生原来的作用域链的不释放
过度的闭包可能会导致内存的泄露,或者加载太慢
#立即执行函数、闭包深入、逗号运算符
普通的函数在全局定义之后是存在GO中的,是不释放的,在想调用的时候就能调用 有些函数只需要运
行一次之后再也不会执行 -> 立即执行函数
(1)立即执行函数 (初始化函数)
IIFE -> immediately-invoked function expression
自动执行
执行完自己销毁
1. 立即执行函数的写法
(function(){})();
(function(){}());//W3C建议
(function test(){
var a = 1,
b = 2;
console.log()
})();
test();// 报错
// 证明函数执行完就销毁了
2. 立即执行函数可以进行传参
(function(形参){语句}(实参))
3. 立即执行函数可以返回值,声明一个变量来保存返回的值
var num = (function(a, b){
return a + b;
}(2, 4));
console.log(num);// 6
4. 一定是表达式才能用执行符号()执行 括号包起来的都能变成表达式
var test1 = function(){
console.log(2);
}
console.log(test1)
// 输出
// 2 -> 函数test1 运行
// underfind -> test1 运行后销毁 所以是 undefined
当函数声明使用括号转换成表达式的时候,自动忽略函数名
(function test(){
console.log(‘123’)
})()//123
(function(){
console.log(‘123’)
})()//123
函数声明变成表达式的方法 + - ! || && 立即执行函数的函数名自动被忽略
+ function test(){
console.log(2);
}();
! function test(){
console.log(2);
}();
~ function test(){
console.log(2);
}();
0 || function test(){
console.log(2);
}();
(2)逗号运算符
逗号运算符 返回所有逗号最后的一个值
var num = (2 - 1, 6 + 5, 24 + 1);
console.log(num);// 25
