目录
一、function:
function:函数,也称之为方法。也是一个对象。需要提前定义好的,以后就可以反复使用。
二、何时使用:
1.不希望打开页面立刻执行,需要时再使用或者用户来触发(绑定事件)
4.函数的地位非常高,函数是第一等公民,随时随地考虑能不能封装为一个函数,尤其是重复的代码
三、创建函数并且调用:3种
function 函数名(形参列表){
函数体;
return 返回值;
}
var 函数名=function(形参列表){
函数体;
return 返回值;
}
var 函数名=new Function("形参1",....,"函数体;return 返回值;");
四、箭头函数 —— ES6
var fn=()=>{
console.log("你好");
console.log("不好");
}
(1)只有一句话时,大括号可以省略
var fn=()=> console.log("你好");
(2)只有一个参数时,可以省略()
var fn=a=> console.log("a=",a);
fn(123)
function addSum() {
let a = 10;
let b = 20;
console.log(a + b);
}
addSum()
所以,若函数完成功能需要调用者传入数据,那么就需要用有参数的函数,可以大大提高函数的灵活性。
五、匿名函数:创建的函数,没有函数名引用着
(1)匿名函数自调:只会执行一次,执行完毕后会自动释放,代替全局写法,节约内存空间
(function(){
console.log("我是匿名自调");
})();
(2)匿名函数回调:将函数调用时,传入的实参,又是一个匿名函数,不需要我们程序员调用,会由主函数自动执行
arr.sort(function(a,b){return a-b;})
<button id="btn">按钮</button>
<script>
btn.onclick = function() {
alert(1) //1 不用调用,自动执行
}
</script>
六、使用对象作为参数
function fn(a){
// console.log("a =", a)
// console.log(a.name)
a.name = "猪八戒" // 修改对象时,如果有其他变量指向该对象则所有指向该对象的变量都会受到影响
console.log(a)//"猪八戒"
}
// 对象可以作为参数传递
let obj = {name:"孙悟空"}
// 传递实参时,传递并不是变量本身,而是变量中存储的值
fn(obj)
console.log(obj)//"猪八戒"
function fn(a){
// console.log("a =", a)
// console.log(a.name)
a = {} // 修改变量时,只会影响当前的变量
a.name = "猪八戒" // 修改对象时,如果有其他变量指向该对象则所有指向该对象的变量都会受到影响
console.log(a)//"猪八戒"
}
// 对象可以作为参数传递
let obj = {name:"孙悟空"}
// 传递实参时,传递并不是变量本身,而是变量中存储的值
// fn(obj)
console.log(obj)//"孙悟空"
// 函数每次调用,都会重新创建默认值
function fn2(a = {name:"沙和尚"}){
console.log("a =", a)
a.name = "唐僧"
console.log("a =", a)
}
fn2() // 沙和尚 唐僧
fn2() // 沙和尚 唐僧
let obj2 = {name:"沙和尚"}
// 函数每次调用,都会重新创建默认值
function fn2(a = obj2){
console.log("a =", a)
a.name = "唐僧"
console.log("a =", a)
}
fn2() // 沙和尚 唐僧
fn2() //唐僧 唐僧
七、函数返回值:return
function fn() {
return 20
}
fn()
//return 相当于执行了 fn()=20。返回的是函数值
只不过如果return后面跟着一个数据,会顺便将其返回到全局作用域中,但是只负责返回不负责保存!
所以在调用函数时:如果有return,记得拿一个变量接住结果
function getSum() {
for (var i = 1, sum = 0; i <= 100; i++) {
sum += i;
}
return sum
}
var result = getSum();
console.log(result);//5050
八、作用域:2种
所有直接编写到script标签中的代码都位于全局作用域中。
函数每次调用都会产生一个全新的函数作用域。
在函数中定义的变量是局部变量,只能在函数内部访问,外部无法访问。
function fn() {
let a = 10;
console.log(a);
}
fn()
console.log(a);
var a = 1;
function fn1() {
var a = 2;
var b = '22';
fn2();
function fn2() {
var a = 3;
fn3();
function fn3() {
var a = 4;
console.log(a); //4
console.log(b); //22
}
}
}
fn1()
function fn() {
let num = 10;
console.log(num);//10
function fn1() {
console.log(num);//10
let num2 = 20;
}
fn1();
console.log(num2); //num2 is not undefined
}
fn();
console.log(num); //num is nor undefined(前面报错了,这不不会被执行了)
带来了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就会报错了
特殊:(1)尽量不要全局污染:在函数中创建变量的使用记得一定要叫var。
在局部作用域中,如果没有使用var或者let声明变量,则变量会称为window对象的属性,也就是全局变量。
function fn() {
num = 10; —— 此时是全局变量 不推荐
}
fn();
console.log(num); //10
(2)本身是函数的东西,全局用不到,但是配合return其实也可以
九、window对象
(1)在浏览器中,浏览器为我们提供了一个window对象,可以直接访问
(2)window对象代表的是浏览器窗口,通过该对象可以对浏览器窗口进行各种操作
除此之外window对象还负责存储JS中的内置对象和浏览器的宿主对象
(3)window对象的属性可以通过window对象访问,也可以直接访问
(4) 函数可以认为是window对象的方法
window.alert(123);= window.alert(123);
(5)var用来声明变量,作用和let相同,但是var不具有块作用域
在全局中使用var声明的变量,都会作为window对象的属性保存
var b=20//window.b=20
console.log(window.b)
使用function声明的函数,都会作为window的方法保存
function fn(){
alert('我是fn')
}
window.fn()
使用let声明的变量不会存储在window中,而是存在一个秘密的小地方(无法访问)
let b=20//window.b=20
console.log(window.b)//报错
十、声明提前
预解析:JavaScript代码是由浏览器中的JavaScript解析器来执行的。JavaScript解析器在运行JavaScript代码时分为两部分:预解析和代码执行。
预解析js引擎会把js里面所有的var和function提升到当前作用域的最前面,然后才是代码执行 —— 从上往下
变量提升:把所有的变量声明提升到当前作用域的最前面 ,不提升赋值操作。
函数提升:把所有的函数声明提升到当前作用域的最前面,不调用函数。
console.log(num); //undefined
var num = 10;
相当于:
var num;
console.log(num);
num = 10
fun();
var fun = function() {
console.log(22); //爆错
}
相当于:
var fun;
fun();//调用要写在 函数表达式很后面才可以
fun = function() {
console.log(22);
}
fn()
function fn() {
console.log(2);
}
相当于:
function fn() {
console.log(2);
}
fn();
var a,b;
(function(){
alert(a);
alert(b);
var a=b=3;
alert(a);
alert(b);
})();
alert(a);
alert(b);
相当于:
// 经过预编译原来的代码可以理解为下面的代码
var a, b; // 全局作用域下 var 定义的变量将成为 window 的对象 windows: {a: undefined, b: undefined, ...}
(function () {
var a // 这个局部变量 a 访问优先级比 外面的 a 更高
alert(a); // 局部变量 a: undefined
alert(b); // window.b: undefined
a = b = 3; // 局部变量 a: 3, window.b: 3
alert(a); // 局部变量 a: 3
alert(b); // window.b : 3
})();
alert(a); // window.a: undefined
alert(b); // window.b: 3
十一、按值传递
十二、重载(overload):
相同的函数名,根据传入的实参的不同,会自动选择对应的函数执行
问题:JS的语法不支持重载。JS不允许存在 多个同名函数,最后一个函数会覆盖之前所有的
function zwjs(name) {
return "我的名字叫" + name;
}
function zwjs(name, age) {
return "我叫" + name + ",今年" + age + "岁";
}
function zwjs(name, age, hobby) {
return name + ",今年" + age + "岁,喜欢" + hobby;
}
console.log(zwjs("袍哥")); //做第三个函数。袍哥,今年undefined岁,喜欢undefined。
什么是arguments对象:函数中,自带的,不需要我们创建的,是一个【类数组】对象,作用:接收住所有实参
强调:类数组对象不是数组,所有的数组的API,类数组都不能使用
变相实现重载:在函数内部判断传入的实参(个数、类型)的不同,执行不同的分支操作
function zwjs(){
if(arguments.length==1){
return "我的名字叫"+arguments[0];
}else if(arguments.length==2){
return "我叫"+arguments[0]+",今年"+arguments[1]+"岁";
}else if(arguments.length==3){
return arguments[0]+",今年"+arguments[1]+"岁,喜欢"+arguments[2];
}
}
console.log(zwjs("袍哥"));
console.log(zwjs("袍哥",128));
console.log(zwjs("袍哥",128,"打游戏"));
十三、闭包:
不会被污染,只有函数调用时内部可用。缺点:调用结束后,就释放了,一次性的,不可以反复使用
十二、函数的执行原理 5步
创建一个执行环境栈(ESC):保存函数调用顺序的数组。栈:一端开启,一端封闭
在EC中添加了scope chain(作用域链)属性引用着AO
变量的使用规则:优先使用局部变量,局部没有找全局,全局没有就报错
作用域链(scope chain):以函数的EC中的scope chain属性为起点,经过AO,逐级引用,形成的一条链式结构