前端JavaScript高级面试技巧[1]

第1章 课程介绍

1-1 导学

课程概述

  • 做什么?— 讲解前端 JS 高级面试题
  • 哪些部分?— 高级基础, 框架原理, app混合开发
  • 技术?— JS、ES6、虚拟DOM、vue、React、hybrid

知识点介绍

  • 基础知识:ES6 常用语法、原型高级应用、异步全面讲解
  • 框架原理:虚拟 DOM、MVVM vue、组件化 React
  • 混合开发:hybrid、hybrid vs H5、前端客户端通讯

课程安排

  • 高级基础
    1. ES6 常用语法:Class Module Promise 等
    2. 原型高级应用:结合 jQuery 和 zepto 源码
    3. 异步全面讲解:从原理到 jQuery 再到 Promise
  • 框架原理
    1. 虚拟 DOM:存在价值,如何使用,diff 算法
    2. vue:MVVM,vue 响应式、模板解析、渲染
    3. React:组件化,JSX,vdom,setState
    4. 对比:有主见,自圆其说
  • App混合开发
    1. hybrid:基础、和 h5 对比,上线流程
    2. 通讯:通讯原理,JS-Bridge 封装

讲授方式

  • 先出面试题,带领大家思考
  • 通过题目引出知识点,扩充讲解知识体系
  • 最后通过学到的知识点,解答题目

课程收获

  • 从深度和广度都扩充了自己的知识体系
  • 学会如何高效学习
  • 深入理解常用框架的实现原理和 hybrid 应用

1-2 课程重要提示

1-3 架构-题目

ES6

模块化的使用和编译环境?

Class 与 JS 构造函数的区别?

Promise 的用法?

ES6 其他常用功能?

异步

什么是单线程,和异步有什么关系?

什么是 event-loop?

目前 JS 解决异步的方案有哪些?

如果只用 jquery 如何解决异步?

Promise 的标准?

async/await 的使用?

原型

原型如何实际应用?

原型如何满足扩展?

vdom

什么是 vdom,为何要用 vdom?

vdom如何使用,核心函数有哪些?

了解 diff 算法吗?

MVVM

之前使用 jquery 和现在使用 Vue 或 React 框架的区别?

你如何理解MVVM?

Vue 如何实现响应式?

Vue 如何解析模版?

介绍 Vue 的实现流程?

组件化

对组件化的理解?

JSX 是什么?

JSX 和 vdom 什么关系?

简述 React 的 setState?

简述自己如何比较 React 和 Vue?

hybrid

hybrid 是什么,为何要用hybrid?

hybrid 如何更新上线?

hybrid 和 h5 有何区别?

JS 如何与客户端通信?

第2章 ES6 语法

2-1 开始

ES6

  • 开发环境已经普及使用
  • 浏览器环境却支持不好(需要开发环境编译)
  • 内容很多,重点了解常用语法
  • 面试:开发环境的使用 + 重点语法的掌握

题目

  • ES6 模块化如何使用,开发环境如何打包?
  • Class 和普通构造函数有何区别?
  • Promise 的基本使用和原理?
  • 总结一下 ES6 其他常用功能?

2-2 模块化

【题目】

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

【知识点】

1. 模块化的基本语法

  • export 语法
// util1.js
export default {
  a: 100
};

// util2.js
export function fn1() {
  alert('fn1');
};
export function fn2() {
  alert('fn2');
};
  • import 语法
// index.js
import util1 from './util1.js';
import { fn1, fn2 } from './util2.js';

console.log(util1);
fn1();
fn2();

2. 开发环境配置

babel

  • 安装 babel
1. 电脑有 node 环境,运行 npm init
2. npm install --save-dev babel-core babel-preset-es2015 babel-preset-latest
3. 创建 .babelrc 文件,输入以下内容:
    { 
        "presets": ["es2015", "latest"],
        "plugins": []
    }
4. sudo npm install -g babel-cli
5. babel --version
  • 使用 babel
1. 创建:./src/index.js
2. 内容:[1, 2, 3].map(item => item + 1);
3. 运行:babel ./src/index.js

webpack

  • 安装 webpack
    此处 babel-loader 需要指定版本,不然掉坑
    https://www.cnblogs.com/jiebba/p/9618930.html
  • 使用 webpack
1. npm install webpack webpack-cli babel-loader@^7.1.2 --save-dev
2. 配置 webpack.config.js,输入以下内容:
    module.exports = { 
        entry: './src/index.js',
        output: { 
          path: __dirname,
          filename: './build/bundle.js'
        },
        module: { 
          rules: [{
            test: /\.js?$/,
            exclude: /{node_modules}/,
            loader: 'babel-loader'
          }]
        }
    }
3. 配置 package.json 中的 scripts
    "scripts": {
        "start": "webpack"
    }
4. 运行 npm start
5. 创建:index.html
    
6. http-server -p 8881
7. 访问 http://localhost:8881/index.html

rollup

  • 安装 rollup

https://www.rollupjs.com/guide/tutorial rollup 中文网

1. npm init
2. npm i rollup rollup-plugin-node-resolve rollup-plugin-babel@^3.0.3 babel-plugin-external-helpers babel-preset-latest babel-core --save-dev
3. 配置 .babelrc
{
  "presets": [
    ["latest", {
      "es2015": {
        "modules": false
      }
    }]
  ],
  "plugins": ["external-helpers"]
}
4. 配置  rollup.config.js
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';

export default {
  input: 'src/index.js',
  output: {
    file: 'build/bundle.js',
    format: 'cjs'
  },
  plugins: [
    resolve(),
    babel({
        exclude: 'node_modules/**'
    })
  ]
};
  • 使用 rollup
1. 将 webpack 环境的 JS 代码拷贝过来
2. 修改 package.json 的 scripts
  "scripts": {
    "start": "rollup -c rollup.config.js"
  }
3. 运行 npm start
  • 关于工具
rollup 功能单一,webpack 功能强大
参考设计原则和《Linux/Unix设计思想》
工具要尽量功能单一,可集成,可扩展
wangEditor 用的 gulp + rollup

3. 关于 JS 众多模块化标准

  • 没有模块化
  • AMD 成为标准,require.js (也有 CMD)
  • 前端打包工具,是的 nodejs 模块化可以被使用
  • ES6 出现,想统一现在所有模块化标准
  • nodejs 积极支持,浏览器尚未统一
  • 你可以自造 lib ,但是不要自造标准!!!

【解答】

  • 语法: import export (注意有无 default)
  • 环境: babel 编译 ES6 语法,模块化可用 webpack 和 rollup
  • 扩展: 说一下自己对模块化标准统一的期待

2-9 class

【题目】

Class 与 JS 构造函数的区别?

  • Class 在语法上更加贴合面向对象的写法
  • Class 实现继承更加易读、易理解
  • 更易于写 java 等后端语言的使用
  • 本质还是语法糖,使用 prototype

【知识点】

JS 构造函数

function MathHandle(x, y) {
  this.x = x;
  this.y = y;
}

MathHandle.prototype.add = function () {
  return this.x + this.y;
};

var m = new MathHandle(1, 2);
console.log(m.add());

// typeof MathHandle // "function"
// MathHandle === MathHandle.prototype.constructor // true
// m.__proto__ === MathHandle.prototype // true

Class 基本语法

class MathHandle {
  constructor (x, y) {
    this.x = x;
    this.y = y;
  }

  add() {
    return this.x + this.y;
  }
}
const m = new MathHandle(1, 2);
console.log(m.add());
// typeof MathHandle // "function"
// MathHandle === MathHandle.prototype.constructor // true
// m.__proto__ === MathHandle.prototype // true

语法糖

class MathHandle {
  // ...
}

typeof MathHandle // "function"
MathHandle === MathHandle.prototype.constructor // true

继承

  • 继承 - JS
ES6 之前的继承,是把低级构造函数的原型,赋值成高级构造函数的实例这种方式来实现的
// 动物
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(); // animal eat
hashiqi.bark(); // dog bark
  • 继承 - Class
// 动物
class Animal {
  constructor(name) {
    this.name = name;
  }
  eat() {
    console.log(`${this.name} eat`);
  }
}
// 狗
class Dog extends Animal {
  constructor(name) {
    super(name);
    this.name = name;
  }
  say() {
     console.log(`${this.name} say`);
  }
}
// 哈士奇
const dog = new Dog('哈士奇');
dog.say(); // 哈士奇 say
dog.eat(); // 哈士奇 eat

【解答】

class Ad extends Component {
    constructor(props) {
        super(props);
        this.state = {
            data: []
        }
    }
    render() {
        return (
            
Hello, World!
) } componentDidMount() { } }

2-13 Promise

【题目】

Promise 的用法?

【知识点】

Promise 的基本使用

  • Callback Hell
function loadImg(src, callback, fail) {
  var img = document.createElement('img');
  img.onload = function () {
    callback(img);
  }
  img.onerror = function () {
    fail();
  }
  img.src = src;
}

var src = 'https://www.imooc.com/courseimg/s/cover042_s.jpg';
loadImg(src, function (img) {
  console.log(img.width);
}, function () {
  console.log('failed');
})
  • Promise 语法
function loadImg(src) {
  const promise = new Promise(function (resolve, reject) {
    var img = document.createElement('img');
    img.onload = function () {
      resolve(img);
    }
    img.onerror = function () {
      reject();
    }
    img.src = src;
  })
  return promise;
};

var src = 'https://www.imooc.com/courseimg/s/cover042_s.jpg';
var result = loadImg(src);

result.then(function (img) {
  console.log(img.width);
}, function () {
  console.log('failed');
});

result.then(function (img) {
  console.log(img.height);
});

【解答】

  • new Promise 实例,而且要 return
  • new Promise 时要传入函数,函数有 resolve reject 两个参数
  • 成功时执行 resolve() 失败时执行 reject()
  • then 监听结果

2-16 总结一下 ES6 其他常用功能

题目

总结一下 ES6 其他常用功能?

  • let/const
  • 多行字符串/模板变量
  • 解构赋值
  • 块级作用域
  • 函数默认参数
  • 箭头函数 (this)

知识点

  • let/const
// JS
var i = 10;
i = 100;

// ES6
let i = 10;
i = 100;  // 正确
const j = 20;
j = 200;  // 报错
  • 多行字符串/模板变量
// JS
var name = 'zhangsan', age = 20, html = '';
html += '
'; html += '

' + name + '

'; html += '

' + age + '

'; html += '
'; // ES6 const name = 'zhangsan', age = 20; const html = `

${name}

${age}

`; console.log(html);
  • 解构赋值
// JS
var obj = { a: 100, b: 200 };
var a = obj.a;
var b = obj.b;

var arr = ['xxx', 'yyy', 'zzz'];
var x = arr[0];
// ES6
const obj = { a: 10, b: 20, c: 30 };
const { a, c } = obj;
console.log(a);
console.log(c);

const arr = ['xxx', 'yyy', 'zzz'];
const [x, y, z] = arr;
console.log(x);
console.log(y);
console.log(z);
  • 块级作用域
// JS
var obj = { a: 100, b: 200 };
for (var item in obj) {
  console.log(item);
}
console.log(item); // 'b'

// ES6
const obj = { a: 100, b: 200 };
for (let item in obj) {
  console.log(item);
}
console.log(item); // undefined
  • 函数默认参数
// JS
function fn(a, b) {
  if (b == null) {
    b = 0;
  }
}

// ES6
function fn(a, b=0) {

}
  • 箭头函数
// JS
var arr = [1, 2, 3];
arr.map(function (item) {
  return item + 1;
});

// ES6
const arr = [1, 2, 3];
arr.map(item => item + 1);
arr.map((item, index) => {
  console.log(index);
  return item + 1;
});
function fn() {
  console.log('real', this); // {a: 100}
  var arr = [1, 2, 3];
  // 普通 JS
  arr.map(function (item) {
    console.log('js', this); // window
    return item + 1;
  });
  // 箭头函数
  arr.map(item => {
    console.log('es6', this); // {a: 100}
    return item + 1;
  });
}
fn.call({a: 100});

第3章 原型

3-1 开始

  • 《前端 JS 面试技巧》已经讲解过原型的基础知识
  • 高级面试题,光会原型基础还不够,还要实际应用
  • zepto jquery 中如何用原型?
  • 顺便也算是解读了 zepto 和 jquery 的部分源码

题目

原型如何实际应用?

  • jquery 和 zepto 的简单使用



    
    Document


    

jquery test 1

jquery test 2

jquery test 3

jquery test in div

  • zepto 如何使用原型
(function (window) {

  var zepto = {};

  function Z(dom, selector) {
      var i, len = dom ? dom.length : 0;
      for (i = 0; i < len; i++) {
          this[i] = dom[i];
      }
      this.length = len;
      this.selector = selector || '';
  }

  zepto.Z = function (dom, selector) {
      return new Z(dom, selector);
  };

  zepto.init = function (selector) {
      var slice = Array.prototype.slice;
      var dom = slice.call(document.querySelectorAll(selector));
      return zepto.Z(dom, selector);
  };

  var $ = function (selector) {
      return zepto.init(selector);
  };
  window.$ = $

  $.fn = {
      css: function (key, value) {
          alert('css');
      },
      html: function (value) {
          return '这是一个模拟的 html 函数';
      }
  }
  Z.prototype = $.fn;
})(window);
  • jquery 如何使用原型
(function (window) {

    var jQuery = function (selector) {
        return new jQuery.fn.init(selector)
    };

    jQuery.fn = {
        css: function (key, value) {
            alert('css');
        },
        html: function (value) {
            return 'html';
        }
    };

    var init = jQuery.fn.init = function (selector) {
        var slice = Array.prototype.slice;
        var dom = slice.call(document.querySelectorAll(selector));

        var i, len = dom ? dom.length : 0;
        for (i = 0; i < len; i++) {
            this[i] = dom[i];
        }
        this.length = len;
        this.selector = selector || '';
    }

    init.prototype = jQuery.fn;

    window.$ = jQuery;

})(window);

原型如何满足扩展?

第4章 异步

  • 《前端 JS 面试技巧》讲到异步的基础
  • 高级面试会问到更多的内容
  • 如 event-loop Promise Async/Await 等

题目

什么是单线程,和异步有什么关系?

  • 单线程 - 只有一个线程,同一时间只能做一件事
// 循环运行期间,JS 执行和 DOM 渲染暂时卡顿
var i, sum = 0;
for (i = 0; i < 1000000000; i++) {
  sum += i;
}
console.log(sum);

// alert 不处理, JS 执行和 DOM 渲染暂时卡顿
console.log(1);
alert('hello');
console.log(2);
  • 原因 - 避免 DOM 渲染的冲突
浏览器需要渲染 DOM
JS 可以修改 DOM 结构
JS 执行的时候,浏览器 DOM 渲染会暂停
两段 JS 也不能同时执行(都修改 DOM 就冲突了)
webworker 支持多线程,但是不能访问 DOM
  • 解决方案 - 异步
    什么是 callback?异步完成之后要执行的函数
问题一:没按照书写方式执行,可读性查
问题二:callback 中不容易模块化

什么是 event-loop?

  • 文字解释
事件轮询,JS 实现异步的具体解决方案
同步代码,直接执行
异步函数先放在 "异步队列" 中
待同步函数执行完毕,轮询执行 "异步队列" 的函数

如果只用 jquery 如何解决异步?- Deferred

  • 是否用过 jQuery 的 Deferred
jQuery 1.5 的变化
使用 jQuery Deferred
初步引入 Promise 概念
  • jQuery 1.5 的变化 - 1.5 之前
var ajax = $.ajax({
  url: 'data.json',
  success: function () {
    console.log('success1');
    console.log('success1');
    console.log('success1');
  },
  error: function () {
    console.log('error');
  }
})
console.log(ajax); // 返回一个 XHR 对象
  • jQuery 1.5 的变化 - 1.5 之后
var ajax = $.ajax('data.json');
ajax.done(function () {
      console.log('success 1');
    })
    .fail(function () {
      console.log('error');
    })
    .done(function () {
      console.log('success 2');
    })
console.log(ajax); // 返回一个 deferred 对象
// 很像 Promise 的写法
var ajax = $.ajax('data.json');
ajax.then(function () {
        console.log('success 1');
      }, function () {
        console.log('error 1');
      })
      .then(function () {
        console.log('success 2');
      }, function () {
        console.log('error 2');
      })
  • jQuery 1.5 的变化
无法改变 JS 异步和单线程的本质
只能从写法上杜绝 callback 这种形式
它是一种语法糖形式,但是解耦了代码
很好的体现:开放封闭原则 ( 对扩展开发,对修改封闭 )
  • 使用 jQuery Deferred
var wait = function () {
  var task = function () {
     console.log('执行完成');
     console.log('此处新需求......');
     console.log('第一步');
     console.log('第二步');
     console.log('第三步');
  };
  setTimeout(task, 2000);
};
wait();
function waitHandle() {
   var dtd = $.Deferred();
   var wait = function (dtd) {
       var task = function () {
           console.log('执行完成');
           dtd.resolve();
           // dtd.reject()
       }
       setTimeout(task, 2000);
       return dtd.promise(); // return dtd; => return dtd.promise();
   }
   return wait(dtd);
}

var w = waitHandle();
// w.then(function () {  
// => 1.w 接收到的不再是一个 dtd 对象,而是一个 promise 对象
// => 2.只有 .then .done .fail 这种被动监听方法
// => 3.不再支持 .resolve .reject 这种主动方法的调用
$.when(w).then(function () {
    console.log('ok 1');
}, function () {
    console.log('err 1');
});
  • jQuery 里引入 promise
总结,dtd 的 API 可分成两类,用意不同
第一类: dtd.resolve  dtd.reject
第二类: dtd.then  dtd.done  dtd.fail
这两类应该分开,否则后果很严重!
可以在上面代码最后执行 dtd.reject() 试一下后果

Promise 的基本使用和原理?

  • 基本语法回顾
function loadImg(src) {
  const promise = new Promise(function (resolve, reject) {
    var img = document.createElement('img');
    img.onload = function () {
      resolve(img);
    }
    img.onerror = function () {
      reject();
    }
    img.src = src;
  })
  return promise;
};

var src = 'https://www.imooc.com/courseimg/s/cover042_s.jpg';
var result = loadImg(src);

result.then(function (img) {
  console.log(img.width);
}, function () {
  console.log('failed');
});

result.then(function (img) {
  console.log(img.height);
});
  • 异常捕获
// 捕获程序错误异常
// throw new Error('自定义错误');

result.then(function (img) {
  console.log(img.width);
  return img;
}).then(function (img) {
  console.log(img.height);
}).catch(function (ex) {
  // 统一捕获异常
  console.log(ex);
})
// 捕获业务逻辑异常
// reject('图片加载失败');
// var src = 'https://cover042_sXXX.jpg';

result.then(function (img) {
  console.log(img.width);
  return img;
}).then(function (img) {
  console.log(img.height);
}).catch(function (ex) {
  // 统一捕获异常
  console.log(ex);
})
  • 多个串联
//业务需求;先加载一个,再加载另外一个
var src1 = 'https://www.imooc.com/courseimg/s/cover042_s.jpg';
var result1 = loadImg(src1);
var src2 = 'https://coding.imooc.com/static/module/class/content/img/190/section5-img.png';
var result2 = loadImg(src2);

// 链式操作
result1.then(function (img) {
  console.log('第一个图片加载完成', img.width); // 240
  return result2;
}).then(function (img) {
  console.log('第二个图片加载完成', img.width); // 998
}).catch(function (ex) {
  // 统一捕获异常
  console.log(ex);
})
  • Promise.all 和 Promise.race
// 全部完成才执行
Promise.all([result1, result2]).then(function (datas)  {
 console.log(datas[0]);
 console.log(datas[1]);
});
// 只要有一个完成就执行
Promise.race([result1, result2]).then(function (data)  {
 console.log(data);
});
  • Promise 标准
// 关于“标准”的闲谈
任何技术推广使用都需要一套标准来支撑
如 html js css http 等,无规矩不成方圆
任何不符合标准的东西,终将会被用户抛弃
不要挑战标准,不要自造标准
// Promise 标准 - 状态变化
三种状态:pending fulfilled rejected
初始状态是 pending
pending 变为 fulfilled ,或者 pending 变为 rejected
状态变化不可逆
// Promise 标准 - then
Promise 实例必须实现 then 这个方法
then() 必须可以接收两个函数作为参数
then() 返回的必须是一个 Promise 实例

介绍一下 async/await(和 Promise 的区别、联系)?

  • then 只是将 callback 拆分了
var w = waitHandle();
w.then(function () { 
    console.log('ok 1');
}, function () {
    console.log('err 1');
}).then(function () { 
    console.log('ok 2');
}, function () {
    console.log('err 2');
});
  • async/await 是最直接的同步写法
const load = async function () {
  const result1 = await loadImg(src1);
  console.log(result1);
  const result2 = await loadImg(src2);
  console.log(result2);  
}
load();
  • 语法
使用 await ,函数必须用 async 标识
await 后面跟的是一个 Promise 实例
需要 babel-polyfill
  • 坑来了
// webpack 打包
1.首先,npm i babel-polyfill -D
2.运行报错,Uncaught ReferenceError: regeneratorRuntime is not defined
3.在 .babelrc 文件中添加:
    "plugins": [
        [
            "transform-runtime",
            {
                "helpers": false,
                "polyfill": false,
                "regenerator": true,
                "moduleName": "babel-runtime"
            }
        ]
    ]
4.运行报错,ReferenceError: Unknown plugin "transform-runtime" specified
5.npm install babel-plugin-transform-runtime -D
6.运行再次报错,Cannot use import statement outside a module
7.
8.成功
// rollup 打包
1.npm i babel-polyfill -D
之前也报和 webpack 相同的错误,自己就好了,原因未知
  • 小结
promise 是对异步回调的封装
async await 是使用 promise 时的一种扩展
完全是同步的写法,再也没有回调函数
但是:改变不了 JS 单线程、异步的本质

目前 JS 解决异步的方案有哪些?

  • jQuery Deferred
  • Promise
  • Async/Await
  • Generator

你可能感兴趣的:(前端JavaScript高级面试技巧[1])