- JSON.stringify
- document.execCommand
- window.getSelection
- document.createRange
- 对象的比较
- this指向
- typeof
- SPA
- null和undefined区别
- bind,call,apply
- reduce
- GC:垃圾回收
- js事件循环和消息队列
- 深浅拷贝
- DOM节点创建
- 清除浮动
- 前端网站优化
- 浏览器渲染页面过程
- 纯函数
- for…of和for…in
- args 剩余参数
- js的分号
- Symbol,Object.keys
- 箭头函数
- 事件传播的三个阶段
- 所有对象都有原型 - 错误
- ++a和a++
- 模板字符串
- eval
- 所有对象的键都会被储存为字符串,set除外
- 注意原型链底层函数中对this的操作会覆盖上层的值
- continue
- setInterval
- promise.all/promise.race
- 值/对象
- Object.definedProperty
- import/export
- Object.assign
- 队列
- Object.create
- css变量
- CSS变量不合法的缺省特性
- Reflect作用
- 类class
- UML类图
- delete操作符
- AMD,CMD
- 函数参数传递
- 对象的拷贝
- 页面禁用缓存
- 按位索引简写
- Switch 简写
JSON.stringify
JSON.stringify(value[, replacer [, space]])
第二个参数:可以是一个函数或者一个数组
- 为函数时:
(key, value) => value
,返回的是value值 - 为数组时:只保留数组的值代表将被序列化成 JSON 字符串的属性名
第三个参数:控制结果字符串的间距
document.execCommand
bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
aCommandName:命令名称
aShowDefaultUI:展示用户界面,Mozilla 没有实现,设置为false即可
aValueArgument:一些命令的额外参数,默认为null
允许命令操作可编辑区域的元素
dom元素设置contentEditable属性为true
window.getSelection
let s = window.getSelection()
s.getRangeAt(0)
// s.toString() 获取到选择的文字
// 等价于 s + ''
document.createRange
返回一个Range对象
var range = document.createRange();
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
eg. https://www.jianshu.com/p/ad2f818cc3b0
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>range</title>
</head>
<body>
<p id="p">
<b>Use the buttons below</b> to select or deselect the contents of this
paragraph.
</p>
<p>
2. Use the buttons below to select or deselect the contents of this
paragraph.
</p>
<p>
3. Use the buttons below to select or deselect the contents of this
paragraph.
</p>
<p>
4. Use the buttons below to select or deselect the contents of this
paragraph.
</p>
<div id="d">5. Use the buttons below to select or deselect the contents of this paragraph.</div>
<button id="select-button">Select paragraph</button>
<button id="deselect-button">Deselect paragraph</button>
<button id="set-start-button">Set Start</button>
<button id="set-end-button">Set End</button>
<button onclick="deleteChar()">删除文字</button>
<script>
const p = document.getElementById("p");
const selectButton = document.getElementById("select-button");
const deselectButton = document.getElementById("deselect-button");
const setStartBtn = document.getElementById("set-start-button");
const setEndBtn = document.getElementById("set-end-button");
selectButton.addEventListener("click", (e) => {
// Clear any current selection
const selection = window.getSelection();
selection.removeAllRanges();
// Select paragraph
const range = document.createRange();
range.selectNodeContents(p);
selection.addRange(range);
});
deselectButton.addEventListener("click", (e) => {
const selection = window.getSelection();
selection.removeAllRanges();
});
setStartBtn.addEventListener("click", (e) => {
var range = document.createRange();
var startNode = document.getElementsByTagName("p").item(2);
var startOffset = 0;
range.setStart(startNode, startOffset);
var endNode = document.getElementsByTagName("p").item(3);
var endOffset = endNode.childNodes.length;
range.setEnd(endNode, endOffset);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
});
setEndBtn.addEventListener("click", (e) => {
var range = document.createRange();
var endNode = document.getElementsByTagName("p").item(3);
var endOffset = endNode.childNodes.length;
range.setEnd(endNode, endOffset);
});
function deleteChar() {
var div = document.getElementById("d");
var textNode = div.firstChild;
var range = document.createRange();
range.setStart(textNode, 1);
range.setEnd(textNode, 4);
range.deleteContents();
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>1212</title>
<script type="application/javascript">
function delrow() {
var table = document.getElementById("mytable");
if (table.rows.length > 0) {
var row = table.rows[0];
var rangeObj = document.createRange();
rangeObj.setStartBefore(row);
rangeObj.setEndAfter(row);
rangeObj.deleteContents();
}
}
</script>
</head>
<body>
<table id="mytable" border="1">
<tr>
<td>内容1</td>
<td>内容2</td>
</tr>
<tr>
<td>内容3</td>
<td>内容4</td>
</tr>
</table>
<button onclick="delrow()">删除第一行</button>
</body>
</html>
对象的比较
当比较两边有对象时,先调用对象的toString方法转为原始类型字符串,然后比较;当string和boolean比较时,2个都先转换为number类型比较
而数组转为原始类型时,会调用数组内部的join方法
this指向
在函数中,this的指向是函数的执行环境,this取决于其被谁调用的,而不是被谁定义的
this指向是它所在上下文(定义时的位置)的环境
typeof
typeof返回的时字符串
SPA
优点:
- 用户体验好,快,内容改变不需要加载整个页面,避免了不必要的跳转和页面加载
- 减少服务器压力
- 前后端职责分明,架构清晰,前端交互逻辑,后端数据处理
缺点:
- 初次加载耗时多,需要将js,css统一加载,部分页面按需加载
- 前进后退路由管理,不能使用浏览器的前进后退功能
- SEO难度大,所有内容在一个页面动态替换,所以SEO比较弱势
null和undefined区别
- null指空值,undefined指未定义
- null在Number(null)转换为0,undefined在Number(undefined)转换为NaN
- 在使用场景上
- null
- 作为函数的参数,该函数的参数不是对象
- null代表对象的原型链的终点
- undefined
- 变量被声明了,但是未赋值,就是undefined
- 调用函数时,未提供需要的参数,为undefined
- 对象属性没有赋值,该属性的值为undefined
- 函数没有返回值,默认返回undefined
- null
bind,call,apply
可以传递我们想要的this关键词引用的对象
bind方法返回函数的拷贝值,但带有绑定的上下文,它不会立即执行
call方法会立即执行
apply方法也会立即执行
call和apply传参方式不同,call是传值,apply是传数组
reduce
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
initialValue:第一次调用callback函数的第一个参数的值。如果没有提供,则将使用数组的第一个元素。在没有初始值的空数组上调用reduce将报错
GC:垃圾回收
浏览器帮我们释放内存eval
,try
,catch
,with
不会被回收
eval会欺骗词法作用域
with会创建新的作用域
js事件循环和消息队列
promise
优先于setTimeout
宏任务promise
一旦被定义,就会立即执行Promise
的reject
和resolve
是异步执行,resolve()
会被放到回调队列,在主函数执行完和setTimeout
之前调用await
执行完会让出线程。async
标记的函数返回一个Promise
对象
深浅拷贝
js数据类型分为基本数据类型和引用数据类型,基本数据类型保存的是值,引用类型保存的是引用地址。浅拷贝拷贝的是内存地址,深拷贝是开辟新的内存地址
DOM节点创建
- createElement
- createTextNode
- createDocumentFragment:临时节点
节点操作:
- appendChild
- insertBefore(newNode, refNode)
- removeChild
- replaceChild
清除浮动
- 父元素增加高度撑开
- 浮动元素结尾增加空标签,设置clear: both
- 父元素设置overflow: hidden
- 父元素添加伪类:after和zoom
前端网站优化
减少资源大小:
- 压缩js,css,html文件
- 符合条件的图标转为base64
- 按需加载(UI组件库)
- SPA项目,路由按需加载(import)
- Nginx开启gzip
提高加载速度:
- 图片CDN加速
- 页面使用骨架屏,提高首页加载速度
- 设置缓存
资源加载方式:
- 图片CDN加速
减少请求次数:
加载时机优化:
- 样式表放首部,js代码放尾部
link/src增加rel属性,设置prefetch/preload可预加载资源
使用图片懒加载
- 使用JPEG 2000,JPEG XG,WepP的图片格式代替现有的jpeg和png
浏览器渲染页面过程
- 解析HTML,生成DOM树
- 解析Css,生成CSSOM树
- 将DOM树和CSSOM树关联,生成渲染树
- 布局render树(Layout/reflow),负责个元素的尺寸和位置的计算
- 绘制render树(paint),绘制页面像素信息
- 将像素发送给GPU,展示在页面上
纯函数
如果输入的参数相同,无论何时调用,都会得到相同的输出结果,就是纯函数
for…of和for…in
for…of循环,迭代可迭代对象
for…in循环,遍历一个对象自有的,继承的,可枚举的,非Symbol的属性
args 剩余参数
...args
剩余参数,值是一个包含所有剩余参数的数组,并且只能作为最后一个参数
js的分号
JS引擎会在语句之后自动添加上分号(自动分号插入),一个语句可以是变量,也可以是**throw**
,**return**
,**break**
等关键字
Symbol,Object.keys
Symbol类型是不可枚举的,但是可以使用Object.getOwnPropertySymbols()
访问symbol
Object.keys是返回对象上所有可枚举的键
箭头函数
箭头函数返回的是一个对象时,必须在圆括号之间编写
getUser = (user) => ({ name: user.name, age: user.age })
getList = ([x, ...y]) => [x, y]
// 这种情况下,会报错SyntaxError
getUser1 = (user) => { name: user.name, age: user.age }
事件传播的三个阶段
捕获阶段 => 目标 => 冒泡
捕获阶段事件通过父元素向下传递到目标元素,开始冒泡
默认情况下,事件处理程序在冒泡阶段执行
所有对象都有原型 - 错误
除基础对象外的所有对象都有原型
基础对象是指原型链终点的对象,**null**
typeof null
==> “object”
++a和a++
a++:先返回,再加
++a:先加,在返回
let number = 0;
console.log(number++);
console.log(++number);
console.log(number);
// 0 2 2
模板字符串
如果使用模板字符串,则第一个参数的值始终是字符串值的数组,其余参数获取传递到模板字符串中的表达式的值
function getPersonInfo(one, two, three) {
console.log(one);
console.log(two);
console.log(three);
}
const person = "Lydia";
const age = 21;
getPersonInfo`${person} is ${age} years old`;
// ["", "is", "years old"] Lydia 21
eval
eval会为字符串传递的代码求值
所有对象的键都会被储存为字符串,set除外
注意原型链底层函数中对this的操作会覆盖上层的值
continue
for (let i = 1; i < 5; i++) {
if (i === 3) continue;
console.log(i);
}
// 1 2 4
如果某个条件返回true
,则continue
跳过迭代
setInterval
返回值是一个唯一的**id**
promise.all/promise.race
https://juejin.cn/post/6844904077537574919#heading-26
promise.all:将多个Promise实例包装成一个新的promise实例,成功返回的是一个结果数组,失败的话返回最先被reject失败状态的值。在处理多个异步处理的时很有用
promise.race:赛跑的意思,Promise.race([p1, p2, p3])
哪个结果获得的快就返回哪个的值,不管结果本身是成功状态还是失败状态
then和catch返回的也是promise对象
值/对象
普通参数是值的传递,复制对象复制的是对象的引用,所以改变
对参数进行值传递时,会创建一份该值的复制
function getInfo(member, year) {
member.name = 'b'
year = '1998'
}
const person = {name: 'a'}
const birthDay = '1997'
getInfo(person, birthDay)
console.log(person, birthDay)
// { name: 'b' } '1997'
Object.definedProperty
此方法添加得属性,默认为不可枚举的Object.keys
返回对象中可枚举的属性writable
,enumerable
,configurable
import/export
import命令是编译阶段执行的,在代码运行之前。所以被导入的模块先运行,导入模块的文件后运行
commonjs中require和import的区别:require后,可以在运行代码时根据需要加载依赖项。
// index.js
console.log("running index.js");
import { sum } from "./sum.js";
console.log(sum(1, 2));
// sum.js
console.log("running sum.js");
export const sum = (a, b) => a + b;
// running sum.js running index.js 3
// 用require加载 打印:running index.js running sum.js 3
Object.assign
拷贝源对象自身可枚举的属性到目标对象。
如果源值是一个对象引用,只会复制其引用值。
let obj1 = {a: 0, b: {c: 0}}
let obj2 = Object.assign({}, obj1)
obj1.a = 1
console.log(obj2)
obj2.a = 2
console.log(obj1)
obj1.b.c = 1
console.log(obj2)
obj2.b.c = 2
console.log(obj1)
队列
表的前端删除,表的后端插入操作
先进先出
Object.create
创建新对象,原型指向 oldArrayPrototype,再扩展新的方法不会影响原型
// 重新定义数组原型
const oldArrayPrototype = Array.prototype
// 创建新对象,原型指向 oldArrayPrototype,再扩展新的方法不会影响原型
const arrProto = Object.create(oldArrayPrototype)
arrProto.push = function(){
console.log(100)
}
console.log(arrProto.__proto__.push)
css变量
https://www.zhangxinxu.com/wordpress/2016/11/css-css3-variables-var/
https://www.zhangxinxu.com/wordpress/2018/11/html-js-set-css-css3-var%e5%8f%98%e9%87%8f/
IE浏览器不支持CSS变量,试试参考这个Github项目:https://github.com/jhildenbiddle/css-vars-ponyfill
语法:var( <custom-property-name> [, <declaration-value> ]? )
var( <自定义属性名> [, <默认值 ]? )
.box {
--1: #369;
}
body {
background-color: var(--1, #cd0000);
}
// 背景为#cd0000
CSS变量不合法的缺省特性
body {
--color: 20px;
background-color: #369;
background-color: var(--color, #cd0000);
}
==> 转化为
body {
--color: 20px;
background-color: #369;
background-color: transparent;
}
Reflect作用
- 与Proxy能力一一对应
- 规范化,标准化,函数式 ```javascript const obj = {a: 1, b: 2} // ‘a’ in obj // Reflect.has(obj, ‘a’)
// delete obj.a // Reflect.deleteProperty(obj, ‘a’)
- 代替Object的工具函数
```javascript
const obj = {a: 1, b: 2}
// Object.getOwnPropertyNames(obj)
// Reflect.ownKeys(obj)
类class
- 继承
- 封装
- 实例出来的对象 访问 protected 和 private 的属性,是会报错的 (在typescript中)
多态
- 父类定义方法,子类去覆盖
面向接口编程
class jQuery {
constructor(selector) {
let slice = Array.prototype.slice
let dom = slice.call(document.querySelectorAll(selector))
let len = dom ? dom.length : 0
for (let i = 0; i < len; i++) {
this[i] = dom[i]
}
this.length = len
this.selector = selector || ''
}
append(node) {
}
addClass(name) {
}
html(data) {
}
// 此处省略若干 API
}
window.$ = function (selector) {
return new jQuery(selector)
}
UML类图
delete操作符
delete操作符删除的是对象上的属性
AMD,CMD
AMD
- 依赖前置
- 提前执行
- 用户体验好,没有延迟,依赖模块提前执行了
CMD
- 依赖就近
- 延迟执行
- 性能好,用户需要时才执行
函数参数传递
函数的参数是按值传递的
把函数外部的值复制给函数内部的参数,就是把一个值复制到另一个变量一样
而引用类型是按引用传递,也就是传入函数的是原始值的地址,因此在函数内部修改参数,将会影响到原始值。
对象的拷贝
https://www.html.cn/archives/8319
页面禁用缓存
可以在 css 和 js文件链接上加入版本号
按位索引简写
if(arr.indexOf(item) > -1) {} ====================================> if(~arr.indexOf(item)) {}
if(arr.indexOf(item) === -1) {} ====================================> if(!~arr.indexOf(item)) {}
:::danger 〜)运算符将返回除-1以外的任何值的真实值。** :::
Switch 简写
switch (data){
case 1:
t1();
break;
case 2:
t2();
break;
case 3:
t3();
break;
}
======>转化为
let data = {
1: t1,
2: t2,
3: t3,
}
data[something] && data[something]();