js输出题
setTimeout(() => {
console.log(1);
}, 0);
console.log(2);
(new Promise((resolve) => {
console.log(3);
})).then(() => {
console.log(4);//没有resolve(),状态没改变,不会执行then
});
输出:2 3 1
var name = '123';
var obj = {
name: '456',
getName: function () {
function printName() {
console.log(this.name);
}
printName();
//普通函数中,this 的指向由调用方式决定:
//直接调用 printName(),this 默认指向 全局对象:浏览器中是 window
}
}
obj.getName();//123
//严格模式下是undefined
追问:如何输出456? 两种方式
方法一:使用箭头函数
getName: function () {
const printName = () => {
console.log(this.name);
}
printName();
}
方法二:保存 this 引用
getName: function () {
var self = this;
function printName() {
console.log(self.name);
}
printName();
}
方法三:显式绑定 this
getName: function () {
function printName() {
console.log(this.name);
}
printName.call(this);
}
3.protorype
function Foo() {
this.a = 1;
return {
a: 2,
b: 3
}
}
Foo.prototype.a = 6;
Foo.prototype.b = 7;
Foo.prototype.c = 8;
var o = new Foo();
console.log(o.a);
console.log(o.b);
console.log(o.c);
1️⃣ new Foo() 的行为
当你使用 new Foo() 时,会发生以下步骤:
创建一个空对象 o。
将 o.proto 指向 Foo.prototype。
执行构造函数 Foo,并把 this 指向 o。
如果构造函数显式返回了一个对象,则 new 表达式的结果就是该对象; 如果返回的是非对象(如数字、字符串等),则忽略返回值,使用 this。
new Foo()得到的是 { a: 2, b: 3 },原型链是空,只有this的原型是Foo.prototype
输出 2 3 undefined
追问:如果删除return 返回什么结果?
1 7 8
Function.prototype.a = () => console.log(1);
Object.prototype.b = () => console.log(2);
function A() {};
var a = new A();
A.a();//1
A.b();//2
a.a();//报错
a.b();//2
- 追问1:描述此题中相关的原型和原型链?
Function是所有函数的原型,A是函数,A.a() 指向Function.prototype.a
a = new A();a不是函数,不能调用Function.prototype.a
A,a都是对象,Object是A,a的原型
a --> A.prototype --> Object.prototype --> null
- 追问2:如果A中return一个number类型的数字,输出结果有什么不同?
构造函数返回值 规则
构造函数返回 对象 → 返回该对象。
构造函数返回 非对象(number/string/boolean/undefined/null) → 返回 this(即新建的实例)。
所以 return 100 会被忽略,a 仍然是 new A() 创建的对象实例:
a.proto === A.prototype
a.b() → 可以调用
a.a() → 仍然报错
场景题 :从级联选择器中,找出当前项的元数据,并完善方法filterDataFromCascader
const originData = [{
"field": "shandong",
"displayName": "山东",
"category": 2,
"children": [
{
"field": "weihai",
"displayName": "威海",
"category": 2,
},
{
"field": "qingdao",
"displayName": "青岛",
"category": 2,
}
],
}];
// 示例 key: [shandong, qingdao];
// key 指向的最后一层节点的完整元数据
const filterDataFromCascader = () => {}
function filterDataFromCascader(data, keys) {
if (!data || keys.length === 0) return null;
const [currentKey, ...restKeys] = keys;
const found = data.find(item => item.field === currentKey);
if (!found) return null;
// 如果还有剩余 key,继续递归
if (restKeys.length > 0) {
return filterDataFromCascader(found.children || [], restKeys);
}
// 最后一层返回当前节点
return found;
}
// 测试
const keys = ["shandong", "qingdao"];
console.log(filterDataFromCascader(originData, keys));
最长回文子串
// 最长回文子串
// 中心扩散法
// 遍历字符串,以每个字符为中心,向两边扩散,找到最长的回文子串
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
const helper = (s, left, right) => {
while(left >= 0 && right < s.length && s[left] === s[right]){
left--
right++
}
return right - left - 1
}
const longestPalindrome = (s) => {
let maxLength = 0
let start = 0
let end = 0
for(let i = 0; i < s.length; i++){
let len1 = helper(s, i, i)
let len2 = helper(s, i, i + 1)
let maxLen = Math.max(len1, len2)
if(maxLen > maxLength){
maxLength = maxLen
start = i - (maxLen - 1) / 2
end = i + maxLen / 2
}
}
return s.substring(start, end + 1)
}
console.log(longestPalindrome('babad'))//bab
场景题:有一个menu,想进入页面的时候就定位到上次最后进入的那一个,怎么做?
-
保存用户上次选中的菜单
-
页面初始化时读取上次菜单状态
页面加载时,先读取存储的 key。
根据 key 查找到对应菜单数据或者索引。
将菜单状态初始化为该项选中,滚动到对应位置。
- 如果是 多级菜单 / 树形菜单
保存 完整的 path 或 父子 key 列表,比如 ["shandong", "qingdao"]。
如何统计当前网页出现过多少个html标签?
-
快速统计总数:document.getElementsByTagName('*').length
-
统计每种标签数量:querySelectorAll('*') + 遍历
前两种都不能统计shadowdom
- 可扩展递归统计:递归 DOM 遍历,可处理深层或 shadow DOM
function countTagsWithShadow(node = document.body, counts = {}) {
if (!node) return counts;
if (node.nodeType === 1) {
// 元素节点
counts[node.tagName] = (counts[node.tagName] || 0) + 1;
}
// 遍历普通子节点
node.childNodes.forEach(child => countTagsWithShadow(child, counts));
// 如果元素有 shadowRoot,则递归遍历
if (node.shadowRoot) {
countTagsWithShadow(node.shadowRoot, counts);
}
return counts;
}
const result = countTagsWithShadow();
console.log(result);
场景题手撕:基于 Vue 或 React 实现一个弹窗,
1、弹窗带有半透明的全屏遮罩;
2、弹窗可以点击遮罩和关闭按钮隐藏,也可以通过设置 visible 的 prop 隐藏;
3、弹窗可以设置 title 和主内容;
4、弹窗打开和关闭时可以 emit 事件 open 和 close;
5、场景弹窗显示时可以带动画(加分项);
<my-dialog>
<div>
主内容
</div>
</my-dialog>
import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import "./MyDialog.css"; // 我们用 CSS 做动画和样式
const MyDialog = ({ visible, title, children, onOpen, onClose, onMaskClick }) => {
// 监听 visible 改变,触发 open/close
useEffect(() => {
if (visible) {
onOpen && onOpen();
} else {
onClose && onClose();
}
}, [visible, onOpen, onClose]);
if (!visible) return null;
// 点击遮罩关闭弹窗
const handleMaskClick = () => {
onMaskClick && onMaskClick();
onClose && onClose();
};
return ReactDOM.createPortal(
<div className="my-dialog-overlay" onClick={handleMaskClick}>
<div className="my-dialog-container" onClick={e => e.stopPropagation()}>
<div className="my-dialog-header">
<span>{title}</span>
<button className="my-dialog-close" onClick={handleMaskClick}>
×
</button>
</div>
<div className="my-dialog-body">{children}</div>
</div>
</div>,
document.body
);
};
export default MyDialog;
.my-dialog-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5); /* 半透明遮罩 */
display: flex;
justify-content: center;
align-items: center;
animation: fadeIn 0.3s;
z-index: 9999;
}
.my-dialog-container {
display: flex;
flex-direction: column;
overflow: hidden;
animation: scaleIn 0.3s;
}
.my-dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.my-dialog-close {
cursor: pointer;
}
.my-dialog-body {
overflow-y: auto;
}
/* 动画效果 */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes scaleIn {
from { transform: scale(0.8); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
如何渲染一万个元素(documentfragment、虚拟列表),
同时显示的话呢?(canvas、requestAnimationFrame延迟加载分片渲染)