(1珠峰18)JS的变量提升与闭包

 

三、JavaScript

JS:轻量级的客户端脚本编程语言。

1.编程语言

编程语言是具备一定逻辑的,拥有自己的编程思想(面向对象编程[OOP]、面向过程编程)

-面向对象

   +C++

   +JAVA

   +PHP

   +C#(.net)

   +JS

   +...

-面向过程

   +C

2.目前JS已经不仅仅是客户端语言了,基于Node可以做服务器端程序,所以JS是全栈编程语言。

3.学习js,我们学习它的几部分组成

-ECMAScript(ES):JS的核心语法

-DOM:document Object Model 文档对象模型,提供各种API(属性和方法)让JS可以获取或操作页面中的HTML元素(DOM元素)。

-BOM:Browser Object Model 浏览器对模型,提供各种API让JS可以获取或操作浏览器。

 

四、ECMAScript

它是js的语法规划,JS中的变量、数据类型、语法规范、操作语句、设计模式等等都是ES规定的。

1997 ES1.0  => 1998 ES2.0  =>  1999 ES3.0 (最为广泛的应用,奠定JS基础,目前我们用的大部分都是ES3定下的规则语法)  =》 2000 ES4(激进颠覆式更新,最后夭折)  =》 2015.6 ES6...   (ES5和ES6是一样的,目前的说法是ES5代表老版本也就是ES3)

 

-------------------------------------------

 

五、变量(variable)

它不是具体的值,只是一个用来存储具体值的容器或者代名词,因为存储的值可变所以称为变量。

基于ES语法规范,在JS中创建变量有以下方式

-var (ES3)

-function (ES3) 创建函数(函数名也是变量,只不过存储的值是函数类型而已)

-let (ES6)

-const (ES6) 创建的是常量

-import (ES6) 基于ES6的模块规范导出需要的信息

-class (ES6) 基于ES6创建类

 

创建变量,命名的时候要遵循一些规范:

- 严格区分大小写

- 遵循驼峰命名法:按照数字、字母、下划线来命名(数字不能为名字开头),命名的时候基于英文单词拼接成一个完整的名字(第一个单词字母小写,其余每一个有意义的单词首字母大写)

- 不能使用关键字和保留字:在JS中有特殊含义的叫做关键词,未来可能会成为关键字的叫做保留字。

 

六、数据类型

数据值是一门编程语言进行生产的材料,JS包含以下类型:

- 基本数据类型(值类型)

  + 数字 number

  + 字符串 string

  + 布尔 boolean

  + null

  + undefined (JS独有)

- 引用类型

  + 对象object

     + 普通对象

     + 数组对象

     + 正则对象

     + 日期对象

     + ...

  + 函数 function 

- ES6中新增加的一个特殊的类型:Symbol ,唯一的值  

 

扩展:JS代码如何被运行以及运行后如何输出结果。

【如何被运行】

- 把代码运行在浏览器中(浏览器内核来渲染解析)

- 基于node来运行(NODE也是一个基于V8引擎渲染和解析的JS的工具) //node 是环境和工具,js来做后台,依托node来运行。node不是语言还是js。

【如何输出结果】

- alert:在浏览器中通过弹窗的方式输出(浏览器提示框)// window.alert(); alert(1+1);=> '2' 基于alert输出的结果都会利用toString()转换为字符串。 js中表达式先行,先计算结果再输出;       

- confirm:和alert用法一致,只不过提示的内容不一样,有确定和取消两个按钮,所以是确认提示框。

- prompt:在confirm的基础上增加输入框。

- console.log:在浏览器控制台输出日志。  console(控制台).log(日志);

   + Elements:当前页面中的元素和样式在这里都可以看到,还可以调节样式和修改结构等。

   + Console:控制台,可以通过JS代码中通过.log输出到这里,也可以在这里直接编写js代码。

   + Sources:当前网站的原文件都在这里。

   +...

- console.dirI:比log输出的更详细一些(尤其是输出对象数据值的时候)

- console.table:把一个JSON数据按照表格的方式输出。

- ...(自己扩展更多console输出方法)

 思考:为什么对象转换为字符串是 '[object object]' ,toSting()结果。 //  var flag = confirm('确定要退出么?'); if(flag){  //点击的确认 }else{  //点击的取消 } ; 返回的是true和false;

 

 

七、数据类型的详细剖析

1.  number数字类型

NaN:not a number 但是它是数字类型

isNaN:检测当前值是否不是有效数字,返回true,代表不是有效数字,返回false是有效数字。

//=>语法:isNaN([value])
var num = 12;
isNaN(num); //->检测num变量存储的值是否为非有效数字    

isNaN('7')  => false
isNaN('由由') => true
isNaN(true) => false
isNaN(false) => false
isNaN(null) => false
isNaN(undefined) =>true
isNaN({AZUKI:7}) => true
isNaN([12,29]) => true
isNaN([29]) => false
isNaN(/^$/) => true
isNaN(function(){}) => true

重要:isNaN检测的机制
1.首先验证当前要检测的值是否为数字类型的,如果不是,浏览器会默认的把值转换为数字类型
2.当前检测的值已经是数字类型,是有效数字,返回false,不是返回true. 

//tips:再次说明变量本身没有意义,主要看它存储的值是什么。

2.布尔类型

只有两个值,一个是true,一个是false;

如何把其他类型转换为布尔类型?

-Boolean

-!

-!!

Boolean(1) => true

!'深红乌鸦' => 先把其它数据类型转换为布尔类型,然后取反

!!null => 取两次反,等价于没取反,也就剩下转换布尔类型了

真实项目中一般转换布尔类型都是两个叹号。

规律:' 在JS当中只有,0、NaN、空字符串、null、undefined ' 这五个值转换为布尔类型的false,其余都转换为true。

3.null && undefined

>都代表空

>null:空对象指针  

>undefined:未定义 

 

null 一般都是意料之中的没有(通俗理解:一般都是人为手动的先复制为null,一般后面的程序中我们会再次给它赋值)

var num = null ;  //=>null 是手动赋值,预示着后面我会把num的变量的值进行修改
...
num = 7;

undefined 代表的没有一般都不是人为手动控制的,大部分都是浏览器自主为空(后面可以赋值,也可以不赋值)

var num ; //=>此时变量的值浏览器给分配的就是undefined
...
后面可以赋值也可以不赋值

AZUKI七(BOY)的女朋友是 null ,他的男朋友是 undefined ;

null转换为数字是0,undefined是NaN; 

 

object对象数据类型:

> 普通对象
> - 由大括号包裹起来
> - 由零到多组属性名和属性值(键值对)组成

属性是用来描述当前对象特征的,属性名是当前具备的特征,属性值是对这个特征的描述(专业语法,属性名称为键[key],属性值称之为[value],一组属性名和属性值称之为键值对)

var obj = {
    name:"AZUKI七",
    age:"26"     
};
//=>对象的操作:对键值对的增删改查

[获取]

obj.name

obj['name']  一般来说,对象的属性名都是字符串格式的(属性值不固定,任何格式都可以)

[增/改]

JS对象中,属性名是不允许重复的,是唯一的。、

obj.name="柏仔" ; //=>原有对象中存在NAME属性

此处属于修改属性值

obj.sex = '男'; //=>原有对象中不存在sex,此处相当于给当前对象新增加一个sex属性

[删]

彻底删除:对象中不存这个属性了

delete  obj['age'] ;

假删除:并没有移除属性,只是让当前属性值为空

obj.sex = null ;

 

在获取属性值的时候,如果当前对象有这个属性名则可以正常获取到值(哪怕是null),如果没有则获取的结果是 undefined (意料之外的)。

obj['friends'] => undefined

 

 属性名是字符串或者数字格式,如果是其它格式浏览器会用toString()先转换为字符串然后进行存储。

obj[ { } ] = 300; => 先把({}).toString()后的结果作为对象的属性名存储进来 obj['[object object]'] = 300 ;

obj[ { } ] => 获取的时候也是先把对象转换为字符串'[object object]' , 然后获取之前存储的300 ;

存对象没有意义,因为不管里面有什么toString()转换后都是 [object object]

数组也是对象,对象拥有的行为数组也可以。

索引就是属性名,即是属性名也是索引。

 

var a=12;
var b=a;
b=13;
console.log(a);

var obj1 = {n:100};
var obj2 = obj1;
obj['n'] = 200;
console.log(obj.n);

浅分析JS的运行机制:

1.当浏览器(它的内核\引擎)渲染和解析JS的时候,会提供一个JS代码运行的环境,我们把这个环境称之为"全局作用域 (global/window scope) ";

2.代码自上而下执行(之前还有一个变量提升阶段)

   =>基本数据类型的值会存储到当前作用域下

        var a = 12 

        1) 首先开辟一个空间存储12  (栈内存空间)

        2) 在当前作用域中声明一个变量a  (var a)

        3) 让声明的变量和存储的12进行关联(把存储的12赋值给a =>赋值操作叫做定义)

        基本类型值(也叫作值类型),是按照值来操作的:把原有值复制一份,放到新的空间或者位置上,和原来的值没有关系。(按值操作就是为了断了和原来的联系)

       

    => 引用数据类型的值不能直接存储在当前的作用域下(因为可能存储的内容过于复杂),我们需要先开辟一个空间(理解为仓库),把内容存储到这个空间中。   

          var obj = { n : 100 };

          1) 首先开辟一个新的内存空间,把对象中的键值对依次存储起来(为了保证后面可以找到这个空间,此空间有一个16进制的地址)

          2) 声明一个变量

          3) 让变量和空间地址关联在一起(把空间地址赋值给变量)

          引用类型,不是按值操作,它操作的是空间的引用地址,把原来的地址赋值给新的变量,但是原来的空间没被克隆,还是一个空间,这样就会出现多个变量关联的是相同的空              间,相互之间就会存在影响了。

面试题:js值类型和引用类型的区别?

js值类型比较简单,会在当前作用域中开辟一个位置把值存进来,而值类型的操作,都是把原来的值复制一份放到一个新位置,两个位置无关联,按值直接操作。而引用类型因为结构比较复杂,所以是开辟一个新的空间仓库来存储值,为了能够找到有一个16进制的地址关联,变量和引用类型关联都是通过地址,引用类型操作也是通过地址来操作的,不像值类型复制,而是公用同一个地址,通常会导致很多变量指向同一个地址,导致冲突。基本值类型,不会导致两个变量之间产生关联,而引用类型会产生关联。


在js中所有赋值操作都是先有值再关联。

栈内存作用:执行代码,存储基本类型值。(栈内存本身就是代码运行的环境,基本类型值就存在这里,所有值类型都会在栈内存中开辟出对应的位置存储值。)

堆内存作用:存储引用类型值。(对象存储的是键值对,函数存储的是代码字符串。)

 

 

 

###JS中的判断操作语句

1.if / else if /else

if(0){
  //=>不管你在条件判断中写什么,最后总要把其计算出TRUE/FALSE来判断条件是否成立(把其他类型值转换为布尔类型值,只有 0/NaN/' '/null/undefined 是fasle,其它是true)

 //一个值就是先转换为布尔值
}

if('3px'+3){
  //=>在JS中,+ - *  / % 都是数学运算,除 + 以外,其余运算符在运算的时候,如果遇到了非有效数字类型,首先会转化为数字类型(Number),然后再进行运算。

  //=> + 在JS中除了数学相加,还有字符串拼接作用

  '3px' + 3 =>'3px3'

}


if('3px'-3){

   '3px'-3 => NaN

}

 

### typeof

>在JS中用来检测数据类型的方式之一,除此以外,还有:

>- instanceof

>- constructor

>- Object.prototype.toString.call()

只有这四种。

语法: typeof [value] => 检测value的数据类型

返回值:使用tyoeof检测出来的结果是一个字符串,字符串包含着对应的数据类型,例如:“number”,“string”,“boolen”,“undefined” , “object”,“functiton”

typeof null => 'object'   //null 也代表空对象指针(没有指向任何的内存空间)

typeof 检测数组、正则、对象,最后返回的都是“object”,也就是基于这种方式无法细分对象。

typeof 是逻辑运算符不是方法

面试题:
console.log(typeof []);  //=>'object'

console.log(typeof typeof []);
//=> typeof 'object'

//=>"string"

永远是字符串,第一次返回的就是字符串,所以第二次或者n次都是string;
//BAT面试题:
var num = parseInt('width:35.5px');
if(num == 35.5){
   alert(0);
} else if(num == 35){
   alert(1);
} else if(num == NaN){
   alert(2);
} else if(typeof num=='number'){
   //=>先算typeof num 
   //=>再做比较
   alert(3); //=>alert输出的都是字符串格式的  最终结果: "3"
} else {
   alert(4);
}

 

2.三元运算符

>语法:条件?成立做的事情:不成立做的事情;

//如果三元运算符中的某一部分不需要做任何处理,我们用null / undefined / void 0 (相当于undefined) 占位即可

var  num  = 12 ;
num > 10?num++:null//如果需要执行多项操作,我们把其用小括号包裹, 每条操作语句逗号隔开

num = 10;
num>=10?(num++,num*=10):null;


//思考题:改写成三元运算符!

var num = 12 ;
if(num>0){
     if(num<10){
         num++;
     }else{
         num--;
     }
} else {
     if(num==0){
         num++;
         num = num / 10;
     }
}

 

3.switch case

>js的一种判断方式

var num = 12;
if(num == 10){
    num ++ ;
}else if (num==5){
    num -- ;
}else{
    num =0;
}

//switch case 改写:
switch(num){
    case 10:
        num ++;
        break;
    case 5:
        num --;
        break;
    default:
        num = 0;  
}

switch case 应用于变量(或者表达式等)在不同值的情况下的不同操作,每一种case结束后都要加 break(结束整个判断);

switch case 中每一种case情况的比较都是基于“===”绝对相等来完成的。

不加break,后面的条件不管是否成立都会执行;利用此机制,可以做一些特殊处理。

例如:如果num等于10和等于5都要做同一件事,那我们可以写在一起不加break即可。

switch (num){  
     case 10:
     case 5 :
         num --breakdefault:
         num=0;
}

tips:作为一名优秀的it编程者,要更多的勇于尝试。响应式布局:官方文档解决方案只有一种@media ;但是目前项目中的响应式布局方案:flex box 弹性盒子 / rem等比缩放 / scale 固定宽度和等比缩放 ;

 

##FOR循环

作用:按照一定的规律,重复去做某件事情,此时就需要用循环来处理。

语法:①定义初始值 var i = 0 ;

           ②设定循环成立条件 (条件成立循环继续,不成立循环结束) i<ary.length

           ③条件成立执行循环体中的内容(大括号包裹的就是循环体)

   ④执行步长累加的操作

在for循环体中经常出现的两个关键字:

①continue:继续

②break:中断或者结束

for( var i=0;i<10;i++ ){
     if(i<5){
         i++;
         continue;  //=>结束本轮循环(循环体中continue后面 代码将不再执行,继续执行下一轮循环)
     }  
     if(i>7){
         i+=2 ;
         break;   //=>强制结束整个循环不做任何处理
     }
     i += 1;
}

for (var i=1; i<=10; i+=2){
     if(i<=5){
        i++;
        continue;
     } else {
        i-=2;
        break;
     }
     console.log(i);
}
console.log(i);    //=>5

 

CSS3 隔行变色

nth-child:当前容器所有元素中的第N个

                 .box li:nth-child(1)  :  box容器所有子元素中的第一个并且标签名是LI的

nth-of-type(n) :先给当前容器按照某一标签名进行分组,获取组中第N个

                         .box li:nth-of-type(1) : 先获取BOX中所有li,在获取li中的第一个

   .box li:nth-of-type(even) {
            /* !*EVEN:偶数 ODD:奇数*! */
            background: lightcyan;
   }

   .box li{
            /*超出一行的内容自动裁切,以省略号代替*/
            text-overflow: ellipsis;
            white-space: nowrap;
            overflow: hidden;
   }

 

获取页面DOM元素:

document.getElementById

>在整个文档中,通过元素的ID属性值,获取到这个元素对象。

>

>getElementById是获取元素的方法,而document限定了获取元素的乏味,我们把这个范围称之为“上下文 [context]”

var oBox = document.getElementById('box');

①通过getElementById获取的元素是一个对象数据类型的值(里面包含很多内置属性)

type of oBox = > "object"  

②分析包含属性

className:存储的是一个字符串,代表当前元素的样式类型

id:存储的是当前元素的id,字符串格式

innerHTML:存储当前元素中的所有内容(包含HTML标签)

innerText:存储对当前元素中所有文本内容(无标签)

onclick:基于该属性可以给当前元素绑定事件

onmouseover:鼠标滑过事件

onmouseout:鼠标离开事件

style:存储当前元素所有行内样式值

 

想要修改BOX的样式:

①通过style修改行内样式  // oBox.style

②通过CLASS-NAME修改样式类  // oBox['className'] += ' bgColor'

 

[context].getElementByTagName

>在指定的上下文中,通过元素的标签名获取一组元素集合

>

>上下文是我们自己来指定的

var boxList = oBox.getElementByTagName('li');

①获取的结果是一个元素集合(HTMLCollection),首先它也是对象数据类型的,结构和数组非常相似(数字为索引,length代表长度),类数组。

 

###函数

>在js中,函数就是一个方法(一个功能体),基于函数一般都是为了实现某个功能。

函数诞生的目的就是为了实现封装,把实现一个功能的代码封装到一个函数中,后期想要实现这个功能,只需要把函数执行即可,不需要再次编写重复代码,起到了,低耦合高内聚(减少页面中的冗余代码,提高代码的重复使用率),的作用 。

函数作为引用类型中的一种,它也是按照引用地址来操作的,首先会开辟一个堆内存,把函数体中的代码当作“字符串”存储到内存中(对象向内存中存储的是键值对)

把开辟的堆内存地址赋值给函数名(变量名),加()就是调用了,不加就是地址。

【函数执行】

目的:把之前存储到堆内存中的代码字符串变成真正的JS代码,自上而下执行,从而实现现有功能。

1.函数执行,首先会形成一个私有作用域(一个供代码执行的环境,也是栈内存)

2.把之前在堆内存中存储的字符串复制一份过来,变为真正的js代码,在新开辟的作用域中自上而下执行。

【函数参数】

参数是函数的入口:当我们在函数中封装功能的时候一些原材料不确定,需要执行函数的时候用户传递进来才可以,此时基于参数的机制,提供出入口即可。

函数定义时:入口,形参,是变量。

函数调用时:入口,实参,给入口提供的具体值。

=========

创建函数:

ES3标准

function 函数名([参数]){

      函数体:js实现函数功能

}

ES6提供箭头函数

 

 

 

 

 

 

 

 

 

 

 

 

 

JS的变量提升与闭包

【JS渲染机制堆栈内存】

  当浏览器去加载界面加载js时,首先会创建提供window全局作用域,然后,代码开始自上而下执行,

代码:var a = 7;

①声明变量a,默认值为undefined

②在当前作用域中开辟一个位置存储7这个值

③让变量a和值12关联在一起(赋值)

基本类型和引用类型的区别就是,存储方式的不同。

基本类型直接在作用域中,引用类型因为相对复杂,所以需要单独开辟的存储空间。

var ary1 =  [12,23];

var ary2 = ary1;

ary2.push(100);

console.log(ary1); //[12,23,100]

所有作用域的两个作用:提供代码的执行环境 存储基本类型值。

 

IE靠的是计数器,引用加一,反之减一。Chrom则是,固定时间查看一下,是否还被引用。

IE计数器,记混的时候,就发生了内存泄漏。

想让堆内存销毁,直接赋值为 null ,通过空对象指针 null 可以让 原始变量或者其它 指向空,那么原有被占用的堆内存就没有被占用了,浏览器就会在空闲的时候销毁它。

 

【变量提升机制】

变量提升:当栈内存(作用域)形成,JS代码自上而下执行之前,浏览器受限会把所有带"VAR"/"FUNCTION"关键词的进行提前"声明"或者"定义",这种预先处理机制,叫做"变量提升"。 

=》 声明(declare): var a (默认值undefined)

=》 定义(defined): a = 12 (定义其实就是赋值操作)

    [变量提升阶段]

=》带"VAR"的只声明未定义

=》带"FUNCTION"的声明和赋值都完成了

=》变量提升只发生在当前作用域。(例如:开始加载页面的时候只对全局作用域下的进行提升,因为此时函数中存储的都是字符串而已)

=》在全局作用域声明的函数或者边阿玲是"全局变量",同理,在私有作用域下声明的变量是"私有变量" [带VAR/FUNCTION的才是声明]

自从学了预解释,从此节操是路人。

=》浏览器很懒,从不会做相同的事情。当代码执行遇到创建函数这部分代码后,会直接跳过(因为在提升阶段就已经完成了函数的赋值操作了)

 

【重名问题】 

 

【暂时性死区】

在ES6中Let和const等方式创建变量或者函数,不存在变量提升机制。

=》切断了全局变量和window属性的映射机制。

=》在相同作用域,基于Let 不能声明相同名字的变量。(不管是是什么方式只要声明了,在用let重复声明就会报错,var也一样)

虽然,没有变量提升机制,但是在当前作用域代码自上而下执行之前,浏览器会做一个重复性检测:自上而下查找当前作用域下所有变量,一旦发现重复的,直接抛出异常,代码停止,不会继续执行。(虽然没有把变量提升,但是浏览器已经记住了,当前作用域下有哪些变量。)

 

 

 

   

a,b变为私有的,与全局无关,c为全局。 

 

【私有变量练习】

 

 

【上级作用域查找】

 

 =》arguments:实参集合

=》arguments.callee:函数本身

=》arguments.callee.caller:当前函数在哪执行的,CALLER就是谁(记录的是执行它的宿主环境),在全局下执行的结果是null。(严格模式编程禁止使用这两个属性。)

=》当函数执行时,形成一个私有作用域A,A的上级作用域是谁,和他在哪执行没有关系,和它在哪创建定义有关系,在哪创建的,它的上级作用域就是谁。

 

【堆栈内存销毁机制】 

=》JS分为堆内存和栈内存

=》堆内存(存储引用类型值),和代码分开(对象:键值对  函数:代码字符串)

=》栈内存,提供JS代码的执行环境存储基本类型值

[堆内存释放] :让所有引用堆内存空间地址的变量赋值为 NULL 即可(没有变量占用这个堆内存,浏览器在空闲的时候就会将其释放)

[栈内存释放] :一般情况下,当函数执行完成后,所形成的私有作用域(栈内存)都会自动释放掉,(在栈内存占用存储的值也会释放掉),但是也存在特殊情况:

                         ①函数执行完成,当前形成的栈内存中,某些内容被栈内存以外的变量占用。

                         ②全局栈内存,只有当页面关闭后才会被释放掉。 

                          ...

                         如果当前栈内存没有被释放掉,那么之前在栈内存中存储的基本值也不会被释放掉,能够一直保存下来。

 i++ :自身累加1 ,和别人运算的时候 ,先拿原有值和其其它进行运算,运算结束后,本身累加1 。

++i  :自身累加1 ,先自身累加1,再和别人运算。

 

 

 6 12 16 8 

 

【带不带var的区别】

=>在全局作用域下声明一个变量,也相当于给Window全局对象设置了一个属性,变量的值就是属性值(私有作用域中声明的私有变量和Window无关)

用  in 操作符 可以检测某个属性名是否隶属于这个对象。 'AZUKI'  in  BoZai ,rue;

=》全局变量和window中的属性存在"映射机制" , 双方互相同步。

=》不加var本质是win的属性,创建变量必需加var,养成良好的编程习惯。

 

【闭包】

函数执行形成一个私有的作用域,保护里面的私有变量不受外界干扰,这种保护机制称之为“闭包”。

函数执行形成一个不销毁的私有作用域(私有栈内存)才是闭包。

//=>闭包:柯理化函数 fn执行返回一个堆内存被f占用,所以fn作用域不销毁
function fn(){
  return function (){

  }
}

var f=fn();
//=>闭包:惰性函数 自执行匿名函数形成的私有作用域被utils占用
var utils=(function(){
  return{
  
  }
})();

小纸条:()内表示声明一个函数,正常声明函数是不能直接在后面加括号调用的。

闭包应用举例:
真实项目为了保证JS性能(堆栈内存的性能变化),应该尽可能减少闭包的使用(不销毁的堆栈内存是消耗性能的)。 1.闭包的保护作用:保护私有变量不受外界干扰 真实项目开发中,尤其是团队协作开发,应尽量减少全局变量的使用,防止冲突,造成全局变量污染,那么此时我们可以把自己这一部分内容封装到一个闭包中,让全局变量转换为私有变量。 (function(){})(); 封装插件的时候,也会把程序都放到闭包中保护起来,防止和用户的程序冲突,这时对于一些需要暴露给用户的方法可以抛到全局。 JQ:把需要暴露的方法抛到全局 Zepto:基于RETURN把需要外面使用的方法暴露出去

2.闭包的保存作用:形成不销毁的栈内存,把一些值保存下来,方便后面调取使用

 

tips:

进入函数:形参赋值 变量提升 代码自上而下执行

在传统的ES规范中,只有全局作用域和函数执行产生的私有作用域,判断和循环并不会产生作用域。

原生JS:闭包,oop,异步编程,promise,async和await,es6新特性,js事件机制

所有的事件绑定都是异步编程(当前事件没有完成,不再等待,继续执行下面的任务。),同步编程(一件事一件事做,当前事件没完成,下一个任务不能处理。)

小结:

有占用,不释放,无论是变量,还是事件什么占用,就是闭包。

ES6中判断循环都是块级作用域,一般大括号内部都是块级作用域。(对象除外)

每一轮循环,都会形成一个单独的作用域。

ES6

自带严格模式,严格模式下的一些限制:

 

常用数组遍历方法:

-forEach

-map

-find(ES6)

-findIndex(ES6)

-filter

-some

-every

以上都可以改this

-reduce(数组去重,对象属性求和,数组元素出现次数,这里主要就是利用reduce第一个参数是迭代,可以通过初始化这个参数的数据类型,达到想实现的效果。)

-reduceRight

ES6数组空位统一为undefined处理;

扩展运算符将一个数组,变为参数序列。

set Map【小纸条:详情链接】:

set:

不存储value。由于key不能重复,所以,在Set中,没有重复的key

[ ...new Set(arr)] 去重,set 是一个类数组对象;

 set.has(Nan) 判断有无,返回true/false;

 set.clear() 清空,无返回值undefined

 map:

 对象的属性名必是字符串,即是不写字符串也会因默认数据类型而变为字符串。

 

Symbol:

基本数据类型,typeOf 可检测,不能和字符串进行拼接,

不能进行运算,可以转布尔,

只要通过Symbol()函数得到的值就是唯一的值,只做自己,和任何人都不一样

Symbol("参数作为描述,两个Symbel创建的值描述相同,也不会相等")

 

 对象的属性用 [ ]  中括号括起来,代表着里面是变量。

如果属性名是Symbol形式,必须通过中括号,不能通过点的形式

 

 

Iterator【小纸条:详情链接详情链接2:

 es6中有三类结构生来就具有Iterator接口:数组、类数组对象、Map和Set结构。(Promise.all())

只要具备Iterator,遍历接口,就可用扩展运算符 [...arr]

默认的遍历接口:__proto__[Symbol.Iterator] 

 

prototype与__proto__【小纸条:详情链接:

1.在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此,它们都会具有对象共有的特点。
即:对象具有属性__proto__,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。

2.方法(Function)
方法这个特殊的对象,除了和其他对象一样有上述_proto_属性之外,还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。

 

proxy和defineProperty:

new Proxy(target目标对象,{代理方法});

 

 

 

posted @ 2021-04-26 13:48  AZUKI七  阅读(252)  评论(0编辑  收藏  举报