第一章:JS 基础上篇(js 类型)
- 值类型
var a = 100
var b = a
a = 200
console.log(b) // 100
- 引用类型
var a = {age:100}
var b = a
a.age = 200
console.log(a.age) // 200
问题:为什么对值类型和引用类型进行修改会出现不同的结果呢?
答:值类型:存的是具体的数值,比如 a=200,那么 a 变量内存中地址存的就是 200。所以改变 a=100 ,仅仅只是影响到了 a。
引用类型:内存中存的是对象的地址,所以 a 和 b 此刻指向了同一个对象的地址。改变 a.age 就会同时影响到 b.age。
- 引用类型包括
对象、数组、函数(为什么需要用到引用呢?因为这些类型可能非常大,每次赋值都新建一个新对象,就会比较浪费空间) - typeof 运算符
typeof undefined // undefined
typeof 'abc' // string
typeof 123 // number
typeof true // boolean
typeof {} // object
typeof [] // object
typeof null // object (它也是引用类型)
typeof console.log // function
结论: typeof 能区分值类型;对于引用类型只能区分 function 其他无法区分。
- 问:JS 中有哪些内置函数 -- 数据封装类对象
答:
Object
Array
Boolean
Number
String
Function
Date
RegExp
Error
第二章:JS 基础上篇(原型和原型链)
- var a = {} 其实是 var a = new Object() 的语法糖
- var a = [] 其实是 var a = new Array() 的语法糖
- function Foo(){...} 其实是 var Foo = new Function(){...}
- 使用 instanceof 判断一个函数是否是一个变量的构造函数.
总结:引用类型都有一个构造函数
- 下写一个原型链继承的例子
function Animal() {
this.eat = function () {
console.log('animal eat')
}
}
function Dog() {
this.bark = function () {
console.log('dog bark')
}
}
Dog.prototype = new Animal();
let hashiqi = new Dog()
hashiqi.bark()
hashiqi.eat()
- 描述 new 一个对象的过程
- 创建一个新对象
- this 指向这个新对象
- 执行代码,即对 this 赋值
- 返回 this
第三章:JS 基础中篇(作用域和闭包)
- 表达式和声明的区别
fn() // 输出: fn
// fn1() // 输出: fn1 is not a function
console.log(a); // 输出: undefined
// 这个叫做"声明"
function fn() {
console.log('fn');
}
// 这个叫做"表达式"
var fn1 = function () {
console.log('fn1');
}
// 这个叫做"表达式"
var a = 100;
- JavaScript 解释器中存在一种变量声明被提升的机制,也就是说函数声明会被提升到作用域的最前面,即使写代码的时候是写在最后面,也还是会被提升至最前面。
- 而函数表达式创建的函数是在运行时进行赋值,且要等到表达式赋值完成后才能调用。
前面的函数,相当于如下写法:
// 这个叫做"函数声明"
function fn() {
console.log('fn');
}
var a = undefined;
var fn1 = undefined;
fn() // 输出: fn
// fn1() // error: fn1 is not a function
console.log(fn1); // 输出: undefined
console.log(a); // 输出: undefined
// 这个叫做"表达式"
var fn1 = function () {
console.log('fn1');
}
// 这个叫做"表达式"
var a = 100;
2.函数内部会默认有 this 和 arguments 自带变量
fn('zhansan')
function fn(name) {
console.log(this); //输出:复杂对象
console.log(arguments); //输出:{ '0': 'zhansan' }
age = 20
console.log(name, age); //输出:zhansan 20
var age
}
- this 要在执行时才能确认值,定义时无法确认
let a = {
name: 'A',
fn: function () {
console.log(this.name)
// console.log(this)
}
}
a.fn() // this === a
a.fn.call({ name: 'B' }) // this === {name:'B'}
this.name = 'here'
this.fn1 = a.fn
this.fn1() // this === window
- JavaScript 无块级作用域
if (true) {
var name = 'zhansan'
}
console.log(name); // 输出: name === 'zhansan'
- JavaScript 有 函数作用域和全局作用域
var a = 'global'
function fn() {
var a = 'function'
console.log(a);
}
fn() // 输出 'fn'
console.log(a); // 输出 'global'
6.作用域链:就是函数定义的时候,内部使用的变量没有进行定义,会向父级作用域寻找该变量。
函数作用域中使用没有在本函数作用域中的变量叫做自由变量:自由变量的定义一定是在定义时候的父级作用域去寻找。
var a = 100
function F1(){
var b = 200
function F2(){
var c = 300
console.log(a);
console.log(b);
console.log(c);
}
F2()
}
F1()
- 闭包-闭包的定义,自己从下面 代码一作为返回值、代码二作为参数 中体会。
// 代码一:闭包作为返回值
function F1() {
var a = 100
// 返回一个函数(函数作为返回值)
return function(){
console.log(a); // 自由变量,父级作用域寻找
}
}
// f1 得到一个函数
var f1 = F1()
var a = 200
f1() // 输出: 100
// 代码二:闭包作为参数值
function F1() {
var a = 100
// 返回一个函数(函数作为返回值)
return function(){
console.log(a); // 自由变量,父级作用域寻找
}
}
// f1 得到一个函数
var f1 = F1()
function F2(fn) {
var a = 200
fn()
}
F2(f1) // 依然输出: 100
闭包使用的时候经常会搞不清楚自由变量是什么?请返回阅读上一条自由变量相关内容。
- 闭包实际应用中主要用于封装变量,收敛权限。
function isFirstLoad() {
var _list = []
return function (id) {
if (_list.indexOf(id) >= 0) {
return false
} else {
_list.push(id)
return true
}
}
}
// 使用
var firstLoad = isFirstLoad()
console.log(firstLoad(10)); // true
console.log(firstLoad(10)); // false
console.log(firstLoad(20)); // true
上面的代码,使用闭包,就会将 _list 很好的隐藏起来,保护它的其他操作权限。
第四章:JS 基础下篇(异步和单线程、其他知识点)
- 什么是异步?什么是同步?setTimeout() 就是异步(不阻塞代码),alert()就是同步(阻塞代码)。
- 什么是单线程?就是一次只能做一件事情,类似一次执行一行代码。
- 日期
Date.now() // 获取当前时间毫秒数
var dt = new Date()
dt.getTime() // 获取毫秒数
dt.getFullYear() // 年
dt.getMonth() // 月(0-1)注意:这里是比较特殊
dt.getDate() // 日 (1-31)
dt.gatHours() // 小时(0-23)
dt.getMinutes() // 分钟 (0-59)
dt.getSeconds() // 秒 (0-59)
- math 主要应用:math.random() 获取一个 0-1 之间的随机数
第五章:JS-Web-API 上篇(DOM 、 BOM)
- 常说的 JS(浏览器执行的 JS)包含两部分:
① JS 基础知识( ECMA262 标准 )
② JS-Web-API( W3C 标准 )
- DOM 的本质是什么?
浏览器把拿到的 HTML 代码,结构化成一个浏览器能识别并且 JS 可操作的一个模型而已。
- 获取 DOM 节点(最常用的几种)
var div1 = document.getElementById('div1') //元素
var divList = document.getElementsByTagName('div') //集合
var containerList = document.getElementsByClassName('container') //集合
console.log(divList.length)
console.log(divList[0])
console.log(containerList.length)
var pList = document.querySelectorAll('p') //集合
var p = pList[0]
console.log(p.style.width)
p.style.width = '200px' // 改变宽度
console.log(p.style.width)
console.log(p.className)
p.className = 'p2class'
// 获取 nodeName 和 nodeType
console.log(p.nodeName)
console.log(p.nodeType)
- Property 和 Attribute 中文翻译都是‘属性’,有什么不同呢?
var pList = document.querySelectorAll('p') //集合
var p = pList[0]
p.style.width // 这里就是 property 改的是 JS 对象的属性
p.setAttribute('data-name', 'helloworld') // 改的是 dom 文档的属性
p.setAttribute('style', 'font-size: 26px;')
console.log(p.getAttribute('data-name'))
console.log(p.getAttribute('style'))
- navigator & screen (BOM 内置变量)
// navigator 判断浏览器
var ua = navigator.userAgent
var isChrome = ua.indexOf('Chrome')
console.log(!!isChrome)
// screen 判断窗体大小
console.log(screen.width)
console.log(screen.height)
- location & history
// location
console.log(location.href) // 'https://www.baidu.com/s?wd=aaa'
console.log(location.protocol) // 'https:'
console.log(location.host) // www.baidu.com
console.log(location.pathname) // '/s'
console.log(location.search) // ?号后面的内容 wd=aaa
// history
history.back()
history.forward()
第六章:JS-Web-API 下篇(事件、跨域、存储)
- 通用事件绑定(写一个通用事件绑定方法,可以减少方法名长度)
event.preventDefault() // 阻止控件的默认事件
var btn = document.getElementById('btn1')
btn.addEventListener('click',(event)=>{
console.log('click')
})
function bindEvent(element, type, fn) {
element.addEventListener(type, fn)
}
var a = document.getElementById('link1')
bindEvent(a, 'click', (event)=> {
event.preventDefault() // 阻止 a 标签默认行为
alert('clicked')
})
- 事件冒泡
event.stopPropagation() // 阻止事件冒泡
问:如何让所有
绑定点击事件,使得点击激活;执行激活操作,点击取消,执行取消操作。
激活
取消
取消
取消
取消
取消
取消
取消
答:根据事件冒泡原理,我们可以先绑定 body 的事件。
- 问题如下:如何让程序实现点击 a 标签,弹出 a 标签内的内容?
答:通过 event.target 可以获取点击事件触发的最顶层控件
- 什么是跨域?
- 浏览器有同源策略,不允许 ajax 访问其他域接口。
- 跨域条件:协议、域名、端口,有一个不同就算跨域。
- 有哪三个标签运行跨域访问?
- 三个标签的特殊应用场景?
用于打点统计,统计网站可能是其他域
- 本地存储之 cookie
- 本身用于客户端和服务器端通信
- 但是它有本地存储的功能,于是就被“借用”
- 使用 document.cookie = ... 获取和修改即可
- cookie 用于存储的缺点
- 存储量太小,只有 4KB
- 所有 http 请求都带着,会影响获取资源的效率
- API 简单,需要封装才能用 document.cookie = ...
- locationStorage 和 sessionStorage
- HTML5 专门为存储而设计,最大容量 5M
- API 简单易用
- localStorage.setItem(key, value); localStorage.getItem(key);
- locationStorage 和 sessionStorage
- iOS safari 隐藏模式下
- localStorage.getItem 会报错
- 建议统一使用 try-catch 封装
第七章:模块化
- 先看不用模块化的代码会出现的问题。有如下说明代码:
// util.js function getFormatDate(date, type){ // type === 1 返回 2019-04-30 // type === 2 返回 2019 年4 月 15 日 // ... } // a-util.js function aGetFormatDate(date) { // 要求返回 返回 2019 年4 月 15 日 格式 return getFormatDate(date, 2) } // a.js let dt = new Date() console.log(aGetFormatDate(dt))
对于上述代码的调用:
- 这些代码中的函数必须是全局变量,才能暴露给使用方。容易造成全局变量污染。
- a.js 知道药引用 a-util.js ,但是他知道还需要依赖于 util.js 吗?
- 使用模块化。有如下说明代码:
// util.js export { getFormatDate: function (date, type){ // type === 1 返回 2019-04-30 // type === 2 返回 2019 年4 月 15 日 // ... } } // a-util.js var getFormatDate = require('util.js') export { aGetFormatDate: function (date){ return getFormatDate(date, 2) } } // a.js var aGetFormatDate = require('a-util.js') let dt = new Date() console.log(aGetFormatDate(dt))
模块化的代码有如下好处:
- 直接
,其他的根据依赖关系自动引用。
- 那两个函数,没必要做成全局变量,不会来带污染和覆盖。
第八章:运行环境
- 浏览器加载一个资源的过程
- 浏览器根据 DNS 服务器得到域名的 IP 地址
- 向这个 IP 的机器发送 http 请求
- 服务器收到、处理并返回 http 请求
- 浏览器得到返回内容
- 浏览器渲染页面的过程
- 根据 HTML 结构生成 DOM Tree
- 根据 CSS 生成 CSSOM
- 将 DOM 和 CSSOM 整合形成 RenderTree
- 根据 RenderTree 开始渲染和展示
- 遇到