JavaScript是什么
-
JavaScript是 动态类型、弱类型、基于原型 的 客户端脚本语言。
-
JavaScript由以下三部分组成:
- ECMAScript (核心):规定语言的组成部分:语法、类型、语句、关键字、保留字、操作符、对象等。ECMAScript是JavaScript语言的国际标准,JavaScript是ECMAScript的实现(即也可以有其他语言来实现ECMAScript标准)。
- DOM (文档对象模型 Document Object Model):HTML DOM 是关于如何获取、更改、添加或删除 HTML 元素的标准。
- BOM (浏览器对象模型 Browser Object Model):允许JavaScript与浏览器对话(window对象)。
ECMA2015(ES6)
作用域
-
在 ES6 之前,JavaScript 只有两种作用域: 全局变量 与 函数内的局部变量。
// 使用 var 关键字声明的变量不具备块级作用域的特性,它在 {} 外依然能被访问到。 { var x = 2; } // 这里可以使用 x 变量- ES6之前真的没有块级作用域吗?
- 别高估自己,这道题,有点难!
- (34条消息) 一道面试题告诉了我函数在块级作用域中的提升并没有那么简单_CS_DGD的博客-CSDN博客
- ES6中:块级作用域中声明的函数,只会提升其声明部分,不分配实际的内存空间。即将var a声明提升到全局作用域,而function a(){}提升到块级作用域中的最前面。且块级作用域中真正声明函数时,会将当前自身的值同步给外部 window。
- catch块捕获的异常只在catch块中可见,但是catch块中定义的其他变量还是属于整个函数作用域的。
- 研究js的块级作用域中的变量声明和函数声明 - 掘金 (juejin.cn)
- 块级作用域内的变量声明不会提升到全局作用域的顶层。
- 未用var声明的变量,在执行后,会将该变量添加到全局环境。即在块内的默认变量没执行之前不可以访问这个变量。
console.log(a); // ReferenceError: a is not defined { a = 1; } console.log(a); // 1
- ES6之前真的没有块级作用域吗?
-
在浏览器环境中, 全局作用域是针对 window 对象。
- 使用 var 关键字声明的全局作用域变量属于 window 对象。即可以使用 window.xxx 访问变量。
- 使用 let 关键字声明的全局作用域变量不属于 window 对象。
- 在node中顶层对象指的是 global 对象。
-
块级作用域
- ES6 可以使用 let 关键字来实现块级作用域。let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问。
{ let x = 2; } // 这里不能使用 x 变量 - 块 (语法块)
{} if(){} for(){}
- ES6 可以使用 let 关键字来实现块级作用域。let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问。
-
如何在ES5环境下实现let
通过自执行函数来模拟块级作用域
变量
-
为什么浏览器控制台分次用let或const声明,不报错?
- Chrome DevTools 的 Feature google chrome devtools - The strange behavior of let and var in Javascript - Stack Overflow
-
let a; let a; // One script: redeclaration error let b let b // Separate evaluations: OK, no error
-
变量提升
- 变量提升 只提升变量的声明,不提升赋值
// eg1: var a = 1; var b = 2; // 实际为: var a,b; a = 1; b = 2; // eg2: var v='Hello World'; (function(){ alert(v); // v is undefined var v='I love you'; })() - 函数声明形式可以提升函数,函数表达式方式不能提升。
- 函数提升优先于变量提升。
- let不会变量提升,即变量必须在声明后使用,否则报错ReferenceError。
- 变量提升 只提升变量的声明,不提升赋值
-
暂时性死区
- ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。即在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
- 暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
if (true) { // TDZ开始 tmp = 'abc'; // ReferenceError console.log(tmp); // ReferenceError let tmp; // TDZ结束 console.log(tmp); // undefined tmp = 123; console.log(tmp); // 123 } - [ES6]什么是变量提升和暂时性死区 - 简书 (jianshu.com)
-
let
- let不允许在相同作用域中重复声明。
-
const
- const声明的常量不能改变值,即声明时必须初始化。
const a; // SyntaxError - const并非真正的常量。const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
// 创建常量对象 const car = {type:"Fiat", model:"500", color:"white"}; // 修改属性: car.color = "red"; // √ // 添加属性 car.owner = "Johnson"; // √ //可以使用Object.freeze()方法来 冻结变量 const obj = { name:"1024kb" } Object.freeze(obj) // 此时对象obj被冻结,返回被冻结的对象 // 若对象的属性仍是引用类型,则对象的属性也需要被冻结才可 // 实现Object.freeze() function myFreeze(obj){ if(obj instanceof Object){ Object.seal(obj); // 封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置 let p; for (p in obj) { if(obj.hasOwnProperty(p)){ Object.defineProperty(obj,p,{ writable: false }) } } } } - 如何在ES5环境下实现const?
使用Object.defineProperty()。这个API用于在一个对象上增加或修改属性。通过配置属性描述符,可以精确地控制属性行为。 function _const(key,value){ const desc = { value, writable:false } Object.defineProperty(window,key,desc) } _const('obj',{a:1}) obj = {} // Cannot redefine property: obj
。。。持续编辑中
- const声明的常量不能改变值,即声明时必须初始化。