JavaScript基础语法4

续JavaScript基础语法3

五丶JavaScript函数

为什么要有函数?

如果要在多个地方求1-100之间所有数的和,应该怎么做?

5.1 函数的定义

5.1.1 函数的概念

函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。通俗来讲:把一段相对独立的具有 特定功能的代码块封装起来,形成一个独立实体,就是函数,起个名字(函数名)。

函数的作用就是封装一段代码,将来可以重复使用。

函数就是包裹在花括号中的代码块:

5.1.2 函数语法

  • 表达式法:
var fn = function(){

}
  • 函数声明:
function 函数名(参数列表){
	// 函数体
}

两种方法的区别:

声明的方式定义的,调用可以写在函数定义之前;

表达式的方式定义的,调用必须写在函数定义之后;

5.2 JavaScript声明式函数的应用

函数的应用分为两步,一是先声明一个函数,再调用该函数。

声明函数:

  1. 声明无参函数语法
  2. 声明有参函数的语法
  3. 声明带有返回值的函数

5.2.1 函数的调用

  • 调用函数的语法:
函数名();
  • 特点:
    • 函数体只有在调用的时候才会执行,调用需要()进行调用。
    • 可以调用多次(重复使用)

在JavaScript中,调用函数时,如果没有返回值,就直接用函数方法名()调用。如果有参数,则必须给每 个参数赋值,函数方法名(参数值),如果还有返回值,可以用一个变量来存储这个值。

代码示例:

// 声明无参函数:无参函数就是在函数名的小括号中不定义任何参数。
function sayHello() {
	console.log("吃了没?");
}
// 调用无参函数
sayHello();
// 求1-100之间所有数的和
function getSum() {
	var sum = 0;
	for (var i = 0; i < 100; i++) {
		sum += i;
	}
	console.log(sum);
}
// 调用
getSum();

5.2.2 函数的参数

5.2.2.1 为什么要有参数
function getSum() {
	var sum = 0;
	for (var i = 1; i <= 100; i++) {
		sum += i;
	}
	console.log();
}

虽然上面代码可以重复调用,但是只能计算1-100之间的值。

如果想要计算n-m之间所有数的和,应该怎么办呢?

5.2.2.2 语法

函数内部是一个封闭的环境,可以通过参数的方式,把外部的值传递给函数内部。

带参数的函数声明语法:

function 函数名(var1, var2...) {
	// 函数体
}

上面的var1,var2就是参数,它代表一个不确定的值,这个值要参与函数代码块的运算,在调用函数时, 可以给这些参数赋值。也可以在函数中定义多个参数,每个参数之间逗号 (,) 分隔。

当声明函数时,参数相当于作为变量来声明。

变量和参数必须以一致的顺序出现。第一个变量就是第一个被传递的参数的给定的值,以此类推。

带参数的函数调用:

函数名(实参1, 实参2, 实参3);
形参1 = 实参1
形参2 = 实参2
5.2.2.3 形参和实参
  • 形式参数:在声明一个函数的时候,为了函数的功能更加灵活,有些值是固定不了的,对于这些固 定不了的值。我们可以给函数设置参数。这个参数没有具体的值,仅仅起到一个占位置的作用,我 们通常称之为形式参数,也叫形参。
  • 实际参数:如果函数在声明时,设置了形参,那么在函数调用的时候就需要传入对应的参数,我们 把传入的参数叫做实际参数,也叫实参。

需要注意的是,同一个函数,形参和实参是一一对应的。

如何区分实参和形参?

  1. 出现的地方不一样,一个是在函数的声明中,一个出现在函数的调用中。
  2. 代表的意义不一样,一个是声明一个变量,一个是该变量的值。
// 定义变量x和y
var x = 5, y = 6;
// 调用fn函数,把x和y传递到函数里面
fn(x,y);
function fn(a, b) {
	console.log(a + b);
}
// x,y实参,有具体的值。函数执行的时候会把x,y复制一份给函数内部的a和b,函数内部的值是复制的新
值,无法修改外部的x,y

代码示例:

/ - 圆的面积 = pi * r * r;
function getArea(r) {
	var pi = 3.1415926;
	console.log(pi * r * r);
}
getArea(7);


// - 求2个数中的最大值
function getMax(a, b) {
	if (a > b) {
		console.log(a);
	} else {
		console.log(b);
	}
}
var x = 100;
var y = 1000;
getMax(x, y);


// - 求3个数中的最大值
function getMax(a, b, c) {
	if (a > b && a > c) {
		console.log(a);
	} else if (b > a && b > c) {
		console.log(b);
	} else if (c > a && c > b) {
		console.log(c);
	}
}
getMax(11111, 100, 1000);
// 求n个数的最大值?
function getMax(arr) {
	// 参数arr 是数组
	var max = arr[0];
	for (var i = 1; i < arr.length; i++) {
	// 判断max和数组中之后的每一个元素进行比较
		if (max < arr[i]) {
			max = arr[i];
		}
	}
	console.log(max);
}
var array = [12, 2, 45, 1, 10];
getMax(array);


// - 判断一个数是否是素数(又叫质数,只能被1和自身整数的数)
function jdugePrimeNumber(number) {
	// 假设number是质数
	var isPrime = true;
	for (var i = 2; i < number; i++) {
	// 判断是否有能被number整数的数
		if (number % i === 0) {
		// 如果此处执行了。说明不是质数
			isPrime = false;
			break;
		}
	}
	if (isPrime) {
        console.log('质数');
	} else {
		console.log('不是质数');
	}
}
jdugePrimeNumber(13);

5.2.3 函数的返回值

当函数执行完的时候,并不是所有时候都要把结果打印。我们期望函数给我一些反馈(比如计算的结果 返回进行后续的运算),这个时候可以让函数返回一些东西,也就是返回值。函数通过return返回一个 返回值。

语法如下:

//声明一个带返回值的函数
function 函数名(形参1, 形参2, 形参3...) {
	//函数体
	return 返回值;
}


//可以通过变量来接收这个返回值
var 变量 = 函数名(实参1, 实参2, 实参3...);

函数的调用结果就是返回值,因此我们可以直接对函数调用结果进行操作。

示范:利用函数计算两个数相乘后的值,并返回。

//1、声明一个带参数的方法
function myFunction(a,b) {
	return a*b;
}


//2、调用带参的方法
var mul=myFunction(5,6);

返回值详解:

  • 如果函数没有显式的使用 return语句 ,那么函数有默认的返回值:undefined。
  • 如果函数使用 return语句,那么跟在return后面的值,就成了函数的返回值。
  • 如果函数使用 return语句,但是return后面没有任何值,那么函数的返回值也是:undefined。
  • 函数使用return语句后,这个函数会在执行完 return 语句之后停止并立即退出,也就是说return后面的所有其他代码都不会再执行。
  • 推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。

5.2.4 函数是一种数据类型

function fn() {}
console.log(typeof fn);
  • 函数作为参数:因为函数也是一种类型,可以把函数作为另一个函数的参数,在另一个函数中调用
  • 函数做为返回值:因为函数是一种类型,所以可以把函数可以作为返回值从函数内部返回。
function fn(b) {
	var a = 10;
	return function () {
		alert(a+b);
	}
}
fn(15)();

5.3 JavaScript arguments对象

JavaScript中,arguments对象是比较特别的一个对象,实际上是当前函数的一个内置属性。也就是说所 有函数都内置了一个arguments对象,arguments对象中存储了传递的所有的实参。arguments是一个 伪数组,因此就可以进行遍历。

示例代码:

// 求任意个数的最大值
function getMax() {
	var max = arguments[0];
	for (var i = 1; i < arguments.length; i++) {
		if (max < arguments[i]) {
			max = arguments[i];
		}
	}
	return max;
}


var max = getMax(5, 10, 1, 5, 100);
console.log(max);

5.4 JavaScript函数作用域

变量从作用域的角度划分,分为两种:

  • 局部变量
  • 全局变量

什么是作用域?

  • 变量可以起作用的范围

5.4.1 局部变量

在JavaScript函数内部声明的变量是局部变量,所以只能在函数内部访问它,该变量的作用域是局部的。

可以在不同的函数中使用名称相同的局部变量,因为只有声明过该变量的函数才能识别出该变量。只要 函数运行完毕,局部变量就会被删除。

function sayHello(){
	//该变量声明在一个函数内部,name就是一个局部变量,
	//局部变量只可以在本函数内调用
	var name="H5";
	alert("Hello "+name);
}

5.4.2 全局变量

在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。

//声明一个全局变量,任何函数都可以使用它
var name="H5";


function sayHello(){
	alert("Hello "+name);
}

//调用函数
sayHello();

需要注意的是,如果没有使用var声明变量该变量将被自动作为全局变量声明,不推荐使用。

5.4.3 变量的生命周期

JavaScript 变量的生命期从它们被声明的时间开始。

局部变量会在退出作用域之后会销毁。

全局变量会在关闭网页或浏览器才会销毁。

5.4.4 局部变量和全局变量的区别

  1. 声明位置不同:局部变量声明在函数内部。全局变量声明在函数外部。
  2. 作用域不一样:局部变量只在某一个局部范围有效,比如函数内部。全局变量在整个页面有效,网 页上的所有脚本和函数都能访问它。
  3. 生命周期不一样:局部变量会在函数运行以后被删除,全局变量会在页面关闭后被删除。

5.4.5 块级作用域

任何一对花括号({和})中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见 的,我们称之为块级作用域。

在es5之前没有块级作用域的的概念,只有函数作用域,现阶段可以认为JavaScript没有块级作用域。

5.5 匿名函数

匿名函数: 有关键词 function, 有小括号,有大括号,就是没有函数名。

function(a,b){
	console.info( a+b );
}

想要执行它,怎么执行?没有名字,怎么调用?

方式一:把它放进一个变量里,这个变量就相当于一个函数名了。没有名字的匿名函数,变成有“名”函数 了,我们把这种方式称之为函数字面量

var myFun = function( a,b ){
	console.info( a+b);
};


myFun( 10,30 );

**方式二:**干脆不要名字,直接执行~!-- 这么做可以在内部形成局部变量和局部函数,防止全局污染。 个人常用的直接执行匿名函数的方式!

(匿名函数)();

(匿名函数)();

//注意: 使用改写法一定要注意添加分号
(function(a,b){
	console.info( a+b );
})(10,30);


(function(a,b){
	console.info( a+b );
}(10,30));

其他直接调用的方式显得比较怪异了。

// 在function前面加一元操作符号
!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();



// 在function前面添加 new 关键词
new function () { /* code */ }
new function () { /* code */ } () // 如果需要传递参数,只需要加上括弧()

**方式三:**利用事件去调用。

var btn = document.getElementById("btn"); // 找到页面某个标签


// 添加事件
btn.onclick = function(){
	console.info("你点了我!");
}

**方法四:**作为对象的方法调用

var myObj = {
	name : "John",
	sayHello:function(){
		console.info("Hello,"+ this.name );
	}
};

myObj.sayHello();

**方法五:**作为另一个函数的参数。

**函数也可以作为另一个函数的参数的。**当然有名函数也可以做参数。

function myFun(fn){
	fn();
}

myFun(function(){
	console.info("这个匿名函数是个参数");
});

5.6 构造函数

通过 new 函数名() 来实例化对象的函数叫构造函数。任何的函数都可以作为构造函数存在。之所以有构 造函数与普通函数之分,主要从功能上进行区别的,构造函数的主要功能为 初始化对象,特点是和new 一起使用。new就是在创建对象,从无到有,构造函数就是在为初始化的对象添加属性和方法。构造函 数定义时首字母大写(规范)。

对new理解:new 申请内存, 创建对象,当调用new时,后台会隐式执行new Object()创建对象。所以,通 过new创建的字符串、数字是引用类型,而是非值类型。

  1. 常用的构造函数:

    • 1. var arr = [];var arr = new Array(); 的语法糖。
      2. var obj = {}var obj = new Object(); 的语法糖
      3. var date = new Date();
      4. ...
      
  2. 自定义构造函数:

    • // 1. 构造函数名首字母要大写
      // 2. 构造函数的作用就是用来创建对象的,
      // 3. 功能上: 普通函数是用来执行某个行为;构造函数是用来创建对象的
      // 4. 语法上: 基本没有差别
      // 5. 从函数体: 普通函数的函数体里面就是要执行的逻辑代码; 构造函数的函数体里面是用来初始化对象成
      员以及对象方法的;
      function Person(id,name,age) {
      	//this关键字: 表示的当前对象
      	this.id = id; //对象的属性
      	this.name = name;
      	this.age = age;
      	this.eat = function () { //对象方法
      		alert(this.name+"的吃饭行为");
      	}
      }
      
      
      //直接通过函数名() 调用的是普通函数
      
      
      
      //使用构造函数,必须结合new来使用
      //Person()就算是构造函数,它也属于函数的一种
      var p1 = new Person(1001,"张三",12); //创建一个Person对象
      var p2 = new Person(1002,"李四",12);
      document.write("p1的name是:"+p1.name+"<br>");
      
      p1.eat()
      

5.7 回调函数

字面上的理解,回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完 之后,再执行传进去的这个函数。这个过程就叫做回调。

function modifyArray(arr, callback) {
	// 对 arr 做一些操作
	arr.push(100);
	// 执行传进来的 callback 函数
	callback();
}

var arr = [1, 2, 3, 4, 5];
modifyArray(arr, function() {
	console.log("array has been modified", arr);
});

上面的代码中,我们先定义了主函数和回调函数,然后再去调用主函数,将回调函数传进去。

定义主函数的时候,我们让代码先去执行callback()回调函数,但输出结果却是后输出回调函数的内容。 这就说明了主函数不用等待回调函数执行完,可以接着执行自己的代码。所以一般回调函数都用在耗时 操作上面。比如ajax请求,比如处理文件等。

5.8 预解析

// js解析器如何工作:
        // 1、预解析:在所有代码执行之前
        // 规则:会把var 关键字声明的变量提前进行说明,但不进行辅赋值

        // 预解析做的就是第一步
        // 第一步var num
        // 第二步 num=100
        // console.log(num);
        // var num=100;
        // console.log(num);



        // 预解析的无节操
        // 不管if是否成立都会进行var n1的预解析
        // return后面的代码也会进行预解析

        // if(false){
        //     var n1=100;
        // }
        // console.log(n1);
        // function fn1(){
        //     console.log("预解析");
        //     console.log(a);
        //     return ;
        //     var a=100;
        // }
        // fn1()



        // 预解析的重名问题
        // 当预解析是变量和函数重名,函数为主。
        // fn2()
        // var fn2;
        // fn2()
        // fn2=100;
        // function fn2(){
        //     console.log("我是函数");
        // }
        // console.log(fn2);
        // fn2()
        /*
            第一步声明一个变量fn2
            第二步声明一个函数fn2覆盖掉变量
            第三步执行代码
                第一行输出我是函数
                第二行变量覆盖掉函数
                第三行报错fn2 is not a function
        
        */
        // fn2()
        // function fn2() {
        //     console.log("我是函数");
        // }
        // fn2()
        // var fn2 = 100;
        // fn2()//报错fn2 is not a function

5.8.1 预解析过程

  1. 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
  2. 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
  3. 先提升var,再提升function。
//面试题:
    <script>
        var n = 110;
        console.log(n);
        console.log(window.n);
        m = 220;
        console.log(m);
        console.log(x);
    </script>
    <script>
        var a = 1;
        var b = "hello";
        function fn() {
            console.log("fn...");
        }
        var arr = ["a", "b", "c"];
        var obj = { name: "wc", age: 100 }
    </script>
    <script>
        function fn(a) {
            console.log(a);
        }
        fn(110)
        console.log(a);
    </script>
    <script>
        var arr = [11, 22];
        function fn(arr) {
            arr[0] = 100;
            arr = [666];
            arr[0] = 0;
            console.log(arr);
        }
        fn(arr);
        console.log(arr);
    </script>
    <script>
        var a = 1;
        var b = 1;
        function gn() {
            console.log(a, b);
            var a = b = 2;
            console.log(a, b);
        }
        gn();
        console.log(a, b);
    </script>
    <script>
        var a = 1;
        var obj = { uname: "wangcai" }
        function fn() {
            var a2 = a;
            obj2 = obj;
            a2 = a;
            obj.uname = "xiaoqiang";
            console.log(a2);
            console.log(obj2);
        }
        fn();
        console.log(a);
        console.log(obj);
    </script>
    <script>
        // 同名的变量名,只会提升第1个
        var a = 1;
        var a = 2;
        var a = 3;
        console.log(a);
        // 预编译后的代码如下:
        var a;
        a = 1;
        a = 2;
        a = 3;
        console.log(a);
    </script>
    <script>
        // 提升:var a;
        // a函数整体提升 a = funciton(){};
        // 执行:a = 1;
        var a = 1;
        function a() {
            console.log("a...");
        }
        console.log(a); // 函数a
    </script>
    <script>
        var a = 10;
        // 赋值操作就是把栈区(GO,AO)中的数据,copy一份,赋值给变量
        var b = a;
        console.log(a, b); // 10 10
        b = 1; // 把1重新赋值给b所对应的内存空间
        console.log(a, b); // 10 1
    </script>
    <script>
        var a = [1, 2];
        // 把栈区的地址赋赋值给b, a和b指向同一个内存空间
        var b = a;
        console.log(a, b); // [1,2] [1,2]
        // 把一个新堆的地址重新赋值给b b指向一个新堆空间
        b = [3, 4];
        console.log(a, b); // [1,2] [3,4]
    </script>
    <script>
        var a = [1, 2];
        var b = a;
        console.log(a, b); // [1,2] [1,2]
        b[0] = 110;
        console.log(a, b); // [110, 2] [110, 2]
    </script>
    <script>
        var a = [1, 2];
        var b = [1, 2];
        // a 和 b 是地址 == 比较时比较的是地址 不同的堆,地址是不可能一样
        console.log(a == b); // false
        console.log(a === b); // false
    </script>
    <script>
        var a = 110;
        var b = 110;
        console.log(a == b); // true
    </script>
    <script>
        var a = [1, 2];
        // a 和 b中保存的地址是一样的
        var b = a;
        console.log(a == b); // true
        console.log(a === b); // true
    </script>
    <script>
        console.log(a, b); // 报错:b is not defined
        var a = b = 2;
    </script>
    <script>
        var a = { m: 666 };
        var b = a;
        b = { m: 888 };
        console.log(a.m); // {m:666}
    </script>
    <script>
        var a = { n: 12 };
        var b = a;
        b.n = 13;
        console.log(a.n); // 13
    </script>
    <script>
        console.log(a); // 报错
        a = 111;
    </script>
    <script>
        var m = 1;
        n = 2;
        console.log(window.m); // 1
        console.log(window.n); // 2
    </script>
    <script>
        function fn() {
            var a = 111;
        }
        fn();
        console.log(window.a); // 访问一个对象上不存在的属性,结果是und
    </script>
    <script>
        var a = -1;
        if (++a) { // ++a 整体是新值 0 => false
            console.log("666");
        } else {
            console.log("888");
        }
    </script>
    <script>
        console.log(a, b); // und und
        if (true) {
            var a = 1;
        } else {
            var b = 2;
        }
        console.log(a, b); // 1 und
    </script>
    <script>
        var obj = {
            name: "wc",
            age: 18
        }
        // in是一个运算符 判断一个属性是否属性某个对象
        console.log("name" in obj); // true
        console.log("score" in obj); // false
    </script>
    <script>
        var a;
        console.log(a); // und
        if ("a" in window) {
            a = 110;
        }
        console.log(a); // 110
    </script>
    <script>
        console.log(a); // und
        if ("a" in window) {
            var a = 110;
        }
        console.log(a); 110
    </script>
    <script>
        var a = 100;
        function fn() {
            console.log(a);
            return
            var a = 110;
        }
        fn();
    </script>
    <script>
        var n = 100;
        function foo() {
            n = 200;
        }
        foo()
        console.log(n);
    </script>
    <script>
        function fn() {
            var a = b = 100;
        }
        fn();
        console.log(a);
        console.log(b);
    </script>
    <script>
        var n = 100;
        // 找一个函数的父的EC,看的是函数的定义处,不是调用处
        function fn() {
            console.log(n);
        }
        function gn() {
            var n = 200;
            console.log(n);
            fn()
        }
        gn()
        console.log(n);
    </script>

5.8.2 变量提升(hoisting)

ES5 提升有变量提升和函数提升。

原则:

  1. 所有声明都会被提升到作用域的最顶上;
  2. 同一个变量声明只进行一次,并且因此其他声明都会被忽略;
  3. 函数声明的优先级优于变量声明,且函数声明会连带定义一起被提升。

变量提升:

把变量声明提升到函数的顶部,但是变量赋值不会提升。

console.log(a);
var a = 10;
//输出为undefined


//与上例等价
var a;
console.log(a);
a = 10;

注意:变量未声明,直接使用,输出‘变量 is not defined。

函数提升:

函数提升会将函数声明连带定义一起提升。

在JavaScript中函数的创建方式有三种:函数声明、函数表达式(函数字面量)、函数构造法(动态的, 匿名的)。

只有函数声明创建的函数会执行函数提升,字面量定义的函数(实质为变量+匿名函数)会执行变量提 升。

test1();
function test1(){
	console.log("可以被提升");
}
test2();
var test2 = function(){
	console.log("不可以被提升");
}
console.log(test2);
var test2 = function(){
	console.log("不可以被提升");
}

函数和变量同时提升:

console.log(test3);
function test3(){console.log('func');}
var test3 = 'Mary';
//面试题:
    <script>
        // --------- 原题
        console.log(a);
        var a = 110;
        console.log(a);
        fn();
        function fn() {
            console.log("我是一个fn函数~");
        }
    </script>
    <script>
        // --------- 分析
        // 下面的代码中有两个声明 加var的变量a function声明的函数 fn
        // 两者都要提升 变量仅仅提升声明 function提升的整体
        console.log(a); // und
        var a = 110;
        console.log(a); // 110
        fn(); // 也可以执行
        function fn() {
            console.log("我是一个fn函数~");
        }
    </script>
    <script>
        // --------- 原题
        g();
        var g = function () {
            console.log("g函数执行了....");
        };
    </script>
    <script>
        // --------- 分析
        // g是一个变量 只不这个变量的值是一个函数 函数是一种数据类型
        // 进行预编译时,仅仅是提升了var g;
        // var g; g的值是und und(); 报错了
        g(); // TypeError: g is not a function 只有函数才可以加()调用
        var g = function () {
            console.log("g函数执行了....");
        }
    </script>
    <script>
        // --------- 原题
        console.log(i);
        for (var i = 0; i < 10; i++) { }
        console.log(i);
    </script>
    <script>
        // --------- 分析
        // i是全局变量 只有定义在函数内部的变量才是局部变量
        // var i会提升,所以前面输出的i是und
        console.log(i); // und
        for (var i = 0; i < 10; i++) { } // for循环对i进行了赋值
        console.log(i); // 10
    </script>
    <script>
        // --------- 原题
        var a = 666;
        fn()
        function fn() {
            var b = 777;
            console.log(a);
            console.log(b);
            console.log(c);
            var a = 888;
            var c = 999;
        }
    </script>
    <script>
        // --------- 分析
        // 提升:
        // 全局的:var a; fn整体; 提升到代码段最前面
        // fn内部中的var b; var a; var c;都提升; 提升到函数体的最前面
        //
        var a = 666;
        fn()
        // fn产生一个局部作用域,它的父级作用域是全局作用域
        function fn() {
            // var b; var a; var c;都提升了
            var b = 777;
            // 找a 自己有 使用自己的 如果自己没有 使用父级作用域的数据
            console.log(a); // und 自己函数体内如果有数据,就使用自己的数据
            console.log(b); // 777
            console.log(c); // und
            var a = 888;
            var c = 999;
        }
    </script>
    <script>
        // --------- 原题
        console.log(value);
        var value = 123;
        function value() {
            console.log("我是value函数...");
        }
        console.log(value);
    </script>
    <script>
        // --------- 分析
        // 预编译:
        // 提升:
        // var value;会提升 value的值是und
        // value函数整体也会提升
        // 如果变量名和函数名一样,变量提升了,函数也提升了,提升后只会存在一个名字
        // 问题是value的值是函数,也就意味着,变量的value就被覆盖了
        console.log(value); // value是函数
        var value = 123; // 123赋值给了value,value又变成了123
        function value() {
            console.log("我是value函数...");
        }
        console.log(value); // 123
// 提升的同名变量名和函数名,函数会覆盖变量,函数在JS中是一等公民,优先级高
    </script>
    <script>
        // --------- 原题
        console.log(a);
        a = 666;
        console.log(a);
    </script>
    <script>
        // --------- 分析
        // 没有加var的变量不会提升
        //
        console.log(a); // a is not defined / und
        a = 666;
        console.log(a); // 在一个代码段中,上面的代码出错了,下面的代码不会执行了
    </script>
    <script>
        // --------- 原题
        function fn() {
            console.log(a);
            a = 666;
            console.log(a);
        }
        fn();
        console.log(a);
    </script>
    <script>
        // --------- 分析
        // 提升:fn整体
        //
        function fn() {
            console.log(a); // 报错 找a 没a a is not defined
            a = 666;
            console.log(a); // 不执行
        }
        fn();
        console.log(a); // 不执行
    </script>
    <script>
        // --------- 原题
        function fn() {
            a = 110;
        }
        console.log(a);
    </script>
    <script>
        // --------- 分析
        // 函数没有调用,相当于函数没有写,没有执行
        // 函数体中定义的所有的数据,都不会执行
        function fn() {
            a = 110; // 没有加var的变量是全局变量
        }
        // fn(); // 如果调用了,结果是110
        console.log(a);
    </script>
    <script>
        // --------- 原题
        gn()
        function gn() {
            var k = 123;
            console.log(k);
        }
        console.log(k);
    </script>
    <script>
        // --------- 分析
        // gn整体要提升
        gn()
        function gn() {
            var k = 123; // var k要提升到函数体最前面
            console.log(k); // 123
        }
        console.log(k); // 报错
    </script>

5.9 防止全局污染

5.9.1 全局污染问题

JavaScript 可以随意定义保存所有应用资源的全局变量。

但全局变量可以削弱程序灵活性,增大了模块之间的耦合性。在多人协作时,如果定义过多的全局变量 有可能造成全局变量冲突,也就是全局变量污染问题

5.9.2 解决全局污染

        // 方式1: 定义全局变量命名空间,只创建一个全局变量,并定义该变量为当前应用容器,把其他全局变量追加在该命名空间下。
        //my就是一个全局变量,我们可以把my这个全局变量当成一个命名空间,然后把其他的所有全局变量都放在它下面;
        var my = {}; //唯一的全局变量
        my.name = {
            big_name: "zhangsan",
            small_name: "lisi"
        };
        my.work = {
            school_work: "study",
            family_work: "we are"
        };
        // alert(my.name.small_name);

        
        // 方式2: 利用匿名函数将脚本包裹起来
        (function () {
            var temp = {};
            //把两个变量赋值给temp
            //temp.school_work = "study";
            //temp.small_name = "李四";
            small_name = "李四";
            temp.getName = function () {
                return small_name;
            }
            //把tmep赋值给全局变量test
            window.test = temp;
        }())
        // alert(test.getName());

5.10 加var的变量和不加var的变量

加var的变量和不加var的变量有什么区别:

  • 加var的变量在预编译期间会提升,不加var的变量在预编译期间不会提升。
<script>
// 加var的变量在预编译期间会提升,不加var的变量在预编译期间不会提升。
// console.log(a); // undefined
// var a = 110;
console.log(b); // ReferenceError: b is not defined
b = 120;
</script>
  • 不管有没有加var,创建的全局变量,都会放到GO中的,也就是可以通过window.xx。
<script>
// 不管有没有加var,创建的全局变量,都会放到GO中的,也就是可以通过window.xx。
var a = 110;
b = 120;
console.log(window.a); // 110
console.log(window.b); // 120
</script>
  • 加var的变量,可能是全局变量,也可能是局部变量,不加var的变量,只能是全局变量
  • 加var的局部变量,不会作用window的属性
<script>
function fn(){
var a = 110;
}
fn();
console.log(window.a);
</script>

不加var创建的变量:

  • 不建议使用。 项目中尽量不要使用全局变量。在项目中,不要使用没有加var的变量。

5.11 IIFE(立即调用函数表达式)

Immediately Invoked Function Expression(立即调用函数表达式)

<script>
	function fn(){
		console.log("fn...");
	}
	// 之前:先定义函数 再去调用函数
	fn();
	// 思考:在定义函数时,能不能直接去调用
	// 答:IIFE
</script>

正确的写法:

<script>
        // IIFE写法一
        (function fn() {
            console.log("fn...");
        })();
    </script>
    <script>
            // IIFE写法二
            (function fn() {
                console.log("fn...");
            }());
    </script>
    <script>
            // IIFE写法三
            + function fn() {
                console.log("fn...");
            }();
    </script>
    <script>
            // IIFE写法四
            - function fn() {
                console.log("fn...");
            }();
    </script>
    <script>
        // IIFE写法五
        !function fn() {
            console.log("fn...");
        }();
    </script>

未完待续…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值