16. 解释 jsonp 的原理,为何它不是真正的ajax ?
同源策略和跨域 (ノ°▽°)ノ 冲鸭!征服她!!!
浏览器的同源策略(服务端没有同源策略)和跨域
后端如何nginx, 我们一般称为转发,不称为跨域
哪些html 标签能绕过跨域?
加载图片 CSS JS 可无视同源策略
<img src="跨域的图片地址" />
<link href="跨域的css地址" />
<script src="跨域的js地址"></script>
jsonp原理
简易代码示例:
后端被请求文件:jsonp.js (由后端处理拼接生成)
// jsonp.js 文件内容
abc(
{ name: 'xxx' }
)
前端请求代码:
<script>
window.abc = function (data) {
console.log(data)
}
</script>
<script src="http://localhost:8002/jsonp.js?username=xxx&callback=abc"></script>
17. document load 和 ready 的区别
window.addEventListener('load', function () {
// 页面的全部资源加载完才会执行,包括图片,视频等
})
document.addEventListener('DOMContentLoaded', function () {
// DOM 渲染完即可执行,此时图片,视频还可能没有加载完
})
18. == 和 === 的区别
JS基础知识:变量的类型和计算
== 会尝试类型转换
=== 严格相等
哪些场景才用 == ?
19. 函数声明和函数表达式的区别
函数声明 function fn() {...}
函数表达式 const fn = function() {...}
函数声明会在代码执行前预加载,而函数表达式不会
// 函数声明
const res = sum(10, 20)
console.log(res) // 30
function sum(x, y) {
return x + y
}
// 函数表达式
var res = sum(10, 20)
console.log(res) // 报错:sum is not a function
var sum = function (x, y) {
return x + y
}
20. new Object() 和 Object.create()的区别
前提:要先明白原型和原型链 JS基础知识:原型和原型链
{} 等同于 new Object(), 原型 Object.prototype
Object.create(null) 没有原型, 必须传个参数
Object.create({…}) 可指定原型
Object.create({…}) : 创建一个空对象,把原型__proto__ 指向传入的对象
代码示例:
const obj1 = {
a: 10,
b: 20,
sum() {
return this.a + this.b
}
}
const obj2 = new Object({
a: 10,
b: 20,
sum() {
return this.a + this.b
}
})
const obj21 = new Object(obj1) // obj21 === obj1
const obj3 = Object.create(null)
const obj4 = new Object() // {}
const obj5 = Object.create({
a: 10,
b: 20,
sum() {
return this.a + this.b
}
})
const obj6 = Object.create(obj1) // obj6.__proto__ == obj1
21. 关于 this 的场景题
const User = {
count: 1,
getCount: function() {
return this.count
}
}
console.log(User.getCount()) // 1
const func = User.getCount()
console.log(func()) // func is not a function
this 的指向:看它执行的时候
22. 关于作用域和自由变量的场景题-1
let i
for(i = 1; i<=3; i++){
setTimeout(function() {
console.log(i) // 4 4 4
}, 0)
}
23. 判断字符串以字母开头,后面字母数字下划线,长度 6 - 30
const reg = /^[a-zA-Z]\w{5,29}$/
学习正则表达式的规则
手写常见的正则表达式
网上有很多教程,自行学习
24. 关于作用域和自由变量的场景题-2
let a = 100
function test() {
alert(a)
a = 10
alert(a)
}
test()
alert(a)
// 100 10 10
25. 手写字符串 trim 方法,保证浏览器兼容性
作用:去除字符串开头和结尾的空字符串
// 原型,this,正则表达式
String.prototype.trim = function () {
return this.replace(/^\s+/,'').replace(/\s+$/,'')
}
26. 如何获取多个数字中的最大值
方法一:
// 获取多个数字中的最大值
function max() {
const nums = Array.prototype.slice.call(arguments) // 变为数组
let max = 0
nums.forEach(n => {
if (n > max) {
max = n
}
})
return max
}
方法二:使用Math API
Math.max(10,20,46,5)
1
27. 如何用JS实现继承?
class 继承 (推荐)
prototype 继承 (ES5的继承方式,不推荐使用)
28. 如何捕获JS程序中的异常?
方式一:
try {
// todo
} catch (ex) {
console.error(ex) // 手动捕获 catch
} finally {
// todo
}
方式二:
// 自动捕获
window.onerror = function (message, source, lineNum, colNum, error) {
// 注意:
// 对于跨域的JS,如 CDN 的,不会有详细的报错信息
// 对于压缩的JS, 还要配合 sourceMap 反查到未压缩代码的行,列
}
29. 什么是JSON?
json 是一种数据格式,本质是一段字符串
json 格式和JS对象结构一致,对JS语言更加友好
window.JSON 是一个全局对象: JSON.stringify :把对象转换成json字符串 JSON.parse :把字符串转换成对象
30. 获取当前页面的url 参数
传统方式:查找 ·location.search
新API, URLSearchParams
代码示例:
浏览器输入:http://127.0.0.1:8080/index.html?a=10&b=20&c=30
// 传统方式
function query(name) {
const search = location.search.substr(1) // 类似 array.slice(1)
// search: 'a=10&b=20&c=30'
const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`, 'i')
const res = search.match(reg) // search字符串来匹配reg表达式
if (res === null) {
return null
}
return res[2]
}
console.log(query('a')) // 10
// URLSearchParams
function query(name) {
const search = location.search
const p = new URLSearchParams(search)
return p.get(name)
}
console.log( query('b') ) // 20
31. 将url 参数解析为JS对象
方式一:
// 传统方式,分析 search
function queryToObj() {
const res = {}
const search = location.search.substr(1) // 去掉前面的'?'
search.split('&').forEach(paramStr => {
const arr = paramStr.split('=')
const key = arr[0]
const val = arr[1]
res[key] = val
})
return res
}
方式二:
// 使用URLSearchParams
function queryToObj() {
const res = {}
const pList = new URLSearchParams(location.search)
pList.forEach((val, key) => {
res[key] = val
})
return res
}
32. 手写数组 flatern, 考虑多层级
作用效果如下:
flat([[1,2], 3, [4, 5, [6, 7, [8, 9, [10, 11]]]]])
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
一层数组可以用如下方法拍平:
多层数组需要递归:
function flat(arr) {
// 验证 arr 中,还有没有深层数组 [1, 2, [3, 4]]
const isDeep = arr.some(item => item instanceof Array) // arr数组中只要有一个元素符合Array类型
if (!isDeep) {
return arr // 已经是 flatern [1, 2, 3, 4]
}
const res = Array.prototype.concat.apply([], arr)
return flat(res) // 递归
}
const res = flat( [1, 2, [3, 4, [10, 20, [100, 200]]], 5] )
console.log(res) // [1, 2, 3, 4, 10, 20, 100, 200, 5]
33. 数组去重
传统方式,遍历元素,挨个比较,去重
使用Set
考虑计算效率
方式一:
// 传统方式
function unique(arr) {
const res = []
arr.forEach(item => {
if (res.indexOf(item) < 0) {
res.push(item)
}
})
return res
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res) //[30, 10, 20, 40]
方式二:
// 使用 Set (无序,不能重复)
function unique(arr) {
const set = new Set(arr)
return [...set]
}
const res = unique([30, 10, 20, 30, 40, 10])
console.log(res) //[30, 10, 20, 40]
建议: 能使用Set就使用Set。 Set比较快,传统方式需要循环。兼容性和速度看需求。
34. 手写深拷贝
JS基础知识:变量的类型和计算
注意: Object.assign 不是深拷贝!只拷贝了一层
/**
* 深拷贝
*/
const obj1 = {
age: 20,
name: 'xxx',
address: {
city: 'beijing'
},
arr: ['a', 'b', 'c']
}
const obj2 = deepClone(obj1)
obj2.address.city = 'shanghai'
obj2.arr[0] = 'a1'
console.log(obj1.address.city)
console.log(obj1.arr[0])
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
// obj 是 null ,或者不是对象和数组,直接返回
return obj
}
// 初始化返回结果
let result
if (obj instanceof Array) {
result = []
} else {
result = {}
}
for (let key in obj) {
// 保证 key 不是原型的属性
if (obj.hasOwnProperty(key)) {
// 递归调用!!!
result[key] = deepClone(obj[key])
}
}
// 返回结果
return result
}
35. 介绍一下 RAF requestAnimationFrame
想要动画流畅,更新频率要60帧/s, 即 16.67ms 更新一次视图
setTimeout 要手动控制频率,而 RAF 浏览器会自动控制
后台标签或隐藏iframe中,RAF会暂停,而 setTimeout 依然执行
代码演示:
html 部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>JS 真题演示</title>
<style>
#div1 {
width: 100px;
height: 50px;
background-color: red;
}
</style>
</head>
<body>
<p>JS 真题演示</p>
<div id="div1"></div>
<script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.js"></script>
<script src="./RAF.js"></script>
</body>
</html>
JS部分:
方式一:setTimeout
// 3s 把宽度从 100px 变为 640px ,即增加 540px
// 60帧/s ,3s 180 帧 ,每次变化 3px
const $div1 = $('#div1')
let curWidth = 100
const maxWidth = 640
// setTimeout
function animate() {
curWidth = curWidth + 3
$div1.css('width', curWidth)
if (curWidth < maxWidth) {
setTimeout(animate, 16.7) // 自己控制时间
}
}
animate()
方式二:RAF
// 3s 把宽度从 100px 变为 640px ,即增加 540px
// 60帧/s ,3s 180 帧 ,每次变化 3px
const $div1 = $('#div1')
let curWidth = 100
const maxWidth = 640
// RAF
function animate() {
curWidth = curWidth + 3
$div1.css('width', curWidth)
if (curWidth < maxWidth) {
window.requestAnimationFrame(animate) // 时间不用自己控制
}
}
animate()
36. 前端性能如何优化?一般从哪几个方面考虑?
原则:多使用内存,缓存,减少计算,减少网络请求
方向:加载页面,页面渲染,页面操作流畅度
|
|