字节日常前端实习凉经
面试官人很好,很和善
项目说一说(单口相声说了20分钟,中间可能捧哏也问了几句)
写一下rem.js中怎么实现的吧(从项目提出来的,不大会写,只说了可能实现方式)
Rem.js 是一种常用的移动端适配方案,它通过动态设置根元素的字体大小(即 html 标签的 font-size)来实现页面元素的相对大小适配。通常情况下,我们会将设计稿按照一定比例转换成 rem 单位,然后在 CSS 中使用 rem 单位来设置元素的大小,从而实现在不同设备上的适配。
以下是一个简单的 rem.js 实现示例:
// rem.js
(function () {
// 设计稿宽度
const designWidth = 750; // 假设设计稿宽度为 750px
// 计算根字体大小
const fontSize = document.documentElement.clientWidth / designWidth * 100 + 'px';
// 设置根字体大小
document.documentElement.style.fontSize = fontSize;
})();
上述代码的原理是根据当前设备的宽度动态计算出根字体大小,然后将其设置为 html 标签的 font-size,以此来实现页面元素的相对大小适配。在这个示例中,我们假设设计稿的宽度为 750px,根据当前设备的宽度计算出对应的根字体大小,然后将其应用到 html 标签上。
在页面中引入这段代码后,无论用户在什么尺寸的设备上访问页面,都会根据当前设备的宽度自动调整页面元素的大小,从而实现移动端适配。
写一个水平垂直居中(写了三方法)
写防抖节流(需要最终版本吗,我有一个promax版的,不用,最简单的就行)
中途穿插问,问了一点八股,会ts吗?会react吗?你的学习能力强表现在哪?你的抗压能力好表现在哪?
反问
你们是不是只招ts和react的?不啊,学习能力强我们也看的
啥时候有结果?这我不知道,得问人事
总结:面试官真的很好,技术栈真的不符合,我也是真的凉
实现 rem.js
在项目中使用 rem.js 可以实现移动端适配,使页面在不同设备上显示效果一致。下面是一个简单的 rem.js 实现示例:
// rem.js
(function () {
// 设计稿宽度
const designWidth = 750;
// 设备宽度
const deviceWidth = document.documentElement.clientWidth || window.innerWidth;
// 设置根字体大小
document.documentElement.style.fontSize = deviceWidth / designWidth * 100 + 'px';
})();
在这个示例中,我们首先获取了设备宽度,然后根据设计稿的宽度来计算根字体大小,最后设置到 html 元素上。
水平垂直居中方法
- 使用 Flexbox 布局:
.container {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
- 使用绝对定位和 transform 属性:
.container {
position: relative;
}
.center {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
- 使用 table-cell 和 vertical-align 属性:
.container {
display: table-cell;
text-align: center; /* 水平居中 */
vertical-align: middle; /* 垂直居中 */
}
防抖节流函数
防抖(Debounce)函数和节流(Throttle)函数都是用来控制函数执行频率的。下面是一个简单的防抖函数实现:
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
};
}
// 使用示例
window.addEventListener('resize', debounce(function() {
console.log('Resize event debounced');
}, 300));
这个 debounce 函数会在连续触发事件时,等待一段时间后再执行函数,如果在等待时间内再次触发事件,则重新计时。这样可以确保在一段时间内只执行一次函数,避免频繁触发导致的性能问题。
作者:总是学不会,不如直接睡
链接:www.nowcoder.com/feed/main/d…
来源:牛客网
实前面答的感觉很不好的,比如问我虚拟dom还有webpack中plugin和loader的区别,我都只是按照自己的理解说了说,很多问题都只能说几句话...,最后四个代码题做的算比较顺利,面试官人很好,外貌和声音都像那种稍微大几岁的哥哥一样,说话啥的感觉很亲切,因为我的一些表现还会笑,后面贴着科比的海报,所以最后问了问面试官是不是和我们差不多大呀,面试官说不要提年龄这种伤心的问题哈哈,他说其实比我大很多。hr不久就来电话说通过了,约了下周二晚上八点三面。
什么心情呢?这次找实习我的机会很少,根本没什么面试机会,但是最好的机会现在就摆在我的面前。
希望能过#我的实习日记#
作者:进击的马哈
链接:www.nowcoder.com/discuss/428…
来源:牛客网
1.上下居中的方法(定位、flex)
2.flex属性 3.父元素宽度不固定,子元素宽度是父元素宽度的一半CSS实现
1. 上下居中的方法
定位方法:
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
Flexbox 方法:
.parent {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
2. Flex 属性
Flexbox 是一种弹性布局模型,通过设置 flex 属性来实现灵活的布局。以下是一些常用的 flex 属性:
flex-grow:定义项目的放大比例,默认为 0,即不放大。flex-shrink:定义项目的缩小比例,默认为 1,即允许缩小。flex-basis:定义项目在主轴上的初始大小。flex:flex-grow,flex-shrink,flex-basis的简写。justify-content:定义项目在主轴上的对齐方式。align-items:定义项目在交叉轴上的对齐方式。align-self:单独设置某个项目在交叉轴上的对齐方式。
3. 父元素宽度不固定,子元素宽度是父元素宽度的一半的 CSS 实现
.parent {
display: inline-block; /* 或者其他不会占满宽度的布局方式 */
text-align: center; /* 让子元素居中 */
}
.child {
width: 50%; /* 子元素宽度为父元素宽度的一半 */
}
在这个示例中,父元素的宽度没有固定,可以根据内容自适应,子元素的宽度设置为父元素宽度的一半,通过这种方式实现子元素宽度与父元素宽度的关联。
要实现父元素宽度不固定,而子元素宽度是父元素宽度的一半,可以使用相对长度单位来实现。一种常用的方法是使用百分比单位。
.parent {
width: auto; /* 父元素宽度不固定,根据内容自适应 */
/* 其他样式 */
}
.child {
width: 50%; /* 子元素宽度为父元素宽度的一半 */
/* 其他样式 */
}
在这个示例中,父元素的宽度设置为 auto,即宽度不固定,会根据内容自适应。子元素的宽度设置为 50%,即父元素宽度的一半。这样就实现了子元素宽度与父元素宽度的关联,无论父元素宽度是多少,子元素的宽度始终是父元素宽度的一半。
4.虚拟dom的作用
虚拟 DOM(Virtual DOM)是一个抽象的概念,它是一个 JavaScript 对象树,用来表示真实 DOM 结构的简化版本。虚拟 DOM 的主要作用包括以下几个方面:
-
性能优化:
- 虚拟 DOM 可以减少对真实 DOM 的操作次数,从而提高页面的渲染性能。因为对真实 DOM 的操作是非常昂贵的,每次操作都会引起浏览器的重新渲染和重排,而虚拟 DOM 可以先在内存中进行操作,最后一次性更新到真实 DOM,减少了重绘的次数。
-
跨平台兼容:
- 虚拟 DOM 的抽象层可以屏蔽不同平台(如浏览器、移动端、服务器端)之间的差异,使得开发者可以使用统一的接口来操作 DOM,从而实现跨平台兼容。
-
简化复杂度:
- 虚拟 DOM 可以将复杂的 DOM 结构抽象成简单的 JavaScript 对象,使得开发者可以更加直观地操作和管理 DOM,降低了开发的复杂度和难度。
-
提供 DOM 操作接口:
- 虚拟 DOM 提供了一系列的 API 接口,可以方便地进行 DOM 的操作,如添加、删除、更新节点等操作,使得开发者可以更加灵活地控制页面的结构和样式。
-
实现高级特性:
- 虚拟 DOM 可以实现一些高级的特性,如组件化、响应式更新、状态管理等功能,使得开发更加方便和灵活。
总的来说,虚拟 DOM 在前端开发中起着非常重要的作用,它不仅可以提高页面的渲染性能,还可以简化开发的复杂度,实现跨平台兼容,为开发者提供了更加灵活和便捷的开发方式。
1.对比->diff算法
Vue 和小程序在数据更新和视图渲染方面的核心算法是 Virtual DOM 和 diff 算法,它们在实现上有一些相似之处,但也存在一些差异:
-
Virtual DOM:
- Vue 和小程序都使用了 Virtual DOM 技术,即在内存中维护了一份虚拟的 DOM 树,用来描述真实 DOM 树的结构和状态。
- 在数据更新时,Vue 和小程序都会先更新虚拟 DOM,然后通过 diff 算法对比新旧虚拟 DOM,找出差异,最后将差异更新到真实 DOM 上。
-
diff 算法:
- Vue 中的 diff 算法是通过递归地对比新旧节点的结构和属性,找出差异,并将差异应用到真实 DOM 上。
- 小程序中的 diff 算法与 Vue 类似,但可能会有一些细微的差别,因为小程序的渲染机制和实现细节与 Vue 不完全相同。
-
精确度:
- Vue 的 diff 算法是基于 Virtual DOM 的,能够精确地找出需要更新的节点,从而最小化 DOM 操作,提高性能。
- 小程序的 diff 算法也尽可能地减少不必要的 DOM 操作,但由于其实现细节和渲染机制的不同,可能在某些情况下与 Vue 有所不同。
-
性能优化:
- Vue 通过一些优化手段(如同级比较、key 值优化等)来减少 diff 算法的时间复杂度,提高了渲染性能。
- 小程序也会对 diff 算法进行优化,以提高渲染性能,但具体的优化策略可能会有所不同。
综上所述,Vue 和小程序在数据更新和视图渲染方面都使用了 Virtual DOM 和 diff 算法,虽然实现细节可能有所不同,但都能够有效地提高渲染性能,并提供流畅的用户体验。
地方v非常vi5.小程序与Vue数据更新与数据绑定方面的区别
小程序和 Vue 在数据更新和数据绑定方面有一些区别,主要体现在以下几个方面:
-
响应式原理:
- Vue 使用了响应式数据机制,当数据发生变化时,相关的 DOM 将会自动更新,这是通过 Vue 的数据劫持和观察机制实现的。
- 小程序中的数据更新是通过 setData 方法实现的,当数据发生变化时,需要手动调用 setData 方法来更新数据,然后小程序会重新渲染相应的视图。
-
模板语法:
- Vue 使用了模板语法(如{{}})来实现数据绑定和渲染,可以将数据动态地绑定到 DOM 元素上。
- 小程序使用了 WXML 模板语言来实现数据绑定,可以将数据动态地绑定到视图层的组件上。
-
性能优化:
- Vue 使用了虚拟 DOM 技术,通过比较虚拟 DOM 的差异来最小化 DOM 操作,从而提高了性能。
- 小程序中的数据更新是通过 setData 方法实现的,性能方面较 Vue 可能稍显不足,需要开发者手动控制数据的更新和渲染。
-
组件通信:
- Vue 中组件通信可以通过 props、事件、插槽等方式实现,非常灵活方便。
- 小程序中组件通信可以通过 properties、事件机制、全局数据等方式实现,较 Vue 略显繁琐。
综上所述,虽然小程序和 Vue 在数据更新和数据绑定方面有一些区别,但都提供了便捷的方式来实现数据和视图的关联,开发者可以根据项目需求和个人喜好选择适合的技术栈。
1.小程序中两个组件共享数据有什么实现方式6.微信小程序是用原生语法写的吗?了解过用Vue等框架去写小程序然后转化的技术栈
在小程序中,如果两个组件需要共享数据,可以通过以下几种方式实现:
-
使用全局变量或全局状态管理器:可以将需要共享的数据存储在全局变量中,或者使用全局状态管理器(如微信小程序的 getApp().globalData、Redux、Mobx 等)管理数据,并在需要的组件中进行读写操作。
-
通过父子组件传值:如果两个组件之间是父子关系,可以通过父组件将数据传递给子组件,在子组件中进行处理和展示。
-
使用事件总线或消息订阅-发布机制:通过事件总线或者消息订阅-发布机制来实现组件间的通信,一个组件发送消息,另一个组件接收消息,并进行相应的处理。
-
使用数据存储和监听:可以使用小程序提供的数据存储方案(如本地存储、数据库等),在一个组件中存储数据,另一个组件监听数据的变化,并进行相应的处理。
至于微信小程序是使用原生语法还是其他框架,微信小程序是使用原生语法(即 WXML、WXSS 和 JS)开发的。但是,开发者可以使用一些框架(如 Vue、React)来开发小程序,然后通过转译工具将其转换成小程序的原生语法。这种技术栈可以让开发者使用熟悉的框架和开发方式来开发小程序,提高开发效率和代码复用性。
7.http与https的区别
HTTP(HyperText Transfer Protocol)和 HTTPS(HyperText Transfer Protocol Secure)是两种不同的网络传输协议,它们之间有以下几点主要区别:
-
安全性:
- HTTP 是明文传输,数据在传输过程中不加密,容易被中间人窃听、篡改或伪造,安全性较低。
- HTTPS 使用 SSL/TLS 协议对数据进行加密,确保数据在传输过程中的安全性和完整性,大大提高了安全性。
-
数据传输方式:
- HTTP 使用明文传输,数据不加密,包括请求头、请求体、响应头和响应体等信息都是明文传输的。
- HTTPS 使用 SSL/TLS 协议对数据进行加密,通信双方之间的数据传输是经过加密的,中间人无法直接读取或篡改数据。
-
端口号:
- HTTP 默认端口号是 80。
- HTTPS 默认端口号是 443。
-
协议:
- HTTP 使用 TCP 协议传输数据。
- HTTPS 在 HTTP 的基础上加入了 SSL/TLS 协议,使用加密通道传输数据。
-
证书:
- HTTP 不需要证书,是不安全的。
- HTTPS 需要服务器端的 SSL 证书,用于验证服务器的身份,并用于加密通信。
-
性能:
- HTTPS 在数据传输过程中需要进行加密和解密的操作,会增加一定的计算和通信开销,导致性能稍微降低,但现代的硬件和软件已经大大减轻了这种影响。
综上所述,HTTPS 是 HTTP 的安全版本,通过加密传输数据来保障通信的安全性,因此在对安全性要求较高的场景下应当优先选择使用 HTTPS。
1.客户端获取网站的公钥,如何获取(http请求获取)
在 HTTP 请求中获取网站的公钥并不常见,因为 HTTP 是明文传输,获取公钥的过程可能会被中间人劫持或篡改,从而降低了安全性。通常情况下,获取网站公钥是在建立安全连接时使用的,而建立安全连接的过程是在 HTTPS 协议中完成的,其中包含了一系列加密和握手的步骤,以确保通信的安全性。
在 HTTPS 中,客户端通过 SSL/TLS 握手过程与服务器进行连接,并在此过程中获取服务器的公钥。这个过程大致如下:
- 客户端向服务器发送一个请求,请求建立安全连接。
- 服务器返回包含公钥的证书。
- 客户端使用服务器证书中的公钥对生成一个随机的对称密钥,并用公钥进行加密。
- 服务器使用自己的私钥解密客户端发送过来的对称密钥。
- 客户端和服务器双方都拥有了相同的对称密钥,接下来的通信将使用对称密钥进行加密和解密。
在这个过程中,客户端会获得服务器的公钥,但这个过程是在建立安全连接的时候进行的,而不是在普通的 HTTP 请求中进行的。
2.https中的s代表什么
HTTPS 中的 "S" 代表 "Secure",表示安全。HTTPS 是 Hyper Text Transfer Protocol Secure 的缩写,是 HTTP 的一种安全版本。
HTTPS 在传输过程中使用了 SSL/TLS 协议对数据进行加密,从而保证了数据在传输过程中的安全性和完整性。使用 HTTPS 可以有效防止数据在传输过程中被窃听、篡改或者伪造,提高了数据的安全性。
在 HTTPS 中,通信双方(客户端和服务器)之间的数据传输是经过加密的,因此即使被拦截也很难解密,保护了用户的隐私信息和数据安全。HTTPS 已经成为了当前互联网上数据传输的标准协议,被广泛应用在网站、移动应用等各种场景中。
8.webpack中plugin和loader两者的区别
在 Webpack 中,Plugin 和 Loader 是两个不同的概念,它们分别用于不同的任务,具有不同的作用。
Loader
Loader 用于对模块的源代码进行转换和处理。它是 Webpack 构建过程中的一个关键部分,用于将不同类型的文件(例如 JavaScript、CSS、图片等)转换为 Webpack 能够处理的模块。
Loader 的作用是将源文件经过转换处理后输出为新的文件,这些转换处理可以包括代码转译(如将 ES6+ 代码转换为 ES5)、样式预处理(如将 Sass 或 Less 转换为 CSS)、文件压缩等。
Plugin
Plugin 用于扩展 Webpack 的功能。它可以在 Webpack 构建过程的各个阶段执行自定义的任务,并且可以访问到整个构建过程中的各种资源。
Plugin 的作用是通过在构建过程中监听事件,执行一些额外的任务或者对输出结果进行修改。比如,可以用 Plugin 来实现打包优化、资源管理、注入环境变量等功能。
区别总结
- Loader 用于转换文件,作用于单个文件的加载阶段,负责将文件从输入的字符串转换为模块。
- Plugin 用于扩展 Webpack 的功能,作用于整个构建过程,负责在构建过程中监听事件,执行一些额外的任务或者对输出结果进行修改。
- Loader 用于处理源文件,Plugin 用于扩展 Webpack 功能。
- Loader 是链式调用的,Plugin 是作为插件引入并配置到 Webpack 的配置中。
10.代码题:this指向(如何修改this指向使输出为....:改为箭头函数) 11.代码题:原型链相关 12.手写代码:数字格式化
10. 修改 this 指向使输出为箭头函数
如果要将给定函数的 this 指向修改为箭头函数的 this,可以通过箭头函数的词法作用域特性来实现。箭头函数没有自己的 this,它继承了外层作用域的 this。
以下是一个示例:
function Person(name) {
this.name = name;
this.getName = function() {
return this.name;
};
}
const person = new Person('John');
// 使用箭头函数修改 this 指向
Person.prototype.getNameArrow = () => {
return this.name;
};
console.log(person.getName()); // 输出:John
console.log(person.getNameArrow()); // 输出:undefined
在这个示例中,getNameArrow 方法使用了箭头函数,这样在箭头函数内部的 this 就指向了全局对象,而不是当前对象 person,因此输出结果为 undefined。
11. 原型链相关
原型链是 JavaScript 中用于实现继承的一种机制,它是由原型对象和构造函数组成的链式结构。
在 JavaScript 中,每个对象都有一个指向其原型对象的内部属性 [[Prototype]](可以通过 __proto__ 或 Object.getPrototypeOf() 访问),原型对象也是对象,因此也有自己的原型对象,以此类推,形成了一个原型链。
当访问对象的属性或方法时,如果对象本身没有该属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到相应的属性或方法或者到达原型链的末尾(即 Object.prototype),如果还没有找到,则返回 undefined。
以下是一个简单的原型链示例:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log('Hello, my name is ' + this.name);
};
const person = new Person('John');
person.sayHello(); // 输出:Hello, my name is John
在这个示例中,Person 是一个构造函数,person 是 Person 的一个实例。Person.prototype 是 person 的原型对象,person 继承了 Person.prototype 中定义的 sayHello 方法。当调用 person.sayHello() 时,JavaScript 引擎会在 person 对象上查找 sayHello 方法,如果找不到,则沿着原型链向上查找,直到找到为止。
12. 手写代码:数字格式化
function formatNumber(number, separator = ',', groupSize = 3) {
// 将数字转换为字符串,并去除前导零
let str = String(number).replace(/^0+/, '');
// 将字符串从右向左每 groupSize 位添加一个分隔符
const regExp = new RegExp(`(\\d{${groupSize}})(?=\\d)`, 'g');
str = str.replace(regExp, `$1${separator}`);
return str;
}
// 测试
console.log(formatNumber(123456789)); // 输出:123,456,789
console.log(formatNumber(123456789, '-')); // 输出:123-456-789
console.log(formatNumber(123456789, ',', 2)); // 输出:12,34,56,789
这个函数接受三个参数:number 表示要格式化的数字,separator 表示分隔符,默认为逗号,groupSize 表示每几位数字添加一个分隔符,默认为 3。
在函数内部,首先将数字转换为字符串,并去除前导零。然后使用正则表达式在字符串中添加分隔符,最后返回格式化后的字符串。
数字格式化问题:1234567890->1,234,567,890
function Person(name, age){this.name = name, this.age = age; this.eat = function(){ console,log(age +"岁的" + name +"在吃饭。"); Person.run = function (){}Person.prototype.walk = function (){}lct p1 = new Pcrson("jsliang", 24);let p2 = new Person("jsllang",24) console.log(p1.eat === p2.eat);consolc.lcg(p1.run == p2.run); onsole,l0g(pl.walk===Pv类a生客967039054号
setTimeout(function() console.log(1) } 0); new Promise(function(resolve){console.log(2);for(var i=0 ;i< 10000 ;i++){if (i == 9999){resolve(); console,log(3);}).then(functlon(){console.log(4); 3); consolc.lcg(5);
class Student{ constructor(name){this.name ='Jarry getInfo(){ return { name:'Tom',getNane(){ rcturn this.namc const stu-new Student()stu.getInfo().getName デg出?
这段代码有一些语法和逻辑错误,我来帮您修正一下:
function Person(name, age) {
this.name = name;
this.age = age;
this.eat = function() {
console.log(age + "岁的" + name + "在吃饭。");
};
}
Person.run = function() {};
Person.prototype.walk = function() {};
let p1 = new Person("jsliang", 24);
let p2 = new Person("jsliang", 24);
console.log(p1.eat === p2.eat); // 输出:false,每次调用构造函数都会创建一个新的 eat 函数
console.log(p1.run === p2.run); // 输出:true,run 是直接添加到构造函数上的静态方法
console.log(p1.walk === p2.walk); // 输出:true,walk 是添加到原型对象上的方法
setTimeout(function() {
console.log(1);
}, 0);
new Promise(function(resolve) {
console.log(2);
for (var i = 0; i < 10000; i++) {
if (i == 9999) {
resolve();
}
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
class Student {
constructor(name) {
this.name = 'Jarry';
}
getName() {
return this.name;
}
}
const stu = new Student();
console.log(stu.getInfo().getName()); // 输出:TypeError: stu.getInfo is not a function,因为 getInfo 方法未定义
修正后的代码更加符合 JavaScript 的语法规范,也更准确地展示了各个部分的功能。