1-1 课程概述
- 要做什么?——讲解前端 JS 基础面试题
- 哪些部分?——JS 基础,JS-WEB-API,JS 开发环境
- 使用技术?——JS,直指面试题
知识点介绍
基础知识(三座大山)
- 原型 原型链
- 作用域 闭包
- 异步 单线程
JS API
- DOM 操作
- AJAX
- 事件绑定
开发环境
- 版本管理
- 模块化
- 打包工具
运行环境
- 页面渲染
- 性能优化
讲述方式
- 以面试题引出知识点,深化知识点,举一反三
课程收获
- 前端 JS 基础知识以及知识体系
1-2 前言
关于面试(分成三个阶段)
- 基层工程师 - 基础知识
- 高级工程师 - 项目经验
- 架构师 - 解决方案
关于基础
- 工程师的自我修养 - 基础
- 扎实的基础会让你高效学习新技术
1-3 几个面试题
JS 中使用 typeof 能得到哪些类型?
考点:JS 变量类型
何时使用 ===,何时使用 ==?
考点:强制类型转换
window.onload 和 DOMContentLoaded 的区别?
考点:浏览器的渲染过程
用 JS 创建10个<a>标签,点击的时候弹出来对应的序号?
考点:作用域
简述如何实现一个模块加载器,实现类似 require.js 的基本功能?
考点:JS 模块化
实现数组的随机排序?
考点:JS 基础算法
思考
- 拿到一个面试题,你第一时间看到的是什么?
答:考点。(考的哪里) - 如何看待网上搜出来的永远也看不完的题海?
答:不变应万变。(知识不变) - 如何对待接下来遇到的面试题?
答:题目到知识再到题目。
第二章 JS基础知识
2-1 变量类型和计算
题目
JS 中使用 typeof 能得到哪些类型?
考点:JS 变量类型(6种),不能区分引用类型*
typeof undefined // undefined
typeof 'abc' // string
typeof 123 // number
typeof true // boolean
typeof {} // object
typeof [] // object
typeof null // object
typeof console.log // function
何时使用 ===,何时使用 ==?
考点:强制类型转换(==有类型转换,===没有)
JS 中有哪些内置函数?
考点:数据封装类对象
Object
Array
Boolean
Number
String
Function
Date
RegExp
Error
JS 变量按照存储方式区分为哪些类型,并描述其特点?
考点:值类型(分块存储) vs 引用类型(共享内存)
前者是值的拷贝,后者是引用的拷贝
如何理解 JSON?
答:JS 对象(同 Math)|| 数据格式
// 常用的方法有两个
JSON.stringify({a:10, b:20}); // 对象 => 字符串
JSON.parse('{"a":10,"b":20}'); // 字符串 => 对象
知识点
1.变量类型:值类型 vs 引用类型
- 值类型
var a = 100;
var b = a;
a = 200;
console.log(b); // 100
- 引用类型(对象、数组、函数),引用类型的设计是为了共享内存空间
var a = {age:20};
var b = a;
b.age = 21;
console.log(a.age); // 21
2.变量计算 - 强制类型转换
- 字符串拼接
var a = 100 + 10; // 110
var b = 100 + '10'; // '10010'
- == 运算符
100 == '100' // true
0 == '' // true
null == undefined // true
- if 语句
var a = true;
if (a) { // ... }
var b = 100;
if (b) { // ... }
var c = '';
if (c) { // ... }
- 逻辑运算
console.log(10 && 0); // 0
console.log('' || 'abc'); // 'abc'
console.log(!window.abc); // true
2-5 原型和原型链
题目
如何准确判断一个变量是数组类型?
var arr = [];
arr instanceof Array; // true
typeof arr; // object,typeof 是无法判断是否是数组的
写一个原型链继承的例子?
// 动物
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();
// 写一个封装 dom 查询的例子,演示原型链继承
function Elem(id) {
this.elem = document.getElementById(id);
}
Elem.prototype.html = function (val) {
var elem = this.elem;
if (val) {
elem.innerHTML = val;
return this; // 链式操作
} else {
return elem.innerHTML;
}
}
Elem.prototype.on = function (type, fn) {
var elem = this.elem;
elem.addEventListener(type, fn);
}
var div1 = new Elem('div1');
// console.log(div1.html());
div1.html('<p>hello imooc</p>').on('click', function () {
alert('clicked');
});
描述 new 一个对象的过程?
考点:构造函数
- 创建一个新对象
- this 指向这个新对象
- 执行代码,即对 this 赋值
- 返回 this
function Foo(name, age) {
this.name = name;
this.age = age;
this.class = 'class-1';
// return this; // 默认有这一行
}
var f = new Foo('zhangsan', 20);
zepto (或其他框架)源码中如何使用原型链?
知识点
构造函数
function Foo(name, age) {
this.name = name;
this.age = age;
this.class = 'class-1';
// return this; // 默认有这一行
}
var f = new Foo('zhangsan', 20);
构造函数 - 扩展
var a = {} 其实是 var a = new Object() 的语法糖
var a = [] 其实是 var a = new Array() 的语法糖
function Foo(){...}其实是 var Foo = new Function(...)
使用 instanceof 判断一个函数是否是一个变量的构造函数
原型规则和示例
5条原型规则:原型规则是学习原型链的基础
- 所有的引用类型(数组、对象、函数),都具有对象特性,即可以自由扩展属性(除了'null'以外)
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn () {}
fn.a = 100;
- 所有的引用类型(数组、对象、函数),都具有一个_proto_属性,属性值是一个普通的对象
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);
- 所有的函数,都具有一个prototype属性,属性值也是一个普通的对象
console.log(fn.prototype);
- 所有的引用类型(数组、对象、函数),_proto_属性值指向它的构造函数的'prototype'属性值
console.log(obj.__proto__ === Object.prototype);
- 当试图得到一个引用类型(数组、对象、函数)的某个属性时,如果这个引用类型本身没有这个属性,那么会去它的_proto_(即它的构造函数的 prototype )中寻找
// 构造函数
function Foo(name, age) {
this.name = name;
}
Foo.prototype.alertName = function () {
alert(this.name);
}
// 创建实例
var f = new Foo('zhangsan');
f.printName = function () {
console.log(this.name);
}
// 测试
f.printName();
f.alertName();
补充:循环对象自身的属性
var item
for (item in f) {
if (f.hasOwnProperty(item)) {
console.log(item);
}
}
原型链(顶级原型 Object.prototype)
f.toString(); // 要去 f.__proto__.__proto__ 中去找
instanceof(用于判断引用类型属于哪个构造函数的方法)
解答
第三章 JS基础知识
闭包和作用域
题目
说一下对变量提升的理解?预解析
考点:变量定义和函数声明
说明 this 几种不同的使用场景?
// 作为构造函数执行
// 作为对象属性执行
// 作为普通函数执行
// call apply bind
创建 10 个 <a> 标签,点击的时候弹出来对应的序号?
// 这是错误的写法!
var i, a;
for (i = 0; i < 10; i++) {
a = document.createElement('a');
a.innerHTML = i + '<br>';
a.addEventListener('click', function (e) {
e.preventDefault();
alert(i);
});
document.body.appendChild(a);
}
// 这是正确的写法!
var i;
for (i = 0; i < 10; i++) {
(function (i) {
var a = document.createElement('a');
a.innerHTML = i + '<br>';
a.addEventListener('click', function (e) {
e.preventDefault();
alert(i);
});
document.body.appendChild(a);
})(i);
}
如何理解作用域?
- 自由变量
- 作用域链,即自由变量的查找
- 闭包
实际开发中闭包的应用?
// 实际开发中闭包主要用于封装变量,收敛权限
function isFirstLoad() {
var _list = [];
return function (id) {
if (_list.indexOf(id) >= 0) {
return false;
} else {
_list.push(id);
return true;
}
}
}
// 使用
var firstLoad = isFirstLoad();
firstLoad(10); // true
firstLoad(10); // false
firstLoad(20); // true
知识点
执行上下文
console.log('a is...', a); // undefined
var a = 100;
fn('zhangsan'); // 'zhangsan' 20
function fn(name) {
age = 20
console.log(name, age);
var age
}
- 范围:一段 <script> 或者一个函数
- 全局:变量定义、函数声明
- 函数:变量定义、函数声明、this、arguments
this
this 要在执行时才能确认值,定义时无法确认
var a = {
name: 'A',
fn: function () {
console.log(this.name);
}
}
a.fn(); // this === a
a.fn.call({name: 'B'}); // this === {name: 'B'}
var fn1 = a.fn;
fn1(); // this === window
- 作为构造函数执行
function Foo(name) {
// this = {};
this.name = name;
console.log('this is...', this);
// return this;
}
var f = new Foo('zhangsan');
// this === f
- 作为对象属性执行
var obj = {
name: 'A',
printName: function () {
console.log('this is...', this);
}
};
obj.printName();
// this === obj
- 作为普通函数执行
function fn() {
console.log('this is...', this);
}
fn();
// this === window
- call apply bind (指定第一个参数是 this, 第二个参数是形参)
function fn(name) {
console.log('name is...', name);
console.log('this is...', this);
}
fn.call({x:100}, 'zhangsan');
// this === {x:100}
var fn = function (name) {
console.log('name is...', name);
console.log('this is...', this);
}.bind({x:100});
fn('zhangsan');
// this === {x:100}
作用域
// 无块级作用域
if (true) {
var name = 'zhangsan';
}
console.log(name);
// 函数和全局作用域
var a = 100;
function fn() {
var a = 200;
console.log('fn ', a);
}
console.log('global ', a); // global 100
fn(); // fn 200
- 没有块级作用域
- 只有函数和全局作用域
作用域链
var a = 100;
function fn() {
var b = 200;
// 当前作用域没有定义的变量,即“自由变量”
console.log(a);
console.log(b);
}
fn();
var a = 100;
function fn1() {
var b = 200;
function fn2() {
var c = 300;
console.log(a);
console.log(b);
console.log(c);
}
fn2();
}
fn1();
闭包
闭包的使用场景
- 函数作为返回值
function fn() {
var a = 100;
// 返回一个函数(函数作为返回值)
return function () {
console.log(a);
}
}
// f1 被赋值为一个函数
var f = fn();
var a = 200;
f(); // 100
- 函数作为参数传递
function fn1() {
var a = 100;
return function () {
console.log(a);
}
}
var f1 = fn1();
function fn2(fn) {
var a = 200;
fn();
}
fn2(f1);
解答
第四章 JS基础知识
异步和单线程
题目
同步和异步的区别是什么?分别举一个同步和异步的例子?
一个关于 setTimeout 的笔试题?
前端使用异步的场景有哪些?
知识点
什么是异步(对比同步)
- 异步和同步最大的区别是有没有阻塞程序运行
异步
console.log(100);
setTimeout(function () {
console.log(200);
}, 1000);
console.log(300);
// 执行顺序 100 300 200
同步
console.log(100);
alert(200); // 10秒钟之后点击确认,确认之前,300永远不会被打印
console.log(300);
何时需要异步
- 在可能发生等待的情况
- 等待过程中不能像 alert 一样阻塞程序运行
- 因此,所有“等待的情况”都需要异步
前端使用异步的场景
- 定时任务
- 网络请求
- 事件绑定
// AJAX 请求代码示例
console.log('start');
$.get('/api/data.json', function (data) {
console.log(data);
});
console.log('end');
// <img> 加载示例
console.log('start');
var img = document.createElement('img');
img.onload = function () {
console.log('loaded');
}
img.src = '/xxx.png';
console.log('end');
// 事件绑定示例
console.log('start');
document.getElementById('btn').addEventListener('click', function () {
alert('clicked');
});
console.log('end');
异步和单线程
一次只能干一件事
- 执行第一行,打印100
- 执行 setTimeout 后,传入 setTimeout 的函数会被暂存起来,不会立即执行(单线程的特点,不能同时干两件事)
- 执行最后一行,打印300
- 待所有程序执行完,处于空闲状态时,会立马看有没有暂存起来的要执行
- 发现暂存起来的 setTimeout 中的函数无需等待时间,就立即来过来执行
console.log(100);
setTimeout(function () {
console.log(200);
});
console.log(300);
// 执行顺序 100 300 200
解答
第四章 JS-Web-API
5-1从基础到JSWebAPI
回顾 JS 基础知识
- 变量类型和计算
- 原型和原型链
- 闭包和作用域
- 异步和单线程
- 日期、Math、各种常用API
特点:表面看来并不能用于工作中开发代码
内置函数:Object Array Boolean String ......
内置对象:Math JSON ......
我们连在网页弹出一句 hello world 都不能实现
JS 基础知识:ECMA 262 标准(规定 JS 的基础语法)
JS-Web-API:W3C 标准(规定浏览器提供给开发者操作页面的API和全局变量)
JS 内置的全局函数和对象有哪些?
- window document
浏览器执行的JS = ECMA262 + W3C
Node.js = ECMA262 + IO
5-2 DOM
DOM = Document + Object + Model
题目
DOM 是哪种基本的数据结构?
- 树
DOM 操作的常用 API 有哪些?
DOM 节点的 attr 和 property 有何区别?
知识点
DOM 本质
- 浏览器把拿到的 html 代码,结构化成一个浏览器能识别、JS 可操作的一个模型(JS 对象)。
DOM 节点操作
- 获取 DOM 节点
var div1 = document.getElementById('div1'); // 元素
var divList = document.getElementsByTagName('div'); // 集合
console.log(divList.length);
console.log(divList[0]);
var containerList = document.getElementsByClassName('.container'); //集合
var pList = document.querySelectorAll('p'); // 集合
- property [对象的属性]
var pList = document.querySelectorAll('p');
var p = pList[0];
console.log(p.style.width); // 获取样式
p.style.width = '100px'; // 修改样式
console.log(p.className); // 获取 class
p.className = 'p1'; // 修改 class
// 获取 nodeName 和 nodeType
console.log(p.nodeName);
console.log(p.nodeType);
-
Attribute [标签的属性]
屏幕快照 2019-12-06 下午9.27.18.png
DOM 结构操作
-
增
屏幕快照 2019-12-06 下午9.32.16.png
-
删
屏幕快照 2019-12-06 下午9.33.34.png
-
查
屏幕快照 2019-12-06 下午9.33.17.png
5-8 BOM
BOM = Brower + Object + Model
题目
如何检测浏览器的类型?
拆解 URL 的各部分?
知识点
- navugator
- screen

- location
-
history
屏幕快照 2019-12-06 下午9.42.12.png
6-1 事件绑定
题目
编写一个通用的事件监听函数?
function bindEvent(elem, type, selector, fn) {
if (fn === null) {
fn = selector;
selector = null;
}
elem.addEventListener(type, function (e) {
var target;
if (selector) {
target = e.target;
if (target.matches(selector)) {
fn.call(target, e);
}
} else {
fn(e);
}
});
}
// 使用委托
var div1 = document.getElementById('div1');
bindEvent(div1, 'click', 'a', function (e) {
console.log(this.innerHTML);
});
// 不使用委托
var a1 = document.getElementById('a1');
bindEvent(a1, 'click', function (e) {
console.log(this.innerHTML);
});
描述事件冒泡流程?
对一个无限下拉加载图片的页面,如何给每个图片绑定事件?
知识点
通用事件绑定
var btn = document.getElementById('btn1');
btn.addEventListener('click', function (event) {
console.log('clicked');
});
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn);
}
var a = document.getElementById('link1');
bindEvent(a, 'click', function (e) {
e.preventDefault(); //阻止默认行为
alert('clicked');
})
事件冒泡

事件委托

6-4 AJAX
题目
手动编写一个 AJAX,不依赖第三方库?
跨域的几种实现方式?
知识点
XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open("GET", "/api", false);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
alert(xhr.responseText);
}
}
}
xhr.send(null);
状态码说明


跨域
-
什么是跨域



-
JSONP


-
服务端设置 http header
6-6 存储
题目
请描述一下 cookie, sessionStorage 和 localStorage 的区别?
知识点
cookie
- 本身用于客户端和服务端通信
- 但是它有本地存储的功能,于是就被“借用”
- 使用 document.cookie = ...获取和修改即可
- 只有 4KB
- 请求携带影响效率
- 需要封装才能用
localStorage 和 sessionStorage
- 容量5M
- 不用在请求中携带
- sessionStorage(浏览器关了会清掉)
网友评论