前言
其实我个人认为JavaScript
是一种非常随便的语言,也是一门很神奇很强大的语言。
因为之前使用过一段时间的JavaScript
并做了些学习笔记都是放在word
上的显得十分杂乱,所以这次也是打算认认真真的重新填一下坑并且认真整理一下JavaScript
笔记到博客园。
以前在群里聊JavaScript
的时候会经常出现一张图,我认为这个很有意思,所以就放在这里做一个填坑目标吧。
我还是希望将整个的笔记好好整理一下,并且以一种文档格式进行书写,也方便后期查阅。
理论知识
语言介绍
JavaScript
官方名称是 ECMAScript
是一种属于网络的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果。
1995年2月Netscape的布兰登.艾奇
开发了针对网景公司的 Netscape Navigator
浏览器的脚本语言LiveScript
。之后Netscape与Sun公司联盟后LiveScript
更名为JavaScript
。
微软在JavaScript
发布后为了抢占市场推出了JavaScript
。为了让脚本语言规范不在混乱,根据JavaScript 1.1
版本推出了ECMA-262
的脚本语言标准。
ECMA是欧洲计算机制造商协会由Sum、微软、NetScape公司的程序员组成。
文档中会经常使用
JS
简写来代替JavaScript
Ps:其实整个JavaScript
最早的开发周期只用了两周,所以在未来很长一段时间里JavaScript
的语法非常混乱,但是随着时间的更迭慢慢的越来越完善起来。
适用场景
-
浏览器网页端开发
-
做为服务器后台语言使用
-
移动端手机APP开发,如Facebook的
-
跨平台的桌面应用程序,如使用
所以
JS
是一专多能的语言,非常适合学习使用。
发展历史
-
1994年Netscape(网景)公司发布了
Navigator
浏览器1.0版本,市场占用率超过90% -
1995年发布了
JavaScript
语言 -
1996年 JS在
Navigator
浏览器中使用 -
1996年微软发布
JScript
在IE3.0中使用 -
1996年11月网景公司将JS提交给ECMA(国际标准化组织)成为国际标准,用于对抗微软。
由ECMA的第39号技术专家委员会(Technical Committee 39,简称TC39)负责制订ECMAScript标准,成员包括Microsoft、Mozilla、Google等大公司。
-
1997年 ECMA发布ECMA-262标准,推出浏览器标准语言
ECMAScript 1.0
ECMAScript 是标准而Javascript是实现
-
...
-
2009年ECMAScript 5.0发布
-
2011年ECMAScript5.1发布,成为ISO国际标准,从而推动所有浏览器都支持
-
...
-
2015年ECMAScript6发布,更名为ECMAScript 2015。
-
2016年ECMAScript7发布,ECMAScript2016
-
2017年ECMAScript8发布,ECMAScript2017
-
2018年ECMAScript9发布,ECMAScript2018
-
2019年ECMAScript10,ECMAScript2019
-
2020年ECMAScript11,ECMAScript2020
-
....
从2015年开始 tc39
委员会决定每年发布新的ECMAScript版本
chrome使用
在学习Js
的过程中,推荐使用chrome
浏览器作为你的开发工具。
引入方式
嵌入式
在HTML
文档中使用标签,在
标签中嵌入
Js
代码即可,关于type
什么的文档类型声明可写可不写。
使用这种在方式最好是将Js
代码写在尾部。也就是写在HTML
与CSS
代码之后。
这种做法是因为如果我们的Js
代码需要去查找某一标签而将其放在头部的话HTML
的代码可能还没有加载出来,会出现一些不稳定的特殊情况。
我个人是非常喜欢夹在标签后的...
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
body>
<script>
console.log("hello,world"); // hello,world
script>
html>
引入式
同样的,也是使用标签,并为其
src
属性指定好Js
文件路径即可,关于type
什么的文档类型声明可写可不写。
还是推荐将它放在尾部,但是也有很多是放在标签中的。
<script src="./first_js.js" type="application/x-javascript">script>
代码注释
在Js
中的注释有两种,一种单行注释,一种多行注释。
单行注释
使用//
放在语句前,即可完成单行注释。
<script> // 下面是个自执行函数 (function (){ console.log("hello,world"); })() script>
多行注释
使用/*
开头,*/
结束,可包含多行。
<script> /* 下面是个自执行函数 它没有参数 */ (function (){ console.log("hello,world"); })() script>
自动分号
自动分号
在一段语句结束后,应当加上;
号,但是这并不是强制性的而是一种规范。
<script> (function (){ console.log("hello,world"); alert("hello,world"); document.write("hello,world"); })(); script>
意义作用
尽管你可以不加,但是请注意前端的代码一般来说在上线部署后都会进行压缩。
在使用构建工具时,不使用分号结束可能会造成异常!
我们可以看一下一个非常常见的Js
库jQuery
的生产版源码。
变量声明
变量就是存储着一个允许变的值。
如年龄,爱好,居住地等都可以定义为变量。
变量的使用都是先声明后使用,这个应该是非常基础的,在每个语言中都是这样。
那么在JavaScript
中关于变量声明有很多有意思的点,可以慢慢往下看。
命名规则
Js
中的变量是弱类型可以保存所有类型的数据,即变量没有类型而值有类型。变量名以字母
、$
、_
开始,后跟字母
、数字
、_
。
Js
中的语言关键字不能用来做变量名,比如 true、if、while、class
等。
请不要轻易使用用
$
来作为变量名的起始,因为它被jQuery
给霸占了,目前请谨记这一点。
正确的命名规范
<script> var username = "Yunya"; var _age = 18; var $select = "Please do not use $ to start variable names lightly, although it is not wrong"; script>
错误的命名规范
<script> var 9username = "ERROR"; var (age = "ERROR"; var --select = "ERROR"; script>
声明赋值
早期的Js
使用者都同一用var
来声明变量,但是es6
后推出了let
,具体的作用我们这里先不管。先看一下最基本的使用,由于Js
是一门弱类型语言,所以不用强调变量声明的类型。
先声明并赋值,后使用。
<script> // 先声明并且赋值 var username = "YunYa"; let age = 18; // 后使用 console.log(username); // YunYa console.log(age); // 18 script>
上面是最常用的方式,其实也可以先声明,再赋值,后使用。
<script> // 先声明 var username; let age; // 再赋值 username = "YunYa"; age = 18; // 后使用 console.log(username); // YunYa console.log(age); // 18 script>
我们还可以一次性声明赋值多个变量。
<script> var username = "YunYa", age = 18, gender = "male"; console.log(username); // YunYa console.log(age); // 18 console.log(gender); // male script>
也可以进行链式赋值。
<script> var a=b=c=1; console.log(a); // 1 console.log(b); // 1 console.log(c); // 1 script>
弱类型
弱类型其实就是说存的是什么类型的值,就是什么类型的变量。
不用提前声明变量变量再进行存储。
<script> var username = "YunYa"; var age = 18; var other = {"hobby":"basketball","marriage":false,"height":192,"weight":126,}; // typeof 是查看变量的类型方法 console.log(typeof username); // string console.log(typeof age); // number console.log(typeof other); // object script>
常量声明
常量存储一些不允许被改变的值。
如PI
,性别,籍贯等等都可以定义为常量。
命名规则
常量的命名规则和变量基本一致,但是一定要注意!常量的命名规则是全部大写形式,这是一种规范。
常量名建议全部大写
只能声明一次变量
声明时必须同时赋值
不允许再次全新赋值
可以修改引用类型变量的值
拥有块、函数、全局作用域
<script> // 常量声明全用大写 const PI = 3.1415926535897; console.log(PI); // 3.1415926535897 script>
声明赋值
常量我们一般都会使用const
来进行声明并赋值,它有一个特点,即声明之后不允许改变。
<script> // 常量声明全用大写 const PI = 3.1415926535897; PI = 100; console.log(PI); // Uncaught TypeError: Assignment to constant variable. // 类型错误: 将值分配给了一个不变的变量(常量) script>
var let const 区别
意义作用
不使用他们会全部乱套,因为有不同的作用域存在,如果不使用他们则代表将所有的变量全部放进全局作用域中。
代码及易出现问题!
<script> username = "YunYa"; function test(params) { console.log(username); // YunYa username = "Jack"; console.log(username); // Jack }; test(); // 可以看到,被污染了.. console.log(username); // Jack script>
<script> var username = "YunYa"; function test(params) { console.log(username); // undefined 这是因为自身局部作用域有一个 username,但是此时还未定义。所以不去找全局的name了,只好显示undefined。 var username = "Jack"; console.log(username); // Jack }; test(); // 可以看到,未污染了.. console.log(username); // YunYa script>
变量提升
变量提升其实你可以将它当做是预加载,它会预先来检查所有声明的变量名字是否合法。
<script> console.log("执行我了..."); // 没执行 let for = "YunYa"; // Uncaught SyntaxError: Unexpected token 'for' console.log("执行我了..."); // 没执行 script>
很明显的看到,代码都没执行,但是却抛出异常。这是预加载做的第一步事情,检查名称是否合法。
当预加载第一步执行完毕后,开始做第二步事情,对var
声明的变量进行开辟内存空间(注意:是开辟内存空间,并未赋值,并且let
与const
声明的变量都不会开辟内存空间)。
也就是说,当Js
代码开始运行时,检查完变量名是否合法后,它会预先拿到所有var
声明的变量名的名字(函数名也会),但并不会进行赋值。
只有当真正开始执行代码并且走到赋值代码时才会进行赋值操作,所以你可以看到下面的这种情况。
<script> // 为什么没抛出异常? console.log(username) // undefined var username = "YunYa"; script>
如果使用一个未被定义的函数,那么才是真正的会抛出异常。
<script> console.log(age) // Uncaught ReferenceError: age is not defined var username = "YunYa"; script>
TDZ暂时性死区
TDZ
又称暂时性死区,指变量在作用域内已经存在,但必须在let/const
声明后才可以使用。
TDZ
可以让程序保持先声明后使用的习惯,让程序更稳定。
变量要先声明后使用
建议使用
let
/const
而少使用var
使用let/const
声明的变量在声明前存在临时性死区(TDZ
)使用会发生错误。
其实说白了就是let
和const
来声明的变量必须遵守先声明后使用的原则。
<script> // 意思就说,不能在完成之前访问name这个变量 console.log(username) // Uncaught ReferenceError: Cannot access 'name' before initialization let username = "YunYa"; script>
<script> // 意思就说,不能在完成之前访问name这个变量 console.log(username) // Uncaught ReferenceError: Cannot access 'username' before initialization const username = "YunYa"; script>
块作用域
作用域你可以简单的理解为,只要有{}
括起来的地方全是作用域,它的作用就是让相同名字的变量名之间互不冲突。
作用域 | |
---|---|
全局作用域 | 变量名全局有效。 |
局部作用域 | 隶属于全局作用域之下,变量名在函数,类中有效,可访问全局作用域中的变量。 |
块作用域 | 隶属于全局作用域之下,对于var 来说不存在,对于let 来说则存在,常见for 循环,通俗讲只要有不是局部作用域和全局作用域而被{} 包裹的代码块全部称为块作用域。 |
注意:let
与const
都具有块作用域,而var
则不具有。
下面例子使用var
则会造成污染(会当成全局作用域来看待,不具有块作用域),而使用let
则不会(const
不可多次赋值应用)。
<script> var i = 100; for(var i = 0;i < 5;i++){ console.log(i); // 0 1 2 3 4 } // 此时我们在想用 100 的那个 i 抱歉,被替换了。 console.log(i); // 5 >
<script> let i = 100; for(let i = 0;i < 5;i++){ console.log(i); // 0 1 2 3 4 } // 未替换。 console.log(i); // 100 >
重复定义
在同一作用域下,使用var
定义的变量名可重复定义,而let
与const
则不可重复定义。
var
<script> var num = 100; var num = 1000; // 明显不太好 console.log(num); // 1000 script>
let
<script> // Uncaught SyntaxError: Identifier 'num' has already been declared // 语法错误 num 已经被定义 let num = 100; let num = 1000; console.log(num); script>
const
<script> // Uncaught SyntaxError: Identifier 'num' has already been declared // 语法错误 num 已经被定义 const num = 100; const num = 1000; console.log(num); // 1000 script>
windows对象
使用var
定义的变量会被存入windows
对象,而let
与const
却不会。
var
<script> var username = "YunYa"; console.log(window["username"]); // YunYa script>
let
<script> let username = "YunYa"; console.log(window["username"]); // undefined script>
const
<script> const username = "YunYa"; console.log(window["username"]); // undefined script>
差异总结
var let const区别 | |||
---|---|---|---|
var | let | const | |
变量提升 | 有 | 无 | 无 |
TDZ暂时性死区 | 无 | 有 | 有 |
块作用域 | 无 | 有 | 有 |
同一作用域下重复定义 | 允许 | 不允许 | 不允许 |
windows对象 | 添加 | 不添加 | 不添加 |
总结:尽量少使用var 多使用let 。 |
严格模式
严格模式可以让我们及早发现错误,使代码更安全规范,推荐在代码中一直保持严格模式运行。
只需要在书写代码前加上"use strict";
即可。
主流框架都采用严格模式,严格模式也是未来JS标准,所以建议代码使用严格模式开发
基本差异
变量必须使用关键词声明,未声明的变量不允许赋值。
<script> // Uncaught ReferenceError: username is not defined "use strict"; username = "YunYa"; console.log(username); script>
关键词不允许做变量使用
<script> // Uncaught SyntaxError: Unexpected token 'try' "use strict"; var try = "YunYa"; console.log(username); script>
变量参数不允许重复定义
<script> // Uncaught SyntaxError: Duplicate parameter name not allowed in this context "use strict"; function test(x,x){ console.log("执行了..."); }; test(); script>
单独为函数设置严格模式
<script> function test(){ "use strict"; console.log("执行了..."); // 执行了... }; test(); script>
为了在多文件合并时,防止全局设置严格模式对其他没使用严格模式文件的影响,将脚本放在一个执行函数中。
<script> (function (param) { "use strict"; let url = "www.google.com"; console.log(url); })(); script>
解构差异
非严格模式可以不使用声明指令,严格模式下必须使用声明。所以建议使用 let
等声明。
<script> // "use strict"; // 在严格模式下不允许这样使用 ({ name, other } = { "name":"YunYa-cnblogs","other":"good" }); console.log(name, other); // YunYa-cnblogs good script>