# 基础知识

# 起步入门

"有姜小鱼带着你,一起学好这门编程语言",然后带着大家一起找轮子。。。下一个改变世界的就只你🤭

# 语言介绍

JavaScript 官方名称是ECMAScript 是一种属于网络的脚本语言,已经被广泛用户鱼web应用开发,常用来为网页添加各式各样的动态的功能,为用户提供跟流畅美观的浏览器效果。

1995年2月 Netscape布兰登.艾奇开发了针对网景公司的Netscape Navigator浏览器的脚本语言 LiveScipt。之后 Netscape 与Sun Netscape 公司联盟LiceScript 更名为 javaScript.

微软在javaScript发布后为了抢占市场推出 JSscript。为了让脚本语言规范不在混乱, 根据javaScript 1.1版本推出了 ECMA-262的脚本语言标准

ECMA 是欧洲计算机制造商协会有 Sun, 微软, NetScape 公司的程序员组成

"文档中会经常使用 JS 简写来代替 JavaScript"

# 使用场景

  • 浏览器网页端开发
  • 做为服务器厚底啊语言使用Node.js
  • 移动端手机APP 开发, 如Facebook 的 React Natve uniapp,phoneGap,IONIC
  • 跨平台的左面应用程序, 如使用electronjs

"所以 JS 是一专多能的语言,非常是适合学习使用的。"

# 发展历史

  • 994 年 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 版本

# 兼容性

下面是 ES6 兼容性状况 你也可以在网站查看 (opens new window)

1

# 学习准备

# 浏览器

本套教程会讲到新的 JS 知识, 所以请使用 chromefirefox 浏览器来进行学习

# 编辑器

推荐使用 vscodeWebStrom 编辑器开始开发,你可能需要一些插件才可以高效使用,后面我们团队专门出一片需要用的那些插件开心, 这个是下载地址

  1. Vscode (opens new window)

  2. WebStrom (opens new window)

本人是这里使用JeBrains公司WebStrom来进行开发的。只是编辑器不同我相信大家很快都能上手的,加油,加油学习是你快乐

补充一点,本人是的Toolboox这是继承了Jetbrains公司里面的开发的编辑器的,极度推荐使用这个,我想到的是大家都是初学则,你们可以使用的Vscode也是可以的😊

# 运行流程

所有内容需要在特定的运行环境中运行,就像PSD需要在类似PS的软件处理一样。浏览器内容了处理的JS的解析器, 但不同浏览器的性能不同,所有JS一般都在浏览器中执行,当然也有可以在服务器后台执行的JS解析器。

JS请求处理步骤如下:

3

# 脚本定义

# 内嵌脚本

像style标签一样, 可以在html文档中使用 script标签迁入 javaScript代码

<script>
	alert('姜小鱼')
</script>

# 外部文件

通过设置 src 属性引入外部js文件

<script src="demo.js"></script>

引入外部文件在标签体内的脚本不会执行,下面的alert弹窗是不会执行的

<script src="demo.js">
	alert('姜小鱼')
</script>

# 避免延迟

# 延迟体验

<html>
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>demo</title>
    <script src="demo.js">
    </script>
</head>
<body>
    <h1>demo.com</h1>
</body>
</html>

Demo.js内容如下

alert('姜小鱼')

h1会在demo.js文件加载并解析后才会显示

# 推荐做法

为了解决上面的问题,可以将js放在

标签前如下所示

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>demo</title>
</head>

<body>
    <h1>demo.com</h1>
    <script src="demo.js">
    </script>
</body>

# 代码注释

和大部分语言使用的注释方式相仿,有单行和多行注释.

# 单行注释

<script>
	// 这个单行注释
</script>

# 多行注释

<script>
/*
这是多行注释体验
请关注姜小鱼的网站https://smallgingerfish.top/
*/
</script>

# 自动分号

使用分号表示一段指令的结束, 当没有输入分号是如果没有换行符JS 会自动添加分号,减少错误的发生。

  • 但推荐每个指令都以分号结束

  • 在使用构建工具是,不是用分号结束可能会造成异常

    let stat = true
    if(stat) {
      document.write('姜小鱼')
    }
    

# 变量声明

# 命名规则

JS中变量是弱类型可以保存所有类型的数据,及变量没有类型而值有类型。变量名以字母, $ 开始,后跟字母, 数字

let name = '姜小鱼'
let $ = 'demoa.js'

JS 语言关键字不能用来变量名, 比如true,if ,while, class等

let class = '姜小鱼'

# 变量声明

可以使用多种方式定义变量比如 var,let(后面作用域章节在讨论变量)

let name = '姜小鱼'

以上代码是声名和赋值的结合

let name;
name = '姜小鱼'

"变量的其他细节使用会在函数, 对象等章节中体验"

使用, 可以同时声明多个变量

let n = 2, f= 4;
console.log(f)

下面是演示了变量可以更换不同类型的数据

let name = '姜小鱼';
console.log(typeof name);

name = 21;
console.log(typeof name);

# 若类型

在JS 中 变量类型由所引用的纸决定

var web = '管理系统';
console.log(typeof web) // string
web = 99;
console.log(typeof web) // number
web = {}
console.log(typeof web) // object

# 变量提升

解析器会先解析代码, 然后把声明的变量的声明提升到最高, 这就叫做变量提升。

下面代码在解析过程中发现的while 不能做为变量名, 没有到执行环节就出错了,这是一个很好的解析过程的体验.

var web = '姜小鱼'
console.log(web)
let while = 'demo'  // Uncaught SyntaxError: Unexpected token 'while'

使用var 声明代码会被提升到前面

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

// 以上代码解析执行过程
var a;
console.log(a) // 1
a = 1;
console.log(a) // 1

下面是 if(false)中定义的var 也会发生变量提升, 注释 if结果也会不同

var web = '架构';
function add(){
  if(false) {
    var web = "姜小鱼";
  }
 	console.log(web)
}
add()

使用var 定义的代码, 声明会被提升到前面,赋值还在原位置

console.log(name);
var name = '姜小鱼';

// 以上代码解析器窒息过程如下
var name;
console.log(name);
name = '姜小鱼'

# TDZ

TDZ 又称暂时性死区, 指变量在作用域内以及存在, 但必须在 let/const 声明后才可以使用。

TDZ 可以让程序保存先声明后使用的习惯, 让程序更稳定.

  • 变量要先声明后使用
  • 建议使用 let/const 而少使用 var

使用 let/const 声明的变量在声明前存在临时性死区 (TDZ) 使用会发生错误

console.log(x) // Cannot access 'x' before initialization
let x = 1

run 函数作用域中产生 TDZ, 不允许变量为声明前使用

var web = '架构';
function run(){
  if(false) {
    console.log(web)
    let web = "姜小鱼";
  }
 	console.log(web)
}
run()

下面代码b是没有声明赋值不允许直接被使用

function test(a = b, b = 3){} 
test() // Cannot access 'b' before initialization

因为a 已经赋值了,所以b可以使用a的变量, 下面的代码访问正常

function test(a = 2, b = a) {}
test()

# 块作用域

# 共同点

var/let/const共同点是全局作用域中定义的变量,可以在使用函数使用

var test = '小三';
function show() {
  return test;
}
console.log(show())

函数中声明的变量, 只能在函数及其子函数中使用

function test(){
  var web = "姜小鱼";
  
  
  function show () {
    console.log(web)
  }
  show() // 子函数结果, 姜小鱼
  console.log(web) // 函数结果: 姜小鱼
}
test()
console.log(web) // 全局访问: test is not defined

函数中声明的变量就像声明了私有领地, 外部无法访问

var web = '小月';
function show() {
  var web = "姜小鱼" // 姜小鱼
}
show()
console.log(web)// 打印结果,小月

# var

使用 var 声明的变量存在于最近的函数或者全局作用域中, 没有块级作用域的机制

没有块作用域很容易污染全局, 下面函数中的变量污染了全局环境

function run() {
  web = "姜小鱼"
}
run()
console.log(web) // 这里打印的结果是: 姜小鱼

没有块作用域时 var 也会污染全局

for(var i = 1; i < 10; i++) {
  console.log(i)
}

console.log(i)

使用 let 有块作用域时则不会

let i = 100;
for(let i = 0; i < 6; i++) {
  console.log(i)
}
console.log(i)

下列中体验到 var 没有块作用域概念, do/while 定义的变量可以在块外部访问到

var num = 0;

function show () {
  var step = 10;
  do {
    var res = 0;
    console.log(num = step++)
    res = num;
  } while (step < 20) 
    console.log(`结果是${res}`)
}
show();

var 全局声明的变量也存在于 windows 对象中

var name = "姜小鱼";
console.log(window.name); // 输出结果是 姜小鱼

以往没有块任何使用立即执行函数模拟块作用域

(function() {
  var $ = this.$ = {};
  $.web = "姜小鱼";
}.bind(window)())
console.log($.web)

有了块作用域后实现就变得简单多了

{
  let $ = (window.$ = {})
  $.web = "姜小鱼";
}
console.log($.web)

# let

var 声明的区别是 let/const 拥有块作用域, 下面代码演示了块外部是无法访问到了他声明的变量.

  • 建议将 let 在代码块钱声明
  • 用逗号分隔定义了多个

let 存在块作用域的特性. 变量之在块域中有效

if(true){
  let web = 'zhangsan', url = 'lisi'
  console.log(web) // 输出结果: zhangsan
}
console.log(web) // web is not defined

块内部是可以访问到上层的作用域的变量

if(true) {
  let user = '张三';
  (function() {
    if(true) {
      console.log(`这是块内访问:${user}`)
    }
  })()
}
console.log(user)

每一层都是独立的作用域,里层作用域可以声明外层作用域同名变量,但不会改变外层变量

function run() {
  name = '王五';
  if(true) {
    let name = "李四";
    console.log(name) // 李四
  }
  console.log(name) // 王五
}
run()

# const

使用 const 用来声明常量, 这与其他语言其他差别不大, 比如可以用来声明后台接口的URL地址

  • 常量名建议全部大写
  • 只能声明一次变量
  • 声明是必须同时赋值
  • 不允许再次在全新赋值
  • 可以修改应用类型变量的值
  • 用有块,函数, 全局作用域

常量不允许全新赋值举例

try{
	const URL = 'https://smallgingerfish.top/'
  URL = 'https://smallgingerfish.top/'
} catch(error) {
	throw new Error(error)
}

改变常量的引用类型值

const INFO = {
  url = 'https://smallgingerfish.top'
  port = '8080'
};
INFO.port = '443';
console.log(INFO)

下面演示了在不同作用域中可以重名定义常量

const NAME = '极客笔记'

function show () {
  const NAME = '姜小鱼';
  return NAME;
}
console.log(show())
console.log(NAME)

# 重复定义

使用var 可能造成不小心定义了同名变量

// 优惠价
var price = 90;
// 商品价格
var price = 100;
console.log(`商品优惠价格是:${price}`)

使用 let 可以避免上面的问题, 因为let 声明后的变量不允许在统一作用域中重新声明

let web = '极客笔记'
let web = '姜小鱼' // Identifirer 'web' hs already been declared

不同作用域可以重新声明

let web = 'https://smallgingerfish.top/'
if(true) {
  let web = '姜小鱼' // Identifirer 'web' hs already been declared
}

但可以改变值这是鱼const 不同先

let price = 90;
price = 88;
console.log(`商品价格是:${price}`);

let 全局声明的变量不存在于 window 对象中,这与 var 声明不同

let hd = "即刻笔记";
console.log(window.hd); //undefined

# Object.freeze

如果冻结变量之后, 变量也不可以修改了, 使用严格模式会报出错误

"use strict"
const INFO = {
  url: 'https://smallgingerfish.top/'
  port: '8080'
};

Object.freeze(INFO);
INFO.prot = '443' // Cannot assgin to read only property
console.log(INFO)

# 传值与传址

基本数据类型指数值, 字符串等简单数据类型,应用类型指对象数据类型

"类型的详细介绍在后面章节讲解"

基本类型复制是值的复制, 互相不受影响.下例中将 a 变量的值赋值给 b 变量后,因为基本类型变量是独立的所以 a 的改变不会影响 b 变量的值。

let a = 100;
let b = a;
a = 300;
console.log(b)

对于应用类型的讲, 变量保存的是引用对象的指针. 变量间赋值时其实变量的指针,这样多个变量就是应用的同一个对象

let a = {
  web: '姜小鱼'
};
let b = a;
a.web = "small";
console.log(b)

# undefined

对声明但为赋值的变量返回类型为undefined表示值为定义

let sm;
console.log(typeof sm)

对未声明的变量使用报错, 但判断类型将显示undefined会出这个错误sm is not deifndat 1.html52

console.log(tyeof sm);
console.log(sm)

我们发现未赋值与未定义的变量值都为 undefined ,建议声明变量设置初始值,这样就可以区分出变量状态了。

function demo(web) {
  console.log(web) // undefined
  return web;
}
consoloe.log(demo()) // undefined

# null

null 用于定一个空对象,即如果变量要用来保存引用类型, 可以子啊初始化时将器设置为null

var sm = null;
console.log(tyeof sm);

# 严格模式

严格模式可以让我们及早发现错误,使代码更安全规范,推荐在代码中一直保持严格模式运行

"主流框架都采用严格模式,严格模式也是未来JS 标准,所以建议代码使用严格模式开发"

# 基本差异

变量必须使用关键词, 未声明的变量不允许赋值

"use strcit"
url = 'sm' // url is not defined

强制声明防止污染全局

"use strcit"
function demo () {
  web = 'sm';
}
demo()
console.log(web) // sm

关键词不允许做变量使用

"use strcit"
var public = '姜小鱼'

变量参数不能允许重复定义

"use strcit"
// 不允许参数重名
function dem(name name){}

单独为函数设置严格模式

function strict() {
  "use strcit"
  return "严格模式"
}

function notStrict(){
  return "正常模式"
}

为了在对文件合并时, 防止全局设置严格模式对其他没有使用严格模式文件的额影响,将脚本放在一个执行函数中

(function () {
  "use strict"
  url = 'demo'
})()

# 结构模式

非严格模式可以不使用声明指令,严格模式下必须使用声明,所以建议使用 let 等声明

// "use strict"
({name_url} = {name: '姜小鱼', url: 'sm'})
console.log(name, url)

"使用严格模式编码总是推荐的"