Я недавно ищу стажировку, поэтому я записал некоторые вопросы по коду, которые я видел и с которыми столкнулся в процессе собеседования.Если есть что-то не так или что-то, что можно улучшить, я надеюсь, что вы можете покритиковать и исправить это~
1. HTML, связанные с CSS
1. Горизонтально по центру
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 块级元素水平居中,已知宽度
<style>
/* 方法一:margin:0 auto */
/* .father{
width:500px;
height:300px;
background-color:blue;
}
.son{
width:100px;
height:100px;
background-color:yellow;
margin:0 auto;
} */
/* 方法二:绝对定位 + left + margin-left */
/* .father{
width:500px;
height:300px;
background-color:blue;
position:relative;
}
.son{
width:100px;
height:100px;
background-color:yellow;
position:absolute;
left:50%;
margin-left:-50px;
} */
</style> -->
<!-- 块级元素水平居中,未知元素宽度 -->
<style>
/* 方法一:绝对定位 + left + translateX(-50%) */
/* .father{
width:500px;
height:300px;
background-color:blue;
position:relative;
}
.son{
height:100px;
background-color:yellow;
position:absolute;
left:50%;
transform:translateX(-50%);
overflow:hidden;
text-overflow:ellipsis;
} */
/* 方法二:flex */
.father{
width:500px;
height:300px;
background-color:blue;
display:flex;
justify-content:center;
}
.son{
height:100px;
background-color:yellow;
}
</style>
</head>
<body>
<div class="father">
<div class="son">我是块级元素我是块级元素</div>
</div>
</body>
</html>
2. Центрировать по вертикали
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
/* position方法 */
/* .father{
width:300px;
height:300px;
background-color:red;
position:relative;
}
.son{
width:100px;
height:100px;
background-color:blue;
position:absolute;
top:50%;
transform: translateY(-50%);
} */
/* flex方法 */
.father{
background-color:blue;
width:300px;
height:300px;
display:flex;
align-items:center;
}
.son{
width:100px;
height:100px;
background-color:red;
}
</style>
</head>
<body>
<div class="father">
<div class="son">垂直居中</div>
</div>
</body>
</html>
3. Получить все флажки на странице
// 希望获取到页面中所有的checkbox怎么做?(不使用第三方框架)
var inputs = document.getElementsByTagName("input");
var checkboxArray = [];
for(let i = 0; i < inputs.length; i++){
if(inputs[i].type === "checkbox"){
checkboxArray.push(inputs[i]);
}
}
4. Изменение цвета строки таблицы
<!-- 请写一个表格以及对应的CSS,使表格奇数行为白色背景,偶数行为灰色背景,鼠标移上去时为黄色背景。 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表格</title>
<style type="text/css">
body {
margin: 0;
}
table {
border: 1px solid #ddd;
border-collapse: collapse; /* 去掉td之间的间隙 */
}
tr:nth-child(odd) {
background-color: #fff
}
tr:nth-child(even) {
background-color: #666
}
tr:hover {
background-color: yellow
}
</style>
</head>
<body>
<table>
<th>表格标题</th>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
</table>
</body>
</html>
2. JS, связанный с алгоритмом
1. Реализация симуляции обещаний
2. Реализация Promise.all
// promise.all 实现
// promise.all(iterable)返回一个新的promise实例。
// 此实例在iterable参数内所有的promise都fulfilled或者参数中不包含promise时,状态才变成fulfilled;
// 如果参数中有一个失败rejected,此实例回调失败,失败的信息是第一个失败promise的返回结果
Promise.all_ = function(promises) {
return new Promise((resolve, reject) => {
// Array.from()可将可迭代对象转化为数组
promises = Array.from(promises);
if(promises.length===0) {
resolve([]);
} else {
let result = [];
let index = 0;
for(let i=0; i<promises.length; i++) {
// 考虑到promise[i]可能是thenable对象也可能是普通值
Promise.resolve(promises[i]).then(data => {
result[i] = data;
if(++index===promises.length) {
// 所有的promise状态都是fulfilled,promise.all返回的实例才变成fulfilled状态
resolve(result);
}
}, err => {
reject(err);
return;
})
}
}
})
}
3. Реализация Promise.race
// promise.race
// Promise.race返回的仍然是一个Promise,它的状态与第一个完成的Promise的状态相同;
// 如果传入的参数是不可迭代的,那么将会抛出错误。
Promise.ra_ce = function(promises) {
promises = Array.from(promises);
return new Promise((resolve, reject) => {
if(promises.length===0) {
return;
} else {
for(let i=0; i<promises.length; i++) {
Promise.resolve(promises[i]).then(data => {
resolve(data);
return;
}, err => {
reject(err);
return;
})
}
}
})
}
4. реализация вызова
// 模拟思路:
// 将函数设为对象的属性
// 执行该函数
// 删除该函数
Function.prototype.call2 = function (context) {
// 将函数设为对象的属性,改变this指向(传null的时候,this指向window)
context = context || window;
context.fn = this;
// 传参并执行函数,用一个数组来接收不定长参数
var args = [];
for(var i = 1; i < arguments.length; i ++){
args.push('arguments['+i+']');
}
var result = eval('context.fn(' + args + ')');
//删除该函数
delete context.fn;
return result;
}
5. Примените реализацию
// 模拟apply()方法的实现
Function.prototype.apply2 = function(context,arr){
context = context || window;
context.fn = this;
var result;
if(!arr){
result = context.fn()
}else{
var args = [];
for(var i = 0; i < arr.length; i++){
args.push('arr[' + i + ']')
}
result = eval('context.fn(' + args + ')')
}
delete context.fn;
return result;
}
6. Привязать реализацию
// 模拟bind的实现
// bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
// 1.返回一个函数
// 2.可以传入参数
// 传参时注意:函数可以只传一个参数,然后在执行返回的函数时再继续传参
// 3.bind函数可以用new来创建对象,相当于把原函数当作一个构造器,即当bind返回的函数作为构造函数的时候,bind指定的this失效了
// 4.调用bind的不是函数时要报错
Function.prototype.bind2 = function(context){
if(typeof this !== "function"){
throw new Error("")
}
var self = this;
var args = Array.prototype.slice.call(arguments,1);
var fNOP = function(){}
var fBound = function(){
var bindArgs = Array.prototype.slice.call(arguments);
self.apply(self instanceof fNOP ? this : context,args.concat(bindArgs));
}
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
7. Унаследованные методы
// 构造函数继承
function Person1(name) {
this.name = name;
}
function Student1(name, age) {
Person1.call(this, name);
this.age = age;
}
var s1 = new Student1("xuhanlin");
console.log(s1.name);
// 原型链继承
function Person2() {
this.name = "renyuan";
}
function Student2(age) {
this.age = age;
}
Student2.prototype = new Person2();
var s2 = new Student2();
console.log(s2.name);
// 组合继承
function Person3() {
this.name = "renyuan";
}
function Student3() {
Person3.call(this);
this.age = "18";
}
Student3.prototype = new Person3();
var s3 = new Student3();
console.log(s3.name, s3.age);
8. Закрытие
// 闭包实现倒计时
for(var i = 10; i > 0; i--){
(function(i){
setTimeout(() => {
console.log(i);
},(10-i)*1000)
})(i)
}
9. Защита от сотрясений
function debounce(func,wait){
var timeout;
return function(){
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function(){
func.apply(context,args);
},wait);
}
}
10. Дросселирование
// 使用时间戳
// 当触发事件的时候,我们取出当前的时间戳,然后减去之前的时间戳(最一开始值设为 0 )
// 如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,
// 如果小于,就不执行。
function throttle(func,wait){
return function(){
var context = this;
var args = arguments;
var previous = 0;
var now = +new Date();
if(now - previous > wait){
func.apply(context,args);
previous = now;
}
}
}
// 设置定时器
function throttle(func,wait){
var timeout;
return function(){
var context = this;
var args = arguments;
if(!timeout){
timeout = setTimeout(function(){
timeout = null;
func.apply(context,args)
},wait);
}
}
}
11. новая реализация
function create(Con, ...args) {
let obj = {}
Object.setPrototypeOf(obj, Con.prototype)
//或者 obj.__proto__ = Con.prototype
let result = Con.apply(obj, args)
return result instanceof Object ? result : obj
}
12. Дедупликация массива
var array = [1,1,'1'];
// 方法一:indexOf()
// 创建一个新数组,遍历原数组,用indexOf判断原数组中的值是否已经存在,不存在就push进去
function unique(arr){
var res = [];
for(let item of arr){
if(res.indexOf(item) === -1){
res.push(item);
}
}
return res;
}
// 方法二:排序后去重
function unique(arr){
var res = [];
var newArr = arr.sort();
for(let i=0; i<newArr.length; i++){
if(newArr[i] !== newArr[i+1]){
res.push(newArr[i]);
}
}
return res;
}
// 方法三:利用Set的唯一性
function unique(arr){
return Array.from(new Set(arr));
}
// 方法四:Map
function unique (arr) {
const map = new Map()
return arr.filter((a) => !map.has(a) && map.set(a, 1))
}
console.log(unique(array));
13. Сглаживание массива
var arr = [1, [2, [3, 4]]];
// 方法一:循环数组,如果里面还是数组,递归调用扁平化方法
function flatten(arr) {
var result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result.push(arr[i])
}
}
return result;
}
// 方法一的改进写法
function flatten(arr) {
return arr.reduce(function (pre, item) {
return pre.concat(Array.isArray(item) ? flatten(item) : item)
}, []);
}
// 方法二:toString(),它的一个缺点是改变了元素的类型,只适合于数组中元素都是整数的情况
function flatten(arr) {
return arr.toString().split(",").map(function (item) {
return +item;
})
}
console.log(flatten(arr));
14. Карри
function sub_curry(fn) {
var args = [].slice.call(arguments, 1);
return function() {
return fn.apply(this, args.concat([].slice.call(arguments)));
};
}
function curry(fn, length) {
length = length || fn.length;
var slice = Array.prototype.slice;
return function() {
if (arguments.length < length) {
var combined = [fn].concat(slice.call(arguments));
return curry(sub_curry.apply(this, combined), length - arguments.length);
} else {
return fn.apply(this, arguments);
}
};
}
15. Массив вышел из строя
// 数组乱序
// 遍历数组元素,然后将当前元素与以后随机位置的元素进行交换
function shuffle(arr) {
for (let i = arr.length; i > 0; i--) {
let j = Math.floor(Math.random() * i)
let x = arr[i - 1];
arr[i - 1] = arr[j];
arr[j] = x;
}
return arr;
}
var arr = [1, 2, 3, 4, 5];
console.log(shuffle(arr))
16. Быстрая сортировка
// 快速排序
// 找到一个基准数,比基准数小的放左边,比基准数大的放右边
// 对左右区间不断重复这个过程
var quickSort = function(arr){
if(arr.length <= 1){
return arr;
}
const pivotIndex = Math.floor(arr.length / 2); //任意基准数索引
const pivot = arr.splice(pivotIndex,1)[0]; //找到对应的基准数
const left = [];
const right = [];
for(let i=0; i<arr.length; i++){
if(arr[i] < pivot){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot], quickSort(right));
}
const arr = [98, 42, 25, 54, 15, 3, 25, 72, 41, 10, 121];
console.log(quickSort(arr));
17. Пузырьковая сортировка
// 冒泡排序
// 两两相邻元素对比,如果前一个比后一个大,就往后移,一轮比较下来,最大的数到了最后一个
// 重复这个步骤
function bubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
const temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
var arr = [10, 14, 8, 5, 88];
console.log(bubbleSort(arr));
18. Глубокое и поверхностное копирование
// 实现浅拷贝
// 遍历对象,然后把属性和属性值都放到一个新对象里
var shallowCopy = function(obj) {
// 只拷贝对象
if (typeof obj !== 'object') return;
// 根据obj的类型判断是新建一个数组还是对象
var newObj = obj instanceof Array ? [] : {};
// 遍历obj,并且判断是obj的属性才拷贝
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
// 实现深拷贝
// 在拷贝的时候判断一下属性值的类型,如果是对象,再递归拷贝一下
var deepCopy = function(obj){
if(typeof(obj) !== "object") return;
var newObj = obj instanceof Array ? [] : {};
for(let key in obj){
if(obj.hasOwnProperty(key)){
newObj[key] = typeof obj[key] === "object" ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
19. Реализуйте функцию накопления, такую как sum(1,2,3)(2).valueOf()
function sum(...args) {
let result = 0;
result = args.reduce(function (pre, item) {
return pre + item;
}, 0);
let add = function (...args) {
result = args.reduce(function (pre, item) {
return pre + item;
}, result);
return add;
};
add.valueOf = function () {
console.log(result);
}
return add;
}
20. Добавляйте большие числа
// js 实现一个函数,完成超过范围的两个大整数相加功能
function bigNumberAdd(a,b){
var res = ""; //用字符串接收结果
var carry; //保存进位结果
//把字符串转换成数组
a = a.split("");
b = b.split("");
// 当数组的长度都变为0,并且最终不再进位时,结束循环
while(a.length || b.length || carry){
carry += a.pop() + b.pop();
res += carry % 10;
// 判断是否需要进位,true 和 false 的值在加法中会被转换为 1 和 0
carry = carry > 9;
}
return res;
}
21. Наибольший общий делитель, наименьшее общее кратное
// 求两个数的最大公约数
// 辗转相除法
// 用大的数对小的数取余,再用小的数对取余后的值取余,一直递归,直到余数为零
function getMaxCommonDivisor(a, b) {
if (b === 0) {
return a;
}
return getMaxCommonDivisor(b, a % b)
}
// 求最小公倍数
// 两数相乘,然后除以他们的最大公约数
function getMinCommonMutiple(a, b) {
return a * b / getMaxCommonDivisor(a, b);
}
22. Повторяющиеся числа в массиве
// 方法三:
// 让对应索引的数到对应的位置,比如第一个数为2,就把它放到索引为2的地方
// 相当于把数放进对应的桶
var findRepeatNumber = function(nums){
for(let i=0; i<nums.length; i++){
while(i !== nums[i]){
if(nums[i] == nums[nums[i]]){
return nums[i];
}else{
var temp = nums[i];
nums[i] = nums[temp];
nums[temp] = temp;
}
}
}
// return -1;
}
23. Поверните наименьшее число массива
// 思路:
// (遍历数组,找出最小值 pass)
// 二分法:
// 因为是旋转数组,前面的元素都大于等于后面的元素,最小的元素是分界线
// 指针指向左(i)右(j)两端,跟中间的数(索引m)作比较,不断缩小比较区间
// nums[m] > nums[j], 中间的数大于最后的数,那最小数一定在后半段,令 i = m + 1;
// nums[m] < nums[j], 中间的数小于最后的数,那最小数一定在前半段,令 j = m;
// nums[m] === nums[j], 无法判断,用 j = j - 1 来缩小范围
var minArray = function (nums) {
var i = 0;
var j = nums.length - 1;
while (i < j) {
var m = Math.floor((i + j) / 2);
if (numbers[m] > numbers[j]) {
i = m + 1;
} else if (numbers[m] < numbers[j]) {
j = m;
} else {
j = j - 1;
}
}
return numbers[i];
};
24. Больше половины чисел в массиве
// 方法一:
// 使用map记录数组中的值以及出现的次数
var majorityElement = function(nums) {
// write code here
const len = nums.length
if (len === 0) return 0
const map = new Map()
for (let i of nums) {
if (map.get(i) === undefined) {
map.set(i, 1)
}else {
map.set(i, map.get(i)+1)
}
}
for (let item of map.entries()) {
if (item[1] > Math.floor(len/2)) return item[0]
}
return 0
};
// 方法二:给数组排序,次数超过一半的话,那么数组中点索引对应的数一定是这个数
var majorityElement = function(nums){
var newNums = nums.sort();
return newNums[Math.floor(nums.length / 2)];
};
25. Создайте ассортимент продуктов
// 思路:1.left:正向遍历A数组,累乘
// 2.right:反向遍历A数组,累乘
// 3.left * right 即为B数组
function constructArr(a) {
var res = [];
var left = 1;
for (let i = 0; i < a.length; i++) {
res[i] = left;
left *= a[i];
}
var right = 1;
for (let i = a.length - 1; i >= 0; i--) {
res *= right;
right *= a[i];
}
return res;
}
26. Максимальная сумма последовательных подмассивов
var maxSubArray = function(nums){
let max = -Infinity;
nums.reduce((pre,cur) => {
if(pre > 0){
pre += cur; //连续子数组的和大于0,对求最大和起正向作用,就加上他
}else{
pre = cur; //连续子数组的和小于0,加上他会越来越小,就不要她了,直接从当前值重新开始
}
max = max > pre ? max : pre;
return pre;
},0)
return max;
}