资讯专栏INFORMATION COLUMN

JavaScript从初级往高级走系列————ES6

孙淑建 / 522人阅读

摘要:采用二八定律,主要涉及常用且重要的部分。对象是当前模块的导出对象,用于导出模块公有方法和属性。箭头函数函数箭头函数把去掉,在与之间加上当我们使用箭头函数时,函数体内的对象,就是定义时所在的对象,而不是使用时所在的对象。

ES6
原文博客地址:https://finget.github.io/2018/05/10/javascript-es6/
现在基本上开发中都在使用ES6,浏览器环境支持不好,可以用babel插件来解决。

采用‘二八定律’,主要涉及ES6常用且重要的部分。

问题:

ES6模块化如何使用,开发环境如何打包

Class和普通构造函数有何区别

Promise的基本使用和原理

总结一下ES6其他常用功能

ES6模块化如何使用,开发环境如何打包 模块化的基本语法
// util1.js
export default {
  a : 100
}

const str = "hello";
export default str;
// export default const str = "hello"; X
// util2.js
export function fn1() {
  console.log("fn1");
}
export function fn2() {
  console.log("fn2");
}
export const fn3 = ()=> {
  console.log("fn3");
}
// index.js
import str from "./util1.js";
import {fn1 , fn2} from "./util2.js";
import * as fn from "./util2.js";
console.log(str);
fn1();
fn2();

fn.fn1();
fn.fn2();
export default 默认输出这个,然后在import的时候就会拿到默认输出的内容。例子中默认输出的a=100
export多个内容,在import时需要使用{}进行引用你需要的内容。
exportexport defaultexportsmodule.exports的区别
require: node 和 es6 都支持的引入
export / import : 只有es6 支持的导出引入
module.exports / exports: 只有 node 支持的导出

module.exports 初始值为一个空对象 {}

exports 是指向的 module.exports 的引用

require() 返回的是 module.exports 而不是 exports

Node里面的模块系统遵循的是CommonJS规范。

CommonJS定义的模块分为: 模块标识(module)、模块定义(exports) 、模块引用(require)

在nodejs,exportsmodule.exports的引用,初始化时,它们都指向同一个{}对象。

对象在JS中属于引用类型,意思就是exportsmodule.exports是指向同一个内存地址的。

看下面的例子:

exports.fn = function(){
  console.log("fn");
}
// 这两种情况的效果是一样的,上面说了exports与`module.exports初始化同一个对象,所以两种定义方就是给这个同对象定义了一个fn的属性,该属性值为一个函数。
module.exports.fn = function(){
  console.log("fn");
}
exports = function(){
  console.log("fn");
}
// 这两种情况就不一样了。上面的exports想当于指向了另一个内存地址。而下面这种情况是可以正常导出的。
module.exports = function(){
  console.log("fn");
}
exports对象是当前模块的导出对象,用于导出模块公有方法和属性。别的模块通过require函数使用当前模块时得到的就是当前模块的exports对象。

module.exports 的使用

// sayHello.js

function sayHello() {
  console.log("hello");
}

module.exports = sayHello;

// app.js
var sayHello = require("./sayHello");

sayHello();

定义一个sayHello模块,模块里定义了一个sayHello方法,通过替换当前模块exports对象的方式将sayHello方法导出。
在app.js中加载这个模块,得到的是一个函数,调用该函数,控制台打印hello。

// sayWorld.js
module.exports = function(){
  console.log("world");
}
// app.js
var sayWorld = require("./sayWorld"); // 匿名替换
sayWorld();

exports 导出多个变量

当要导出多个变量怎么办呢?这个时候替换当前模块对象的方法就不实用了,我们需要用到exports对象。

// userExports.js
exports.a = function () {
  console.log("a exports");
}
 
exports.b = function () {
  console.log("b exports");
}

// app.js
var useExports = require("./userExports");
useExports.a();
useExports.b();
// a exports
// b exports

当然,将useExports.js改成这样也是可以的:

// userExports.js
module.exports.a = function () {
  console.log("a exports");
}
 
module.exports.b = function () {
  console.log("b exports");
}
在实际开发当中可以只使用module.exports避免造成不必要的问题。
开发环境配置
babel

Babel中文网

nodejs环境 npm init

npm i babel-core babel-preset-es2015 babel-preset-latest --save-dev

创建.babelrc文件

npm i --global babel-cli

// .babelrc
{
  "presets": ["es2015","latest"],
  "plugins": []
}
webpack

四大维度解锁webpack3笔记

rollup.js

Rollup.js官网

npm init

安装 rollup.js需要的一些插件

npm i rollup rollup-plugin-node-resolve rollup-plugin-babel babel-core babel-plugin-external-helpers babel-preset-latest --save-dev

配置 .babelrc

配置 rollup.config.js

rollup 功能单一(打包js模块化), webpack功能强大
工具尽量功能单一,可继承,可扩展
// .babelrc
{
  "presets":[
    ["latest", {
      "es2015":{
        "modules": false
      }
    }]
  ],
  "plugins":["external-helpers"]
}
// rollup.config.js
import babel from "rollup-plugin-babel";
import resolve from "rollup-plugin-node-resolve";

export default {
  entry: "src/index.js",
  format: "umd",
  plugins: [
    resolve(),
    babel({
      exclude: "node_modules/**"
    })
  ],
  dest: "build/bundle.js"
}
// package.json
...
"scripts":{
  "start": "rollup -c rollup.config.js"
}
...

npm run start

关于JS众多模块化标准

没有模块化

AMD成为标准,require.js

前端打包工具,使得nodejs模块化(CommonJS)可以被使用

ES6出现,想统一现在所有模块化标准

nodejs积极支持,浏览器尚未统一

你可以自造lib,但是不要自造标准!!!

Class和普通构造函数有何区别 JS构造函数
// 构造函数
function MathHandle(x, y){
  this.x = x;
  this.y = y;
}
// 原型扩展
MathHandle.prototype.add = function(){
  return this.x + this.y;
}

// 创建实例
var m = new ManthHandle(1,2);
console.log(m.add()); // 3
Class基本语法
class MathHandle { // 直接跟大括号
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  
  add() {
    return this.x + this.y;
  }
}
const m = new ManthHandle(1,2);
console.log(m.add()); // 3
语法糖
typeof MathHandle  = "function"
MathHandle其实是个function,‘构造函数’
MathHandle === MathHandle.prototype.constructor
继承 原生js继承
// 动物
function Animal() {
  this.eat = function() {
    console.log("animal eat");
  }
}
// 狗
function Dog() {
  this.bark = function(){
    console.log("dog bark");
  }
}
// 绑定原型,实现继承
Dog.prototype = new Animal();
// 实例化一只狗
var hashiqi = new Dog();

// hashiqi就有了eat方法
hashiqi.eat(); // animal eat
廖雪峰老师的原型继承:点这里
ES6继承
class Animal {
  constructor(name){
    this.name = name;
  }
  eat() {
    console.log(`${this.name} eat`);
  }
}

class Dog extends Animal { // extends 继承
  constructor(name){
    super(name); // 必须*  记得用super调用父类的构造方法!
    this.name = name;
  }
  say() {
    console.log(`${this.name} say`);
  }
}

const dog = new Dog("hashiqi");
dog.eat(); // hashiqi eat
Promise 的基础使用
解决回调地狱(Callback Hell)
详细点的Promise:点这里
Promise 基础语法
new Promise((resolve, reject) => {
  // 一段耗时很长的异步操作
    .....
  resolve(); // 数据处理完成
  reject(); // 数据处理出错
}).then(function A() {
  // 成功,下一步
}, function B(){
  // 失败,做相应处理
})
我最开始接触到Promise的时候,一直傻了吧唧的在想resolve()reject()在什么时候调用。
resolve()reject()就是为后面then()中的两个函数服务的。
resolve和reject
new Promise((resolve, reject) => {
  setTimeout(()=>{
    resolve("good,我要传给then里的一个函数");
  },2000);
  setTimeout(()=>{
    reject("错了,把我给我then里的第二个函数");
  },2000);
}).then(value => {
  console.log(value); // good,我要传给then里的一个函数
},value => {
  console.log(value); // 错了,把我给我then里的第二个函数
});
来个实际的例子
/**
 * 基于jquery封装一个promise ajax请求
 * @param  {[type]} param [选项]
 * @return {[type]}       [description]
 */
request(param){
  return new Promise((resolve,reject) => {
    $.ajax({
      type : param.type || "get",
      url : param.url || "",
      dataType : param.dataType || "json",
      data : param.data || null,
      success:(res)=>{ // 用箭头函数避免this指向问题
        if (0 === res.status) {
           typeof resolve === "function"&&resolve(res.data, res.msg); // 成功就把请求到的数据用resolve返回,这样就可以在then的第一个函数里拿到值了
        } else {
           typeof reject === "function"&&reject(res.msg || res.data); // 失败就返回错误信息
        }

      },
      error:(err)=>{ // 这个失败是请求失败,上面那个失败是请求成功发送了,但是没有拿到数据失败了
         typeof reject === "function"&&reject(err.statusText);
      }
    })
  })
}
ES6常用其他功能 let/const
let constvar都是用来定义变量的,不同的是let自带作用域,const不能重复赋值。
let name = "FinGet"
while (true) {
    let name = "GetFin"
    console.log(name)  //GetFin
    break
}
console.log(name)  //FinGet
let定义的变量只在包含它的代码块内有用
const PI = 3.1415926;
PI = 3.14; // 错误
多行字符串/模板变量
let name = "FinGet";
let age = 22;
// js
var str = "我是"+ name+",今年"+age+"岁"; // 很麻烦

let str1 = `我是${name},今年${age}岁`; // 简单多了
模板字符串就是用`(Tab键上面那个)包含,变量就是用${}`表示
解构赋值
let obj = {
  name: "FinGet",
  age: 22,
  job: "前端",
  addr: "成都"
}
let {name,age} = obj;
console.log(name); // FinGet
console.log(age); // 22

还可以反过来:

let  name = "FinGet";
let  age = 22;
let  job = "前端";
let  addr = "成都";

let obj = {name,age,job,addr};
//obj = {name: "FinGet",age: 22,job: "前端",addr: "成都"}
块级作用域

另外一个var带来的不合理场景就是用来计数的循环变量泄露为全局变量,看下面的例子:

// js
var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10
let 自带块级作用域
// ES6
var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

原生js想实现这种效果,需要用到闭包:

var a = [];
for (var i = 0; i < 10; i++) {
  (function(j){ // 立即执行函数
    a[j] = function() {
      console.log(j);
    }
  }(i))
}
a[6](); // 6
立即执行函数形成了一个块级作用域,将参数j保存了下来,并不会被‘污染’,原生js没有块级作用域,varfor中定义的变量是个全局变量,可以在外部访问,也就可以被改变,所以每次for循环都是重置修改i的值,导致最后只能输出10。
函数默认参数与rest
default很简单,意思就是默认值。大家可以看下面的例子,调用animal()方法时忘了传参数,传统的做法就是加上这一句type = type || "cat" 来指定默认值。
function animal(type){
    type = type || "cat"  
    console.log(type)
}
animal()

如果用ES6我们而已直接这么写:

function animal(type = "cat"){
    console.log(type)
}
animal(); // cat

最后一个rest语法也很简单,直接看例子:

function animals(...types){
    console.log(types)
}
animals("cat", "dog", "fish") //["cat", "dog", "fish"]
而如果不用ES6的话,我们则得使用ES5的arguments。
箭头函数
// js函数
function (a,b){
  console.log(a+b);
}
// es6箭头函数
(a,b) => {
  console.log(a+b);
}
function去掉,在(){}之间加上=>
当我们使用箭头函数时,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,它的this是继承外面的,因此内部的this就是外层代码块的this
最后

创建了一个前端学习交流群,感兴趣的朋友,一起来嗨呀!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99490.html

相关文章

  • JavaScript初级高级系列————异步

    摘要:之所以是单线程,取决于它的实际使用,例如不可能同添加一个和删除这个,所以它只能是单线程的。所以,这个新标准并没有改变单线程的本质。 原文博客地址:https://finget.github.io/2018/05/21/async/ 异步 什么是单线程,和异步有什么关系 什么是event-loop 是否用过jQuery的Deferred Promise的基本使用和原理 介绍一下asyn...

    andot 评论0 收藏0
  • JavaScript初级高级系列————prototype

    摘要:原文博客地址另一篇转载的从初级往高级走系列原型定义原型是对象的一个属性,它定义了构造函数制造出的对象的公共祖先。 原文博客地址:https://finget.github.io/2018/09/13/proto/另一篇转载的JavaScript从初级往高级走系列————prototype 原型 定义: 原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通...

    SKYZACK 评论0 收藏0
  • JavaScript初级高级系列————MVVM-Vue

    摘要:原文博客地址如何理解如何实现是否解读过的源码与框架的区别实现实现独立初始化实例两者的区别数据和视图的分离,解耦开放封闭原则,对扩展开放,对修改封闭在中在代码中操作视图和数据,混在一块了以数据驱动视图,只关心数据变化, 原文博客地址:https://finget.github.io/2018/05/31/mvvm-vue/ MVVM 如何理解 MVVM 如何实现 MVVM 是否解读过 ...

    codercao 评论0 收藏0
  • JavaScript初级高级系列————Virtual Dom

    摘要:当中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如。则就叫称为重绘。 原文博客地址:https://finget.github.io/2018/05/22/virtualDom/ 什么是虚拟DOM 用JS模拟DOM结构 DOM变化的对比,放在JS层来做(图灵完备语言) 提高重绘性能 重绘和回流 页面渲染过程:showImg(https://seg...

    tinyq 评论0 收藏0
  • javascript知识点

    摘要:模块化是随着前端技术的发展,前端代码爆炸式增长后,工程化所采取的必然措施。目前模块化的思想分为和。特别指出,事件不等同于异步,回调也不等同于异步。将会讨论安全的类型检测惰性载入函数冻结对象定时器等话题。 Vue.js 前后端同构方案之准备篇——代码优化 目前 Vue.js 的火爆不亚于当初的 React,本人对写代码有洁癖,代码也是艺术。此篇是准备篇,工欲善其事,必先利其器。我们先在代...

    Karrdy 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<