A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

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. 前端性能如何优化?一般从哪几个方面考虑?
原则:多使用内存,缓存,减少计算,减少网络请求
方向:加载页面,页面渲染,页面操作流畅度


0 个回复

您需要登录后才可以回帖 登录 | 加入黑马