ES5 和 ES6新增

2 篇文章 0 订阅

目录

1. ES6 - 定义变量

2. ES6 - 模板字符串

3. ES6 - 箭头函数

4. ES6 - 函数参数默认值

5. ES6 - 解构赋值

 面试案例 :

6. ES6 - 扩展运算符

7. ES6 - 对象简写语法

8. ES6 - 模块化开发

9. ES6 - 类语法

10. 图例 :


+ ECMAScript 发展过程中的一个版本
=> 官方: ES2015
=> 社区: ES6
+ ES6 和之后所有的内容在 IE 低版本不兼容

1. ES6 - 定义变量

ES2015(ES6) 新增加了两个重要的 JavaScript 关键字 : let 和 const 

let 声明的变量只在 let 命令所在的代码块内有效 ,

const 声明一个只读的常量,一旦声明,常量的值就不能改变 。

1. let       :  变量
2. const  :  常量

  1. let / const 和 var 的区别
    1-1. 预解析
      => 在预解析的过程中 var 定义的变量会被预解析, 可以先使用后定义
      => let / const 不会进行预解析, 必须先定义后使用

// 1-1. 预解析
console.log(num)		// undefined
var num = 100
console.log(num)		// 100
// let 定义变量,不会进行预解析
console.log(num)	// 会报错
let num = 100
console.log(num)
// const 定义变量,不会进行预解析
console.log(num)	// 会报错
const num = 100
console.log(num)


    1-2. 重复声明(变量重名)
      => 使用 var 可以定义两个一模一样的变量, 只是第二次定义没有意义, 赋值有意义
      => let / const 不允许在同一个作用域下, 定义重名变量

// 1-2. 重复声明
var n = 100
var n = 200
console.log(n)	// 200
let n2 = 200
let n2 = 300	// 报错 => Identifier 'n2' has already been declared

const n3 = 300
const n3 = 400	// 报错 => Identifier 'n3' has already been declared


    1-3. 块级作用域
      => var 没有块级作用域
      => let / const 有块级作用域
      => 块级作用域: 任何一个可以书写代码段的 { } 都会限制变量的使用范围

// 1-3. 块级作用域
if (true) {
  var num = 100
  console.log(num)	// 100
}
console.log(num)	// 100
if (true) {
  let num = 100
  console.log(num)	// 100
}
console.log(num)	// 报错 => num is not defined

if (true) {
  const num = 200
  console.log(num)
}
console.log(num)	// 报错 => num is not defined


  2. let 和 const 的区别
    2-1. 声明时赋值
      => let 在定义变量的时候, 可以不赋值
      => const 在定义变量的时候, 必须赋值

// 2-1. 赋值问题
let num
console.log(num)	// undefined
num = 200
console.log(num)	// 200
// 会报错, 初始化的时候必须赋值 ,不能定义常量不赋值
const n // 报错 => Missing initializer in const declaration


    2-2. 值的修改
      => let 定义的变量可以任意修改值内容
      => const 定义的值, 在定义时赋值, 一旦赋值不允许修改

// 2-2. 值的修改
let n = 100
console.log(n)		// 100
n = 'hello world'
console.log(n)		// hello world

const str = '我是定义时就写好的内容'
console.log(str)	// 我是定义时就写好的内容
// 当你试图修改一个 const 定义的常量
// 直接会报错, 因为 const 声明的常量不允许修改
str = 'hello world'

  

 for 循环计数器很适合用 let

for (var i = 0; i < 10; i++) {
  setTimeout(function(){
    console.log(i);
  })
}
// 输出十个 10
for (let j = 0; j < 10; j++) {
  setTimeout(function(){
    console.log(j);
  })
}
// 输出 0123456789

变量 i 是用 var 声明的,在全局范围内有效,所以全局中只有一个变量 i, 每次循环时,setTimeout 定时器里面的 i 指的是全局变量 i ,而循环里的十个 setTimeout 是在循环结束后才执行,所以此时的 i 都是 10。

变量 j 是用 let 声明的,当前的 j 只在本轮循环中有效,每次循环的 j 其实都是一个新的变量,所以 setTimeout 定时器里面的 j 其实是不同的变量,即最后输出 0123456789。(若每次循环的变量 j 都是重新声明的,如何知道前一个循环的值?这是因为 JavaScript 引擎内部会记住前一个循环的值)。 

注意要点 :

const 如何做到变量在声明初始化之后不允许改变的?其实 const 其实保证的不是变量的值不变,而是保证变量指向的 内存地址 所保存的数据不允许改动。此时,你可能已经想到,简单数据类型和复杂数据类型保存值的方式是不同的。是的,对于简单数据类型(数值 number、字符串 string 、布尔值 boolean),值就保存在变量指向的那个内存地址,因此 const 声明的简单数据类型变量等同于常量。而复杂数据类型(对象 Object,数组 Array,函数 Function),变量指向的内存地址其实是保存了一个指向实际数据的指针,所以 const 只能保证指针是固定的,至于指针指向的数据结构变不变就无法控制了,所以使用 const 声明复杂数据类型对象时要慎重。


2. ES6 - 模板字符串

+ ES6 新增了一种定义字符串的方式 => 模板字符串
模板字符串(template string)是增强版的字符串
+ 使用 反引号(` `) 来进行字符串的定义
+ 和 单引号(' ') 或者 双引号(" ") 定义的字符串没有区别, 使用上是一样的
+ 只是当你使用 反引号(` `) 定义的时候, 会有特殊的能力
模板字符串的特点:
  1. 可以换行书写字符串
  2. 可以直接在字符串内拼接解析变量
    => 当你需要解析变量的时候, 书写  ${ 变量 } 

  3. 可以调用函数
+ 注意:
  => ${ } 外面的空格是真实在字符串内的空格
  => ${ } 里面的空格是代码的空格, 和字符串没有关系

const s1 = 'hello world'
const s2 = "hello world"
const s3 = `hello world`
console.log(s1, typeof s1, s1.length, s1.slice(0, 5))
console.log(s2, typeof s2, s2.length, s2.slice(0, 5))
console.log(s3, typeof s3, s3.length, s3.slice(0, 5))
console.log(s1 === s2)		// true

// 特点1: 换行书写字符串
let str = `
  hello world
  你好 世界
`
console.log(str)
// 特点2: 解析变量
let age = 18
let arr = [ 100, 200, 300 ]
// 普通单引号( ' ' )
let s1 = '你好 我今年 ${ age } 岁了'
// ${ } 可以书写一个简单的表达式
let s2 = `你好 我今年 ${ arr.length ? arr[arr.length - 1] : 18 } 岁了`
console.log(s1)
console.log(s2)

 

// 特点 3 : 可以调用函数
function fn(a) {
  console.log(a); // (3) ["hello ", " world ", "", raw: Array(3)]
}
let num = 100
fn`hello ${ num } world ${ num }`
// ${} 会把字符串切割成数组, 并当成第一个参数

 

function fn(a, b, c) {
  console.log(a); // (3) ["hello ", " world ", "", raw: Array(3)]
  console.log(b); // 100
  console.log(c); // 200
}
let num1 = 100
let num2 = 200
fn`hello ${ num1 } world ${ num2 }`
// num1 就是该函数的第二个参数
// num2 就是该函数的第三个参数


3. ES6 - 箭头函数

箭头函数提供了一种更加简洁的函数书写方式。
+ ES6 语法中定义函数的一种方式
+ 只能用来定义函数表达式(赋值式函数/匿名函数)
  => 当你把函数当做一个值赋值给另一个内容的时候, 叫做 函数表达式
  => var xxx = function () {}
  => var obj = { xxx: function () {} }
  => xxx.onclick = function () {}
  => xxx.addEventListener('click', function () {})
  => xxx.forEach(function () {})
  => setTimeout(function () {}, 1000)
  => setInterval(function () {}, 1000)
  => ...
+ 注意: 声明式函数不行
  => function fn( ) { }
+ 箭头函数的语法:  ( ) => { } 
  -> ( ) 书写函数形参的位置
  -> => 是箭头函数的标志
  -> { } 函数的函数体 , 是书写代码段的位置

// 写一个箭头函数
const fn = function () { console.log('我是一个函数') }
const fun = () => { console.log('我也是一个函数') }
fn()
fun()

箭头函数 和 函数表达式的区别
1. 箭头函数内没有 arguments
  => 函数内一个伪数组, 是所有实参的集合
2. 箭头函数内没有 this
  => 官方: 箭头函数内的 this 是上下文(context) 的 this
  => 私人: 箭头函数外面的函数 this 是谁, 箭头函数内的 this 就是谁
箭头函数的特点:(不强制要求)
1. 可以省略小括号不写
  => 当你的形参有且只有一个的时候, 可以不写小括号
  => 如果你的形参没有或者两个及以上, 必须写小括号

// 1. 省略小括号
//没有形参, 小括号必须写
let fn1 = () => { console.log('我是 fn1 函数, 我没有形参') }
fn1()
// 一个形参, 可以不写小括号
let fn2 = a => { console.log('我是 fn2 函数, 有一个参数', a) }
fn2(10)
// 两个形参, 必须写小括号
let fn3 = (a, b) => { console.log('我是 fn3 函数, 有两个参数', a, b) }
fn3(100, 200)

2. 可以省略大括号不写
当你的代码有且只有一句话的时候, 可以省略大括号不写, 并且会自动返回这一句话的结果
否则, 必须写大括号

// 2. 省略大括号
// 这是一个箭头函数, 函数内只有一句代码, 是 a + b
// 这个函数的返回值, 就是 a + b 的结果
let fn1 = (a, b) => a + b
let res = fn1(10, 20)
console.log(res)	// 打印 => 30
// 简写过程
const arr = [ 1, 2, 3, 4, 5, 6, 7 ]
// var res = arr.filter(function (item) { return item % 2 })
// var res = arr.filter((item) => { return item % 2 })
// var res = arr.filter(item => { return item % 2 })
const res = arr.filter(item => item % 2)
console.log(res)    // 打印 => (4) [1, 3, 5, 7]

3. 箭头函数内没有 arguments
  => 箭头函数内天生不带有 arguments
  => 没有所有实参的集合

// 3. 没有 arguments
const fn1 = function () { console.log(arguments) }
fn1(10, 20, 30)
const fn2 = () => { console.log(arguments) }
fn2(10, 20, 30)


4. 箭头函数内没有 this
  => 官方: 外部作用域的 this
  => 私人: 书写在箭头函数的外面那个函数 this 是谁, 箭头函数内的 this 就是谁
  注意 : 不可以作为构造函数,也就是不能使用 new 命令,否则会报错

// 4. 箭头函数内没有 this
const obj = {
  name: '我是 obj 对象',
  f: function () {
	console.log('f : ', this)
  },
  f2: () => {
	// 这里没有 this, 用的是 外部的 this
	console.log('f2 : ', this)
  }
}
obj.f()
// 按说看调用方式, f2 内的 this 应该是 obj
// 因为 f2 是一个箭头函数, 所以该函数内没有 this
// this 使用的是上下文的 this
obj.f2()


4. ES6 - 函数参数默认值

+ 给函数的形参设置一个默认值, 当你没有传递实参的时候, 使用
+ 书写: 直接在书写形参的时候, 以 赋值符号( = ) 给形参赋值设置默认值就可以了
+ 任何函数都可以使用
+ 箭头函数也能设置参数默认值 :
=> 注意: 如果你给箭头函数设置参数默认值, 那么不管多少个形参
=> 都需要书写小括号

// 给形参 a 设置了默认值为 10
// 给形参 b 设置了默认值为 20
function fn(a = 10, b = 20) {
  console.log('fn 函数内的打印')
  console.log('a : ', a)
  console.log('b : ', b)
  console.log('---------------------')
}
// 箭头函数也可以设置默认值
const fn = (a = 10, b = 20) => {
  console.log('fn 函数内的打印')
  console.log('a : ', a)
  console.log('b : ', b)
  console.log('---------------------')
}
// 第一次调用
// 给 两个形参 赋值了, 那么就不使用默认值了
fn(100, 200)
// 第二次调用
// 没有给 b 赋值, 那么 b 就会使用 20 这个默认值
fn(1000)
// 第三次调用
// a 和 b 都没有实参进行赋值, 都会使用 默认值
fn()

// 范围内的随机数
// 定义函数, 两个数字分别默认值设置成 0 和 255
const randomNum = (a = 255, b = 0) => Math.floor(Math.random() * (Math.abs(a - b) + 1)) + Math.min(a, b)
console.log(randomNum(10, 100))

5. ES6 - 解构赋值

解构赋值概述 :

解构赋值是对赋值运算符的扩展。

它是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。

解构模型 : 

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为 解 构(Destructuring)。

在解构中,有下面两部分参与:

解构的源,解构赋值表达式的右边部分;

解构目标,解构赋值表达式的左边部分;

+ 目的: 快速从 对象 或者 数组 中获取一些数据
+ 分成两类
1. 解构数组
2. 解构对象

const arr = [10, 20, 30]
// 需求: 单独定义三个变量获取三个数据
// 原先的方式, 不够方便
const n1 = arr[0]
const n2 = arr[1]
const n3 = arr[2]

1. 解构数组
+ 快速从数组中获取一些数据
+ 注意: 使用  [ ]  解构数组
+ 语法: const [ 变量1, 变量2, 变量3, ... ] = 数组
  => 按照数组的索引依次给 解构 内的 变量进行赋值

// 1. 使用解构数组来获取
// n1 就获取 arr 中 [0] 位置的数据
// n2 就获取 arr 中 [1] 位置的数据
// n3 就获取 arr 中 [2] 位置的数据
const [ n1, n2, n3 ] = arr
console.log(n1, n2, n3)	    // 打印 => 100 200 300

+ 扩展: 多维数组的解构
  => 原先数组长什么样, 解构就长什么样
  -> 数组怎么写, 解构怎么写
  -> 把数据替换成变量

// 扩展 : 多维数组的解构
const arr = [1, 2, [3, 4, [5, 6, [7, 8, [9, [10]]]]]]
console.log(arr)    // (3) [1, 2, Array(3)]
// 需求: 定义变量拿到 9 这个数据
const a = arr[2][2][2][2][0]
console.log(a)    // 9
// 解构:
	  const [a, b, [c, d, [e, f, [g, h, [i, [j]]]]]] = arr
console.log(i)                       //  9

// 2. 解构对象
const obj = { name: 'Jack', age: 18, gender: '男' }
// 以前
const name = obj.name
const age = obj.age
const gender = obj.gender
console.log(name, age, gender)	// Jack  18  男

2. 解构对象
+ 快速从对象内获取一些数据
+ 注意: 解构对象使用  { } 
+ 语法: const { 键名1, 键名2, 键名3, ... } = 对象
 => 按照键名, 依次定义变量从对象中获取指定成员

// 解构
const { name, age, gender } = obj
console.log(name, age, gender)	// Jack  18  男

=> 解构的时候起一个 别名
+ 别名: const { 键名: 别名, 键名2: 别名 } = 对象
-> 注意: 当你起了别名以后, 原先的键名不能在当做变量名使用了, 需要使用这个别名

// 2-2. 解构的时候起一个别名
const obj = { name: 'Jack', age: 18, gender: '男' }
// const { name } = obj 等价于 const name = obj.name
// const { name: n } = obj 等价于 const n = obj.name
const { name: n, gender, age: a } = obj
console.log(n, gender, a)	// Jack  男  18

+ 扩展: 解构多维对象
  => 原先对象长什么样, 解构就长什么样, 数据替换成变量

// 扩展: 解构多维对象
const obj = {
  name: 'Jack',
  age: 18,
  info: {
	weight: 180,
	height: 180,
	data: {
	  desc: '这个人很懒, 什么都没有留下',
	  hobby: [ '吃饭', '睡觉' ]
	}
  }
}

// 我想拿到睡觉
// 解构
const {
  name: n,
  age,
  info: {
    weight: w,
    height: h,
    data: {
      desc,
      hobby: [ a, b ]
    }
  }
} = obj

console.log(h)	// 180
console.log(b)	// 睡觉

 面试案例 :

// 一号坑 :  

const obj = { name: 'Jack', age: 18, gender: '男' }
const { age: a } = obj
// 等价于执行 const a = obj.age
console.log(a)    // 18
console.log(age)  // 报错打印 => age is not defined
// 当你给一个数据起了别名之后, 原先这个键名就不能够再当做变量名使用了, 用的就是别名了
const obj = { name: 'Jack', age: 18, gender: '男' }
const { name: n } = obj
// 等价于 const n = obj.name
console.log(n)	 // Jack
console.log(name)// 不报错 => 空字符串( ' ' ), 因为 Window 中天生自带一个 name 属性
//唯独 name 可以单独使用,因为是 Window 天生自带了这么一个属性,且被锁定为 string 类型
name = 18 
console.log(typeof name)  // 打印 => string

  =>  


// 二号坑 : 

// const 定义的常量不能被修改
// obj 接受的值是一个 对象数据类型 的地址
// 什么情况下才叫做把 obj 的值修改, 更换地址
const obj = { name: 'Jack' }
//并没有修改 obj 的值, 而是把 obj 内空间内的值修改了
obj.name = 'Rose'
console.log(obj.name)	// Rose
//( 当你重新 const obj = { ...... } 时 ) 
//会报错 : Identifier 'obj' has already been declared( 标识符'obj'已经被声明 )

// 三号坑 :

for (var i = 0; i < 3; i++) {
  // 异步
  setTimeout(() => {
	console.log(i)		// 打印 => 三个 3
  }, 0)
}
/*
  全局定义变量 i

  开始循环
	i === 0
	  => 定义一个定时器, 定时器处理函数执行吗 ? => 不执行, 等同步代码都执行完才执行
	  => 向队列内放了一个函数 () => { console.log(i) }
	i === 1
	  => 定义一个定时器
	  => 向队列内放了一个函数 () => { console.log(i) }
	i === 2
	  => 定义一个定时器
	  => 向队列内放了一个函数 () => { console.log(i) }
	i === 3
	  循环结束

  此时所有同步代码执行完毕, 才会开始执行异步代码
	=> 直接执行队列内的三个函数
	=> 在控制台打印三次 i
*/

 // 三号坑 挖深 : 

// 块级作用域: 任何一个可以书写代码段的 { } 都会限制变量的使用范围
for (let i = 0; i < 3; i++) {
  // 异步
  setTimeout(() => {
	console.log(i)		// 打印 => 0  1  2
  }, 0)
}
/*
  打开页面

  循环开始 => 注意 : let 定义的变量会被 {  } 锁住
  {
	i === 0
	准备了一个定时器处理函数, 在队列内, () => console.log(i)
  }
  {
	i === 1
	准备了一个定时器处理函数, 在队列内, () => console.log(i)
  }
  {
	i === 2
	准备了一个定时器处理函数, 在队列内, () => console.log(i)
  }
  {
	i === 3
	循环结束
  }

  所有同步代码执行完毕, 开始执行异步代码    => 打印 0 1 2
*/

 // 三号坑 再 挖深 : 

for (let i = 0; i < 3; i++) {
  // 异步
  setTimeout(() => {
	console.log(i)	// 报错之后打印 => 0  1  2
  }, 0)
}
console.log(i) // 报错 => i is not defined
// 依旧会继续打印出 0  1  2
// 因为定时器的设置, 是在报错以前设置的

不是说报错就会中断程序的执行么 , 可为啥后面的代码还执行打印出来结果了呢 ?

因为 setTimeout 是你异步队列里面的代码 , 是在你报错之前就已经准备好要执行的代码

它只是从报错以后的代码不执行 , 但这一句是报错之前的代码 ,所以依旧会打印出 0 1 2

是因为定时器的设置是在报错以前设置的 , 浏览器会终结到报错之前 ,

把你所有准备好的代码都执行了

比如 : 我们可以把它想象成你指挥一个人 , 当这个人他做错了事 , 他就不再继续往下做事了 ,

在这里你跟他说 : 你去 定一个 闹钟 , 1 秒钟以后 响一下 , 再设置一个 , 1分钟后响 , 

然后这个人去接热水时 , 不小心把手给烫了 , 所以就没办法再办事了 ,

但是他已经把 闹钟 都设置好了 ,到时间就会响 , 所以跟他 能不能办事了就没有任何关系了


6. ES6 - 扩展运算符

+ 在 ES6 语法里面多了一个运算符
+ 展开合并运算符
+ 有两个意义
1. 展开 => 展开运算符 (...)
2. 合并 => 合并运算符 (...)
+ ...
  => 主要是操作 数组 和 对象 的运算符号
1. 展开运算符
=> 可以 展开对象, 或者 展开数组
=> 多用于数组
=> 当你使用在 数组 或者 对象 或者 函数实参位置 的时候叫做 展开运算 
=> 如果是展开对象, 就是去掉 对象 { } 
=> 如果是展开数组, 就是去掉 数组 [ ] 

// 1. 展开运算符
const arr = [ 100, 200, 300 ]
// 如果我想在控制台打印 100 200 300
console.log(arr)	// (3) [100, 200, 300]
console.log(100, 200, 300)// 100 200 300
console.log(...arr)	  // 100 200 300

const arr2 = [...arr, 400, 500]
console.log(arr2)	// (5) [100, 200, 300, 400, 500]

const res = Math.max(...arr)
console.log(res)	// 300
// 展开对象
const o1 = { name: 'Jack', age: 18 }
const o2 = {
  gender: '男',
  ...o1
}
const o3 = {
  ...o2,
  score: 200
}
console.log(o1, o2, o3)


2. 合并运算符
=> 用于合并多个数据使用
=> 当你使用在 解构数组 或者 函数的形参位置 的时候叫做 合并运算 
=> 当这个符号书写在 函数 形参 位置的时候, 叫做 合并运算符
=> 从当前形参位置开始获取实参, 直到末尾
=> 注意: 合并运算符一定要写在最后一位

// 2. 合并运算符
const arr = [ 100, 200, 300 ]
// 在解构中使用合并运算符
// 把 arr 中 [0] 赋值给 a
// 把 arr 中 [1] 开始到末尾的所有内容都赋值给 b, 以一个新数组的形式出现
// 注意: 合并运算符必须写在最后一个的位置
const [ a, ...b ] = arr
console.log(a)	// 100
console.log(b)	// (2) [200, 300]

// 在函数形参位置使用
// 把第一个实参赋值给 a
// 剩下的所有实参给到 b, 以一个新数组的形式出现
// 注意: 合并运算符必须写在最后一个的位置
function fn(a, ...b) {
  console.log(a)	// 100
  console.log(b)	// (2) [200, 300]
}
fn(100, 200, 300)
// 箭头函数有一个特点, 没有 arguments
// 我们可以使用 ... 合并出一个 arguments
const fn = (...arg) => {
  console.log(arg)
}
fn(10, 20, 30)	// (3) [10, 20, 30]

7. ES6 - 对象简写语法

ES6 - 对象简写语法(不强制要求)
1. 当 key 和 value 一模一样, 并且 value 是一个变量的时候
  => 可以省略 value 和 冒号( : ) 不写
2. 当某一个 key 的值是一个函数, 并且不是箭头函数的时候
  => 可以直接省略 function 关键字和 冒号( : ) 不写

// 1. key 和 value 一样
const day = 12
const hours = 23
const minutes = 33
const seconds = 25
const obj = {
  day, // 等价于你写了 day: day
  hours,
  minutes,
  seconds,
  // key 和 value 虽然一模一样
  // 但是 value 不是一个变量
  data: 'data'
}
console.log(obj)

// 2. 函数简写
const obj = {
  name: '我是 obj 对象',
  // f1 是一个函数, 但是不是箭头函数, 可以简写
  f1: function () { console.log(arguments) },
  // f2 虽然是一个函数, 但是是一个箭头函数, 不能简写了
  f2: () => { console.log(arguments) },
  // f3 是一个函数, 并且不是箭头函数
  f3 () { console.log(arguments) },
  f4 () {
	// ...
  }
}
obj.f1(1, 2, 3)
obj.f3(10, 20, 30)


8. ES6 - 模块化开发

开发的历史演变 :
=> 最早: 一个 js 文件
  -> 每一个 html 文件对应一个 js 文件
=> 后来: 把一个项目内部的重复功能提取出来
  -> 写成一个单独的 js 文件
=> 后再:
  -> 决定按照功能拆分出一个一个的文件
  -> a.js : 专门做顶部导航栏各种功能
  -> b.js : 专门做二级菜单
  -> c.js : 专门做搜索引擎
  -> d.js : 左侧边栏
  -> e.js : 轮播图
  -> 最后在每一个 页面 准备有一个整合的 js 文件
    + 就是专门用来组合这个页面使用了多少个 js 文件模块
  -> 此时, 我们管每一个 js 文件叫做一个 模块
    + 页面的完整功能, 就是由一个一个的模块来完成的
  -> 叫做 模块化 开发
模块化开发的规则 :
1. 如果你想使用 ES6 的模块化开发语法
  => 页面必须在服务器上打开
  => 本地打开不行
  => VS Code 下载插件, Live Server ( 会帮你配置一个虚拟服务器 )
  => 打开页面的时候, 鼠标右键 open with live server
    -> 快捷键, alt + l, 再按一次 alt + o


2. 当你使用了 模块化语法以后
  => 每一个 js 文件, 都是一个独立的 文件作用域
  => 该文件内的所有变量和方法, 都只能在这个文件内使用
  => 其他文件不能使用
  => 如果想使用, 需要导出
3. 每一个 js 文件, 也不能使用任何其他 js 文件内部的变量
  => 如果想使用
  => 那么你需要导入该文件
语法: 导出和导入
+ 导出语法 :
  export default { 你要导出的内容 } 
+ 导入语法 :
  import 变量 from 'js 文件' 

<!-- 只需要引入一个 index.js 文件 -->
<!-- 因为 index.js 文件内使用着 其他需要用到的模块 -->
<!-- 如果你页面引入的是一个使用了 ES6 模块化语法的 js 文件 -->
<!-- 必须在服务器上打开, 并且给 script 标签添加一个 type="module" 的属性 -->
<script src="./js/index.js" type="module"></script>

9. ES6 - 类语法

+ 类 就是专门用来创建对象的内容
+ 解释: ES6 书写构造函数的方式
+ 私人: 就是 构造函数

语法:
+ class 类名 { }
  => class: 定义类的关键字
  => 类名: 该类的名字
  => { }: 该类里面包含的所有内容
+ 在类{ }里面书写的内容
  1. construcor ( ) { }
    => 等价于 ES5 的构造函数体
  2. 构造函数原型上的方法
    => 直接在 constructor 的后面书写
    => 方法名 ( ) { }
    => 表示是添加在原型上的方法
    => 等价于 构造函数.prototype.方法名 = function ( ) { }
  3. 类 的 静态方法和属性
    => static 方法名 ( ) { }
    => static 变量 = 值
注意:
+ 因为 构造函数 的本质是 函数, 所以可以当做普通函数调用
+ 但是 类 的本质是 类, 不是函数, 所以不能当做普通函数调用

// ES5 书写构造函数
function Person() {
  this.age = 18
}
Person.prototype.sayHi = function () { console.log('hello world') }
// hello world
const p = new Person()
p.sayHi()
console.log(p)		// Person {age: 18}
// 构造函数当做普通函数调用
Person()

// ES6 类 的书写
class Student {
  constructor () {
	// 这个位置就等价于你 ES5 的构造函数体
	this.age = 20
  }
  // 直接书写原型上的方法
  sayHi () { console.log('hello student') }// hello student
}
const s = new Student()
s.sayHi()
console.log(s)	// Student {age: 20}
// 如果不和 new 关键字连用, 直接把 类 当做普通函数执行, 会报错
// 类的使用 : 因为 类 的本质不是 函数了
// 使用的时候必须和 new 关键字连用
Student()

如何区分静态方法和原型方法
+ 在书写上
  => 如果你想写一个方法将来给实例使用, 那么就写成原型方法
  => 如果你想写一个方法将来给类自己使用, 那么就写成静态方法
  => 如果你想写成原型方法, 那么就直接写 ( 方法名 ( ) { } )
  => 如果你想写成静态方法, 那么就直接写 ( static 方法名 ( ) { } )

// ES6 的类
class Person {
  // "构造函数体"
  constructor (name, age) {
	this.name = name
	this.age = age
  }
  // 原型上的方法 sayHi
  // 添加在 Person 的 prototype 上, 专门用来给该 类 的 所有实例 使用的方法
  sayHi () {
	console.log('hello world')
  }
  sayHi2 () {}
  sayHi3 () {}
  // 添加静态方法和属性
  // 把 Person 当做一个对象来看待, 添加在自己身上的方法
  // 不是为了给实例使用的, 实例也不能使用
  // 是为了给自己使用的
  static fn1 () { console.log('我是 Person 类的一个静态方法') }
  static a = 100
}

+ 在使用上
  => 如果你写的就是 ( 方法名 ( ) { } )
  => 那么将来你使用的时候, 要依赖这个类的 实例对象 去调用
    -> const p1 = new Person( )
    -> p1.方法名( )
  => 获取在方法内以 this 的形式来调用
    -> 方法名 ( ) { this.xxx }
  => 如果你写的是 ( static 方法名 ( ) { } )
  => 那么将来使用的时候要依赖 类名 去调用
    -> 类名.方法名( )

// ES5 的构造函数
function Person(name, age) {
  this.name = name
  this.age = age
}
// 原型上的方法
// 由构造函数来添加, 专门给 实例 使用的, 不是给函数自己本身使用的
Person.prototype.sayHi = function () { console.log('hello world') }
// 因为 Person 是一个构造函数, 可以创建对象
// 使用的时候需要和 new 关键字连用
const p1 = new Person('张三', 18)
console.log(p1)		// Person {name: "张三", age: 18}
// 因为 Person 的本质就是一个函数, 所以也可以不和 new 关键字连用
// 只是没有了自动创建对象的能力, 但是本身没有错
// 把函数体内的内容添加在了 Window 身上( this 指向 Window )
const p2 = Person('李四', 20)
console.log(p2)		// undefined
// 又因为 Person 是一个函数的同时, 也是一个对象
// 可以当做对象来存储一些键值对
// 其实就是 Person 的函数身份不冲突
// 当你把 Person 当做一个对象, 添加一些成员的时候
// 注意: 不是给实例使用的, 实例也不能使用, 给函数自己本身使用的
// 我们管这种给函数自己使用的方法和属性叫做 该函数的 静态属性和方法
// ( 就是把函数当成一个对象 , 往自己身上添加属性和方法 , 供自己使用的 )
Person.a = 100
Person.sayHi2 = function () { console.log('Person 身上自己的方法') }
console.dir(Person)	// ƒ Person(name, age)
// 等价于
const obj = {
  name: 'Jack',
  sayHi2: function () { }
}

 

  ES5 的时候, 你为什么要写构造函数
    => 看中了可以创建对象的能力
    => 为了高度封装, 一次书写这个功能
    => 以后在完成的时候方便很多
    => 一般构造函数不会不和 new 连用, 不会把他当做一个普通函数来使用

  ES6 的时候, 进行一下进化
    => 把他当做普通函数调用的能力给去掉了
    => 去掉以后, 就不能再叫做 构造函数 了
    => 给自己起了一个新的名字, 叫做 
    => 因为进化了, 总要有一些好处, 有一些变化

  原先写成
    function Person( ) {
      // 构造函数体
    }
  现在写成
    class Person {
      constructor ( ) {
        // "构造函数体"
      }
    }

  原型上的方法原先写成
    Perosn.prototype.a = function ( ) { }
  原型上的方法现在写成
    class Person {
      conctructor ( ) { ... }

      a ( ) { }
      b ( ) { }
    }

  静态方法原先写成
    Person.c = function ( ) { }
    Person.d = function ( ) { }
  静态方法现在写成
    class Person {
      constructor ( ) { ... }

      a ( ) { }

      static c ( ) { }
      static d ( ) { }
    }


  整合

  ES5 :
    function Person( ) { }

    Person.prototype.a = function ( ) { }

    Person.c = function ( ) { }

  ES6 :
    class Person {
      constructor ( ) { }

      a ( ) { }

      static c ( ) { }
    }


10. 图例 :

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值