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

 

3、JavaScript

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

1.编程语言node

编程语言是具有必定逻辑的,拥有本身的编程思想(面向对象编程[OOP]、面向过程编程)es6

-面向对象编程

   +C++设计模式

   +JAVA数组

   +PHPpromise

   +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能够获取或操做浏览器。

 

4、ECMAScript

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

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

 

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

 

5、变量(variable)

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

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

-var (ES3)

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

-let (ES6)

-const (ES6) 建立的是常量

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

-class (ES6) 基于ES6建立类

 

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

- 严格区分大小写

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

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

 

6、数据类型

数据值是一门编程语言进行生产的材料,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;

 

 

 

 

 

 

 

 

 

 

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目标对象,{代理方法});

 

 

相关文章
相关标签/搜索