我的前端学习之路之javascript-1

307 阅读21分钟

一、学会处理报错

1.alert('慕课网'); =>不小心写成了中文分号
报错语法:Uncaught SyntaxError: lnvalid or unexpected token
未捕获的语法错误:不合法或错误的符号

2.alert(慕课网); =>没用引号包裹
报错语法:Uncaught ReferenceError:慕课网is not defined
未捕获的引用错误,慕课网没有被定义

2.alret('慕课网'); =>没用引号包裹
报错语法:Uncaught ReferenceError:alert is not defined
未捕获的引用错误,alert没有被定义

二、变量

基础知识

变量是在内存中存储值的符号
变量不是数值本身,它们仅仅是一个用于存储数值的容器
变量使用时不能使用引号

变量的默认值
一个变量只定义,但没有赋初值,默认值是undefined
一个变量只有被var定义,并赋初值之后,才算正式初始化完成

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

变量的常见错误
1.不用var定义,而直接将值赋予它,虽不引发报错,但会产生作用域问题 2.尝试使用一个既没有被var定义过,也没有赋过值的字符,则会产生引用错误 console.log(b); //Reference Error

变量的合法命名
1.只能是字母、数字、下划线、¥组成,但不能以数字开头
2.不能是关键字保留字 3.大小写敏感,a和A两个不同的变量

变量的声明提升

变量声明的提升:你可以提前使用一个稍后才声明的变量,而不会引发异常 变量声明提升时,只提升变量的定义,不会提升它的值

console.log(a);
var a=12; //undefined

变量声明提升是经常会考的面试题

js基本数据类型

两大基本数据类型

基本数据类型 Number,null,boolean,string,undefined 存放在栈中:数据的存储方式是先进后出。 复杂数据类型 object,Array,Function,RegExp,Date,Map,Set,Symbol等 存放在堆中
通过使用在栈中保存对应的指针来获取堆中的值,

数据类型详解

number

面试question-->NaN
它不是一个数,但它是一个数字类型的值
typeof NaN; //number
o除以0的结果是NaN,事实上,在数学运算中,若结果不能得到数字,其结果往往是NaN
NaN 是一个特殊值,它不自等,是唯一一个非自反的值,
NaN!=NaN的结果为true

面试question--> isNaN和Number.isNaN函数的区别
函数isNaN接收参数后,会尝试将这个参数转换为数值,任何不能转换为数值的值将返回true,因此,非数字值传入也会返回true
而Number.isNaN会首先判断传入参数是否为数字,如果是数字再继续判断是否为NaN

面试question-->js中整数的安全范围
安全整数指的是,在这个范围内的整数转换为二进制存储的时候不会出现精度丢失,能够被安全呈现的最大整数范围是2^53-1,在es6中被定义为Number.MAX_SAFE_INTEGER,最小整数Number.MIN_SAFE_INTEGER
如果某次计算得到了一个超过js数值范围的值,那么这个值就会自动转换为特殊的Infinity值。如果某次计算返回了正或负的Infinity值,那么该值就不能参与下一次的计算。判断一个数是不是有穷的,可以使用isInfinite函数来判断 typeof Infinity;//number

string类型

字符串的常用方法

方法功能
charAt得到指定位置字符
subString提取子串
subStr提取子串
slice提取子串
toUpperCase将字符串变为大写
toLowerCase将字符串变为小写
indexOf检索字符串

subString(),subStr(),slice()
subString(a,b) 方法得到从a开始到b结束(不包括b处)的子串
'abcdefg'.subString(3,5) //de
如果省略第二个参数,则会从索引开始一直提取到字符串的结尾,参数a可以小于b

subStr(a,b) 将得到从a开始的长度为b的子串
'abcdefg'.subStr(3,2); //de
a也可以是负数,表示倒数位置

slice(a,b) 方法得到从a开始到b结束(不包括b处)的子串,参数a的值可以是负数,参数a必须小于b

indexOf()方法 返回某个指定的字符串在字符串首次出现的位置,如果要索引的字符串没有出现,则返回-1

用typeof检测null结果是object typeof null; //object 面试比较容易考

数据类型的转换

使用number()函数

面试question-->其他值到数字值的转换规则

字符串->数字 纯字符字符串能变为数字,不是纯数字的字符串将转为NaN
布尔值->数字 true变为1,false变为0
undefined和null->数字 undefined转换为NaN,null转换为0 Symbol 类型 不能转换为数字,会报错。
对象(包括数组) 会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。为了将值转换为相应的基本类型值,抽象操作ToPrimitive 会首先(通过内部操作 Defaultvalue)检查该值是否有valueof()方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用toString()的返回值(如果存在)来进行强制类型转换。如果 valueof()和 toString()均不返回基本类型值,会产生 TypeError错误。

使用parseInt()函数

parselnt()函数的功能是将字符串转为整数
parseInt('3.14'); //3 自动截掉第一个非数字字符后的所有字符
parseInt('3.14是圆周率');// 3 所有文字都将被截掉
parseInt('圆周率是3.14'); // NaN 如果字符串不是以数字开头,则转为NaN
parseInt( '3.99'); // 3 parselnt()函数不四舍五入

使用parseFloat()函数

parselnt()函数的功能是将字符串转为浮点数,与parseInt注意的点比较类似

string()方法

面试question-->其他值到字符串值的转换规则

数字->字符串 变成长得相同的字符串,科学记数法和其他进制数字会转化为10进制
其他数据类型都是转化为长得相同的字符串
null和undefined,null转换为"null",undefined转换为"undefined"
symbol 直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误

表达式与运算符

算数运算符

隐式类型转换 如果参与数学运算的某操作数不是数字型,那么js会自动将此操作数转换为数字型,饮食转换的本质是内部调用Number*()函数

在进行小数运算时,要调用数字的toFixed()方法保留指定的小数位数

~操作符的作用
~返回2的补码,并且~会把数字转换为32位整数,因此我们可以用~进行取反操作,~x大致等同于-(x+1)

面试question-->+操作符何时用于字符串的拼接
如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+将进行拼接操作。如果其中一个操作数是对象(包括数组),则首先对其调用ToPrimitive 抽象操作,该抽象操作再调用[[Defaultvalue]],以数字作为上下文。如果不能转换为字符串,则会将其转换为数字类型来进行计算。简单来说就是,如果+的其中一个操作数是字符串(或者通过以上步骤最终得到字符串),则执行字符串拼接,否则执行数字加法。那么对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字。

幂运算
Math.pow(2,3); //8 Math.sqrt(81); //9

取整
向上取整Math.ceil(2.4); //3
向下取整Math.floor(2.4); //2

null和undefined的区别
1.首先他们都属于基本数据类型,undefined代表的含义是未定义,null代表的含义是空对象
2.一般声明了但未定义的时候会返回undefined,null主要用于赋值给一些可能会返回对象的变量。
3.null==undefined;//true
null===undefined//false

面试question-->==操作符的强制类型转换规则
(1)字符串和数字之间的相等比较,将字符串转换为数字之后再进行比较。
(2)其他类型和布尔类型之间的相等比较,先将布尔值转换为数字后,再应用其他规则进行比较
(3)null和undefined之间的相等比较,结果为真。其他值和他们进行比较都返回假值。
(4)对象和非对象之间的相等比较,对象先调用ToPrimitive 抽象操作后,再进行比较。
(5)如果一个操作值为NaN ,则相等比较返回false ( NaN本身也不等于NaN )。
(6)如果两个操作值都是对象,则比较它们是不是指向同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true,否则,返回false。

不相等和不全等
!= 表示不相等;!== 表示不全等
5!=6 //true
5!==6 //true
5!='5' //false
5!=='5' //true

逻辑运算的优先级
非->与->或

综合运算的运算顺序
非运算->数学运算->关系运算->逻辑运算
逻辑运算 2&&8 //2 2||8 //8

面试问题

内部属性[[Class]]是什么

所有typeof返回值为‘object’的对象(如数组)都包含一个内部属性[[Class]](我们可以把它看作一个内部的分类,而非传统意义上的类)。这个属性无法直接访问,一般通过Object.prototype.toString(...)来查看,例如:

Object.prototype.toString.call([1,2,3]);
//'[object Array]'

介绍Js中有哪些内置对象

js 中的内置对象主要指的是在程序执行前存在全局作用域里的由 js定义的一些全局值属性、函数和用来实例化其他对象的构造函数对象。一般我们经常用到的如全局变量值NaN、 undefined,全局函数如 parseInt()、parseFloat()用来实例化对象的构造函数如 Date、object等,还有提供数学计算的单体内置对象如 Math对象。

Undefined和undeclared的区别

己在作用域中声明但还没有赋值的变量,是 undefined 的。相反,还没有在作用域中声明过的变量,是undeclared 的。对于undeclared变量的引用,浏览器会报引用错误,如ReferenceError: b is not defined 。但是我们可以使用typeof的安全防范机制来避免报错,因为对于undeclared(或者not defined )变量,typeof 会返回“undefined"。

如何获取安全的undefined值

因为_undefined是一个标识符,所以可以被当作变量来使用和赋值,但是这样会影响undefined 的正常判断。表达式 void__没有返回值,因此返回结果是undefined。 void 并不改变表达式的结果,只是让表达式不返回值。按惯例我们用void 0来获得undefined。

书写JavaScript的基本规范

  1. 一个函数作用域中所有的变量声明应该尽量提到函数首部,用一个var声明,不允许出现两个连续的 var声明,声明时如果变量没有值,应该给该变量赋值对应类型的初始值,便于他人阅读代码时,能够一目了然的知道变量对应的类型值。
  2. 代码中出现地址、时间等字符串时需要使用常量代替。
  3. 在进行比较的时候吧,尽量使用'===', '!== '代替'==', '!='。
  4. 不要在内置对象的原型上添加方法,如Array,Date。
  5. switch语句必须带有default分支。
  6. for循环和if语句必须使用大括号。

流程控制语句

if语句

if语句的流程不再赘述,关于if语句有一道水仙花数判断算法题
(水仙花数:个位数、十位数、百位数的三次方相加等于它本身)
两种解法
数字方法

// 要求用户输入一个三位数
        var n = Number(prompt('请输入一个三位数'));

        // 对用户输入的数值,进行合法性的验证
        if (!isNaN(n) && 100 <= n && n <= 999) {
            // 当用户输入的数字是合法
            // 数学方法
            // 百位
            var a = Math.floor(n / 100);
            // 十位
            var b = Math.floor(n / 10) % 10;
            // 个位
            var c = n % 10;

            // 根据水仙花数的条件进行判断
            if (Math.pow(a, 3) + Math.pow(b, 3) + Math.pow(c, 3) == n) {
                alert('这个数字是水仙花数');
            } else {
                alert('这个数字不是水仙花数');
            }
        } else {
            // 输入不合法
            alert('您输入的数字不合法的');
        }

字符串方法

省略部分代码
 var n_str = n.toString();
 var a = Number(n_str.charAt(2));
 var b = Number(n_str.charAt(1));
 var c = Number(n_str.charAt(0));

for循环

while循环

break和continue语句,do while循环

break表示立即终止循环,它只能用在循环语句中,在for和while循环中都可以使用

for(var i=0;i<10;i++){
console.log(i);
if(i==4){
  break;
} //0,1,2,3,4

break用在while语句中,通常和while(true){}搭配使用

var n=1;
while(true){
  if(n*n>456789){
      console.log(n);
      break;
    }
    n++;
 }

continue用于跳过循环中的一个迭代,并继续执行循环中的下一个迭代
do while是一种后测试循环语句
do-while循环将执行条件写在了循环体的后面,这样一来,循环体一定会至少执行一次,然后再检查执行条件是否为true,决定是否继续执行循环体。

do*{
    循环体
}while(循环执行条件)

随机数函数

得到0和1之间的小数 Math.random()
得到[a,b]区间的整数 parseInt(Math.random()*(b-a+1)+a

数组

下标越界 js规定,访问数组中不存在的项会返回undefined,不会报错

创建数组的方式
var array=['A','B','C']
var array=new Array('A','B','C')
var array=new Array(4)

数组类型的检测
1.数组用typeof检测结果是object
2.Array.isArray()方法可以用来检测数组

数组方法

数组的头尾操作方法

方法功能
push()在尾部插入新项
pop()在尾部删除
unshift()在头部插入新项
shift()在头部删除

push()方法

1.push()用来在数组末尾推入新项,参数就是要推入的项
2.如果要推入多项,可以用逗号隔开
3.调用push()方法后,数组会立即改变,不需要赋值

pop()方法

1.与push()相反,pop()方法用来删除数组中的最后一项
2.pop()方法不仅会删除数组末项,而且会返回被删除的项

unshift()方法

1.unshift()方法用来在数组头部插入新项,参数就是要插入的项
2.如果要插入多项,可以用逗号隔开
3.调用unshift()方法后,数组会立即改变,不需要赋值
返回数组长度

shift()方法

与unshift(()相反,shift()方法用来删除数组中下标为0的项
返回被删除的值

splice()方法

splice()方法用于替换数组中的指定项

var arr =['A', 'B', 'c', 'D', 'E', 'F','G'];  
arr.splice(3 , 2 , 'x', 'Y' , 'z'); 
//从下标为3的项开始,连续替换2项 
console.log( arr);  
// [ ' A''B', 'c', 'x', 'Y', 'z''F''G']

slice()方法

1.slice()方法用于得到子数组,类似于字符串的slice()方法
2.slice(a,b)截取的子数组从下标为a的项开始,到下标为b(但不包括下标为b的项)结束
3.slice(a,b)方法不会更改原有数组

join()和split()方法

数组的join()方法可以使数组转为字符串
字符串的split()方法可以字符串转为数组

concat()、reverse()、indexOf()、includes()

concat()方法可以合并多个数组,并且不会改变原数组
reverse()方法用来把数组中的所有项全部顺序置反
indexOf()方法的功能是搜索数组中的元素,并返回它所在的元素,如果元素不存在,则返回-1
includes()方法的功能是判断一个数组中是否包含一个指定的值,返回布尔值

基本类型值和引用类型值

举例当var a=b变量传值时当用==比较时
基本类型值数字型、字符串型、布尔型等内存中产生新的副本比较值是否相等
引用类型值对象,数组内存中不产生新的副本,而是让新变量指向同一个对象比较内存地址是否相同,即比较是否为同一个对象

面试题

Array构造函数只有一个参数值时的表现

Array 构造函数只带一个数字参数的时候,该参数会被作为数组的预设长度(length),而非只充当数组中的一个元素。这样创建出来的只是一个空数组,只不过它的 length属性被设置成了指定的值。构造函数 Array(..)不要求必须带new关键字。不带时,它会被自动补上。

{}和[]的valueOf 和toString 的结果是什么?

  • {}的valueOf 结果为{}, toString 的结果为"[object object]"
  • []的 valueOf 结果为[],toString的结果为""

什么是假值对象?

浏览器在某些特定情况下,在常规JavaScript语法基础上自己创建了一些外来值,这些就是“假值对象”。假值对象看起来和普通对象并无二致(都有属性,等等),但将它们强制类型转换为布尔值时结果为 false最常见的例子是 document.all,它是一个类数组对象,包含了页面上的所有元素,由 DOM(而不是 JavaScript引擎)提供给 JavaScript程序使用。

~操作符的作用?

~返回2的补码,并且~会将数字转换为32位整数,因此我们可以使用~来进行取整操作。 ~x大致等同于 -(x+1)。

解析字符串中的数字和将字符串强制类型转换为数字的返回结果都是数。它们之间的区别是什么?

解析允许字符串(如 parseInt() )中含有非数字字符,解析按从左到右的顺序,如果遇到非数字字符就停止。而转换(如Number ())不允许出现非数字字符,否则会失败并返回NaN。

常用正则表达式

  • 匹配16进制颜色值var regex = /#([O-9a-fA-F]{6}| [O-9a-fA-F]{3})/g;
  • 匹配日期,如 yyyy-mm-dd格式var regex =/^[0-9]{4}-(8[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
  • 匹配 qq 号 var regex = /^[1-9][0-9]{4,10}$/g;l/
  • 手机号码正则var regex =/^1[34578]\d{9}$/g;
  • 用户名正则var regex = /^[ a-zA-Z$][a-zA-ZO-9_$]{4,16}$/;

如何实现数组的随机排序

  1. 使用数组 sort 方法对数组元素随机排序,让 Math.random()出来的数与0.5比较,如果大于就返回1交换位置,如果小于就返回 -1,不交换位置。
function randomSort(a, b) {
return Math .random() > 0.5 ?-1 : 1;}

缺点:每个元素被派到新数组的位置不是随机的,原因是 sort()方法是依次比较的。 2. 随机从原数组抽取一个元素,加入到新数组

function randomSort( arr) {
var result = [];
while ( arr.length > 0){
var randomIndex = Math.floor( Math.random() *arr.length);
result.push( arr[randomIndex]);
arr.splice( randomIndex,1);
}
return result; }
  1. 随机交换数组内的元素(洗牌算法类似)
Function randomSort( arr) {
var index ,
randomIndex,
temp,
len = arr.length;
for (index = 0; index < len; index++) {
randomIndex = Math.floor(Math.random()* ( len - index)) + index;
temp = arr[index] ;
arr[index] = arr[ randomIndex];arr[randomIndex] = temp ;

函数

函数的定义

  • 函数就是语句的封装,可以让代码方便的被复用
  • 函数具有‘一次定义,多次调用’的优点
  • 使用函数,可以简化代码,让代码具有可读性

和变量类似,函数必须先定义然后才能使用;使用function关键字定义函数

函数的调用

  • 执行函数体中的所有语句,就称为调用函数
  • 调用函数只需在函数名字后书写圆括号对即可

函数执行顺序

  • 定义函数,函数是不会被执行的
  • 函数必须要等到调用时才能执行,可以被多次调用

函数声明的提升

函数声明是可以提升的;
但如果函数是用表达式的写法定义的,则没有提升特性

fun();//引发错误
var fun=function(){}

函数的优先提升

函数会优先提升,然后是变量声明提升

fun();  //弹出B
var fun=function(){
  alert('A')
}     //变量声明提升,不会覆盖提升的函数
function fun(){
  alert('B')
}
fun();//弹出A

函数声明提升和变量声明提升应该算是比较经典的面试题吧

函数的参数和返回值

function add(a,b){  //圆括号中定义形式参数
  var sum=a+b;
  console.log(sum);
}
add(3,5)  //调用函数时传入实参

形参和实参个数不同的情况

实参>形参,则没有形参接收它 实参<实参,则输出的值为undefined

function add(a,b,c){  
  var sum=a+b+c;
  console.log(sum);  //NaN
}
add(3,5)  

arguments

  • 函数内arguments表示它接收到的实参列表,它是一个类数组对象
  • 类数组对象:所有属性均为从0开始的自然数序列,并且有length属性,和数组类似可以用方括号书写下标访问对象的某个属性值,但是不能调用数组的方法
  //不管用户传入多少个参数,都能计算它们的和
        function fun(){
            var sum=0;
            for(var i=0;i<arguments.length;i++){
                sum+=arguments[i];
            }
            console.log(sum)
        }
        fun(33,44,66)

返回值

函数的返回值可以被变量接收

function fun(a,b){
  return a+b;
}
var result=fun(3,5);

调用一个有返回值的函数,可以被当做一个普通值,从而可以出现在任何可以书写值的地方。

遇见return即退出函数
调用函数时,一旦遇见return语句就会立即退出函数,将执行权交还给调用者

function fun() {
  console.log( 'A');
  return 'B' ;
  console.log( 'C');
}
console.log(1);
var char = fun();
console.log(char);
console.log(2);
// 1 A B 2

所以写if语句的时候,就不用写else分支了

//编写一个函数是否是偶数
function oushu(a){
            if(a%2==0) return true;
            return false;
        }

javascript中内置sort()方法

 var arr = [5,6,,41,9,22,33];
        arr.sort(function(a,b){
            return b-a;
        })
   console.log(arr)
   //[41,33,22,9,6,5]

递归

函数的内部语句可以调用这个函数自身,从而发起对函数的一次迭代。在新的迭代中,又会执行调用函数自身的语句,从而又产生一次迭代。当函数执行到某一次时,不再进行新的迭代,函数被一层一层返回,函数被递归。

递归的要素

边界条件:确定递归到何时终止,也称为递归出口
递归模式:大问题是如何分解为小问题的,也称为递归体

递归求阶乘

// 书写一个函数,这个函数内部自己会调用自己,从而形成递归。
        function factorial(n) {
            // 函数的功能是计算n的阶乘,n!不就是n * (n-1)!么??
            // 这个就是递归的出口,如果计算1的阶乘,可以不用递归了,直接告诉你答案就是1
            if (n == 1) return 1;
            // 如果询问的不是1的阶乘,就返回n * (n-1)!
            return n * factorial(n - 1);
        }

        var result = factorial(6);

        alert(result);

递归算法:斐波那契数列

递归算法:深拷贝

这两个算法见另一篇文章(算法JavaScript-1/2)

全局变量和局部变量

变量作用域 js是函数级作用域编程语言,变量只在其定义时所在的function内部有意义

全局变量 不将变量定义在任何函数的内部

遮蔽效应
如果函数中定义了和全局同名的变量,则函数内的变量会将全局的变量遮蔽

var a=5;
        function fun(){
            a++;
            var a=10;
            console.log(a);//10
        }
        fun();
        console.log(a);//5

此题解析: 在function中var a=10中的var a会被变量声明提升,此时再考虑遮蔽情况,所以a此时是一个局部变量,值为undefined,a++之后变为NaN

形参也是局部变量

 var a=10;
        function fun(a){
            a++;
            console.log(a);//8
        }
        fun(7);
        console.log(a);//10

作用域链

在函数嵌套(一个函数内部可以定义另一个函数)中,变量会从内到外逐层寻找他的定义

var a = 10;
        var b = 20;
        function fun() {
            var c = 30;
            function inner() {
                var a = 40;
                var d = 50;
                console.log(a, b, c, d);//40,20,30,50
            }
            inner();
        }
        fun();

不加var将定义全局变量

  • 在初次给变量赋值时,如果没有加var,则定义全局变量
function fun(){
//字母c没有加var关键词调用,所以它就变成了全局变量
  c=3;
  c++;
}
fun();
//在函数外部,是可以访问变量c的
console.log(c);//4

闭包

js中函数会产生闭包。闭包是函数本身该函数声明时所处的环境状态的组合

image.png 函数能够记忆住其定义时所处的环境,即使函数不在其定义的环境中被调用,也能访问定义时所处环境的变量。

观察闭包现象

  • 每次创建函数时都会创建闭包;
  • 但是,闭包特性往往需要将函数“换一个地方”执行,才能被观察出来。
    闭包很有用,因为它允许我们将数据与操作该数据的函数关联起来 ,这与“面向对象编程”有少许相似之处。

闭包的功能:记忆性、模拟私有变量

闭包用途1–记忆性
当闭包产生时,函数所处环境的状态会始终保持在内存中,不会在外层函数调用后被自动清除。这就是闭包的记忆性。

function createCheckTemp(standardTemp) {
            function checkTemp(n) {
                if (n <= standardTemp) {
                    alert('你的体温正常');
                } else {
                    alert('你的体温偏高');
                }
            }
            return checkTemp;
        }

        // 创建一个checkTemp函数,它以37.1度为标准线
        var checkTemp_A = createCheckTemp(37.1);
        // 再创建一个checkTemp函数,它以37.3度为标准线
        var checkTemp_B = createCheckTemp(37.3);
        
        checkTemp_A(37.2);

闭包用途2–模拟私有变量
题目:请定义一个变量a,要求是能保证这个a只能被进行指定操作(如加1、乘2),而不能进行其他操作,应该怎么编程呢?此时使用闭包

 // 封装一个函数,这个函数的功能就是私有化变量
        function fun() {
            // 定义一个局部变量a
            var a = 0;
            return {
                getA: function () {
                    return a;
                },
                add: function () {
                    a++;
                },
                pow: function () {
                    a *= 2;
                }
            };
        }

        var obj = fun();
        // 如果想在fun函数外面使用变量a,唯一的方法就是调用getA()方法
        console.log(obj.getA());
        // 想让变量a进行加1操作
        obj.add();
        console.log(obj.getA());

使用闭包的注意点

  • 不能滥用闭包,否则会造成网页的性能问题,严重时可能导致内存泄露。所谓内存泄漏是指程序中己动态分配的内存由于某种原因未释放或无法释放。 所谓内存泄漏是指程序中己动态分配的内存由于某种原因未释放或无法释放。

立即执行函数IIFE

IIFE ( Immediately Invoked Function Expression,立即调用函数表达式)是一种特殊的JavaScript函数写法,一旦被定义,就立即被调用

(function(){
   statements
})();
//function外边的括号对,表示将函数变为表达式;最后的括号对的功能是运行函数

IIFE的作用

  1. 为变量赋值
var age = 42;
        var sex = '女';
        var title = (function () {
            if (age < 18) {
                return '小朋友';
            } else {
                if (sex == '男') {
                    return '先生';
                } else {
                    return '女士';
                }
            }
        })();
  alert(title);``

  1. 将全局变量转化为局部变量
var arr=[];
        for(var i=0;i<5;i++){
            (function(i){
                arr.push(function(){
                    alert(i)
                });
            })(i)
        }
        arr[2]();