系列文章目录
第一章:ES6(一) const、箭头函数、class相关
文章目录
前言
根据与es5 有无冲突或原理上的更改可以大致将es6新语法区分为两类:第一类即本章所要讲述的内容:const 、arrow_function 、class;第二类即只有语法知识的用法上的不同,放在另一篇中讲述(模板字符串、数组(foreach、map、some、every、reduce……)、filter、find、proxy、set、map等内容)。
一、const - 标志常量
const 用来标志常量。
const arg1 = 'name';
const obj = {name:'a', age:18 };
const array = [ 'a', 'b', 'c' ];
// ……
1. 不允许重复声明
var arg1 = 'dayanjign';
arg1 = 'jack';
// es5 不允许被重新赋值的方法
Object.defineProperty(window, 'arg2', {
value: 'jacks',
// 该属性定义是否允许被修改
writable: false
})
// const 直接就不被允许重新赋值
const arg1 = 'dayanjing';
// 重新赋值会报错;
2. 块级作用域
// arg1 用在什么地方会报错?
if (true) {
var arg1 = 'dayanjing';
}
// 用在所有地方都不报错。只是用在var 之前会取到undefined
// arg1 用在什么地方会报错?
if (true) {
const arg1 = 'dayanjing';
}
// 出了if就会报错
3. 无变量提升
console.log(arg1); // undefined
var arg1 = 'dayanjing';
// => js执行之前会将当前上下文的全局作用域变量统一提升至最前
// 执行步骤
var arg1;
console.log(arg1);
arg1 = 'dayanjign';
// 无变量提升 - 严格的先声明再使用
console.log(arg1);
const arg1 = 'dayanjing';
// const 的挂载有变化吗?
var arg1 = 'dayanjing';
console.log(window.arg1); // dayanjing
//const 不在window中
const arg1 = 'dayanjing';
console.log(window.arg1); // undefined
4. dead zone (暂时性死区)
if(true) {
console.log(arg1); // 问题:打印时取不到具体的值,但是能取到有声明,永远取不到值但是永远不报错
// ……当中间代码量较大时,,无法及时定位到问题原因
var arg1 = 'dayanjing';
}
5. let or const
什么时候使用let 什么时候使用const呢? 我们会发现 ,vue源码或者一些框架的源码中会经常使用到const 而不是let。这是因为二者的锁定内存类型不一样。
const 常量锁定的是栈内存。
const 表示栈内存的指针不被改变,但是声明对象或数组时,对象/数组的值是可以被更改的,因此可以实现一个对象多个复用,优化空间使用率,所以使用时,能用const 都用const 。
由此引申出另一个问题 - 引用类型是指向指针,那如果想要达到对象的属性也不能更改应该怎么办呢?
答案是 使用Object.freeze(obj) freeze 是object的一个属性,加上这个属性之后就能锁死属性不被更改。
但是 使用freeze会有一个局限性,只能冻结单层,再嵌套一层obj之后就没法控制不被更改了。
二、arrow_function 箭头函数
// 传统函数
function test1(a, b) {
return a + b;
}
const test2 = function(a, b) {
return a+b;
}
// 箭头函数
const test3 = (a, b) => {
return a + b;
}
const test3 = (a, b) => a + b;
const test4 = x => {
// content
}
1. 上下文 - this指向问题
const obj2 = {
name: 'jack',
job:'teacher',
chinese: [1, 2],
getTeacher: function() {
// 上下文是:调用方法的对象本身
return this.name;
}
getJob: () => {
// 无独立上下文 ,此时 this 指向的是window;
return this.job;
}
}
2. 上下文相关 箭头函数需要区分不能使用的场景
1. dom操作的callback
const btn = document.querySelector('#btn');
// 不能使用箭头函数
btn.addEventListener('click', function() {
this.style.color = '#fff';
})
2. 类操作
function Obj(teacher, leader) {
this.teacher = teacher;
this.leader = leader;
}
const o1 = new Obj();
// 使用箭头函数
const Obj = (teacher, leader) => {
this.teacher = teacher;
this.leader = leader;
}
const o2 = new Obj(); // ERROR 无constructor 构造器
// 箭头函数无法构造类,无法变成构造函数
3. 箭头函数没有arguments
// 箭头函数的参数
const test = function(teacher) {
console.log(arguments);
}
const test = teacher => {
console.log(arguments); // not defined
}
三、class
助力js更加面向对象。
传统对象:
function Course(teacher, course){
this.teacher = teacher;
this.course = course;
}
Course.prototype.getCourse = function() {
return `somethings`;
}
const course = new Course('name', 'es6')
ES6:
class Course {
constructor(teacher, course){
this.teacher = teacher;
this.course = course;
}
static getCourse = function() {
return `somethings`;
}
}
用一个class 整合到一起,感官上更舒服,将传统的不同部分的内容整合到一起,在内部用 constructor、static等区分各个类型部分的定义
1. calss的类型
console.log(typeof Course); // function
2. class & 函数对象的属性
course.hasOwnProperty('teacher'); //true
3. 属性定义 构造器 & 顶层定义 两种方式
class Course {
constructor(teacher, course){
this.teacher = teacher;
this.course = course;
}
static getCourse = function() {
return `somethings`;
}
// 数据劫持
// 数据取用可以重新定义并指定返回的内容
get teacher() {
return this._teacher;
}
// 可以重新set属性及属性值,扩充或删减val内容
set teacher(val) {
this._teacher = 'name: ' + val;
}
}
1. 如何在js中建立一个只读变量
class Course {
constructor(teacher, course){
this.teacher = teacher;
this.course = course;
}
static getCourse = function() {
return `somethings`;
}
get teacher() {
return this._teacher;
}
// set 方法不执行赋值,那么永远无法完成修改
set teacher(val) {
console.log('received!');
}
}
2. js如何实现一个私有属性 - 闭包
class Course {
constructor(teacher, course) {
this._teacher = teacher;
let _course = 'es6';
this.getCourse = () => {
return _course;
}
}
}
3. 封装核心 - 适配器模式
class utils {
constructor(core) {
this.main = 'mamian';
}
get name(){
return {
...this._main.name,
name: ${this._name}
}
}
set name(val) {
this._name = val;
}
}
4. 静态方法 - 直接挂载,无需实例化获取
function Course(teacher, course) {
this.teacher = teacher;
this.course = course;
// 每个实例都会挂载一个call方法,造成资源浪费
this.call = function () {
// ……
}
}
// 所有实例共用同一个call,节约空间
Course.prototype.call = function() {}
class Course {
constructor (teacher, course){
this.teacher = teacher;
this.course = course;
}
// 直接挂载在类上。但是不能被重写
static call() {}
}
5. 类继承方式
class Course{
constructor (teacher, course){
this.teacher = teacher;
this.course = course;
}
// 每个实例对象都有一个send方法
send() {}
// 加上static ,call方法在类上,每个实例对象可以直接调用但本身不再有
static call() {}
}
class Child extends Course {
constructor() {
// 指向父类的constructor方法,继承父类所有属性,并可以直接进行传参
super('jack', 'es6')
}
// 还可以声明自己的方法属性
start() {}
}
总结
以上内容是跟传统es5的原理上或思路上有差别的更改。