java字符串相加去重_一些面经的小知识(二)

1、拷贝

当你把一个对象或数组作为值赋给一个变量时,实际上是将这个对象或数组的引用地址赋给了变量,当这个变量发生了改变对象或数组的操作时,原对象和数组也会受到影响跟着改变,所以我们想到通过拷贝的方式重新复制一份。

大家应该都知道JS拷贝有分浅拷贝和深拷贝~

浅拷贝:

(1)Object.assign

const obj1 = {

a: 1,

b: { c: 2 }

};

const obj2 = Object.assign({}, obj1);

复制代码

451282b6f7b659f69a5e51881731e806.png

(2)es6解构

const obj1 = {

a: 1,

b: { c: 2 }

};

const obj2 = { ...obj1 };复制代码

1031594b404dbbbb2eb63377d6f09f7f.png

(3)遍历一次的key、value赋值

(4)数组的话还有slice

但是浅拷贝还是无法解决对象或数组嵌套的问题,这时我们需要考虑深拷贝。

深拷贝:

(1)JSON.stringify和JSON.parse

const obj1 = {

a: 1,

b: { c: 2 }

};

const obj2 = JSON.parse(JSON.stringify(obj1));

obj2.b.c = 3;

console.log(obj1);

console.log(obj2);复制代码

你会发现obj1和obj2已经独立互不影响了。

dbaabddef27d90bb852b02eac1063e15.png

是不是用这种方法就可以完美解决问题呢?

其实这种方法,他是会忽略对象中值为undefined的属性的。

const obj1 = {

a: 1,

b: { c: undefined }

};

const obj2 = JSON.parse(JSON.stringify(obj1));

console.log(obj1);

console.log(obj2);复制代码

c56de6f1410e576bbe59b5aabceda796.png

(2)递归

function clone(source) {

var target = {};

for(var i in source) {

if (source.hasOwnProperty(i)) {

if (typeof source[i] === 'object') {

target[i] = clone(source[i]);

} else {

target[i] = source[i];

}

}

}

return target;

}复制代码

👆的方法欠缺参数检验、是否是对象的判断不严谨以及没有兼容数组。

其实判断是否是对象常用的方法是Object.prototype.toString.call(obj) === '[object Object]'

如果想了解完美的解决办法,可以看看这里:

其实这种深拷贝方法还有个问题,就是循环引用和层级过深会导致爆栈,这里有篇文章写的很好,大家可以看看:

2、数组去重

(1)利用对象

const arr = [1,2,3,4,2,5,4,6,7,6,8];

const obj = {};

const newArr = [];

arr.forEach((item) => {

if (!obj[item]) {

newArr.push(item);

obj[item] = 1;

}

});

console.log(newArr);复制代码

a9c69834782f2124a1be9e34d1c8fbf5.png

2、利用ES6的Set

const arr = [1,2,3,4,2,5,4,6,7,6,8];

const mySet = new Set(arr);

console.log(mySet);复制代码

2297e21fa6092b3e0ebd48a3d4d6929e.png

这样虽然得出了去重后的结果,但还差一步,这还是一个Set,我们得把它转回数组,用什么方法呢?是的,Array.from。

const newArr = Array.from(mySet);

console.log(newArr);复制代码

6b2e80a3652c7ec5414e572ab78c4b43.png

当然数组去重还有其他方法,比如 原数组遍历,检查新数组是否存在即将插入的元素,不存在则插入,存在则不插入,但这会用到indexOf,其实本质也是把新数组遍历了,所以性能没有上面这两种好。

3、如果让你实现一个搜索框,你会考虑到什么?(这里的搜索框就像百度的搜索框,输入后在下面会展示搜索结果)

这道题应该大部分人会想到的是输入关键字触发请求,那用户每次输入都会触发请求的话,无疑对网络、性能、体验都是不好的,所以我们该用节流函数。

简单的节流函数:

function throttle(fn, duration) {

let flag = true;

return function() {

const context = this;

if (flag) {

flag = false;

setTimeout(() => {

fn && fn.apply(context, arguments)

flag = true;

}, duration);

}

}

}复制代码

节流函数一般可以用在onresize,onscroll,onmousemove,onmouseover等场景。

诶说到节流函数,那顺便提提防抖函数吧,这两者有什么不一样呢?

我觉得差别在于时间的控制吧,防抖函数也是在设置的时间内只会执行一次,但是如果第二次触发则是会重新计算时间。

function debounce(fn, duration) {

let timer = null;

return function() {

const context = this;

if (timer) {

clearTimeout(timer);

timer = null;

}

timer = setTimeout(() => {

fn && fn.apply(context, arguments);

timer = null;

}, duration);

}

}复制代码

回到搜索框的问题上,除了设置节流以外,其实还有个问题。如果用户输入“abc”第一次触发,发出了请求,再继续输入“def”又触发一次,又发出一次请求,但是这两次请求返回顺序是不固定的,这样得到的搜索结果很可能并不是用户想要的,体验会很差。

所以这样需要用到XMLHttpRequest的中止请求abort,当你上一次请求的结果未返回时,先abort中止它,再进行下一次请求。

4、实现拖拽效果,用鼠标拖动一个东西,随意拖动,随意放下。

首先要理解这里不是让我们用html5的drag,然后自己画图想想这里要怎么利用各种坐标距离,再试着用代码实现一下看看。

test

#box {

width: 100px;

height: 100px;

position: absolute;

top: 0px;

left: 0px;

background-color: #FF0000;

}

window.onload = function() {

const box = document.getElementById('box');

box.addEventListener('mousedown', mouseDown);

box.addEventListener('mouseup', mouseUp);

let boxLeft = 0; // 用来保存鼠标点击时 box绝对位置的left

let boxTop = 0; // 用来保存鼠标点击时 box绝对位置的top

let initX = 0; // 用来保存鼠标点击box时 的X坐标

let initY = 0; // 用来保存鼠标点击box时 的Y坐标

let distanceX = 0; // 用来保存box X轴上移动的距离

let distanceY = 0; // 用来保存box Y轴上移动的距离

function mouseDown(e) {

// 鼠标点击box触发

initX = e.pageX;

initY = e.pageY;

boxLeft = e.target.offsetLeft;

boxTop = e.target.offsetTop;

// 这里给body绑定鼠标移动事件,是因为body覆盖整个页面。

// 如果给box绑定鼠标移动事件,当鼠标快速滑动的时候,滑出了box,那事件就会中断了

document.body.addEventListener('mousemove', mouseMove);

}

function mouseUp() {

// 鼠标松开时触发

document.body.removeEventListener('mousemove' mouseMove);

}

function mouseMove(e) {

// 鼠标滑动时触发

distanceX = e.pageX - initX;

distanceY = e.pageY - initY;

box.style.left = boxLeft + distanceX;

box.style.top = boxTop + distanceY;

}

}

复制代码

5、大数相加

javascript支持的数字范围是(-2^53, 2^53),超过了就会丢失精度。

如果后端返回了两个超大数字符串,我们要怎样将两者相加呢?因为如果转成数字相加,超大数字符串转成数字精度会丢失,相加的结果必然不准确;如果直接字符串相加,那也只是字符串拼接,并不是我们想要的结果。

我们来看一下,其实数字相加原理是每一位相加,然后满十进一。

12345

+ 56789

——————

69134

那我们是不是可以将字符串每一位相加,模拟数字的相加呢?

function add(str1, str2) {

const arr1 = str1.split('').reverse();

const arr2 = str2.split('').reverse();

const res = [];

let flag = 0;

while(arr1.length || arr2.length || flag) {

const num1 = arr1.shift() || 0;

const num2 = arr2.shift() || 0;

const sum = Number(num1) + Number(num2) + flag;

if (sum > 9) {

flag = 1;

res.push(sum % 10);

} else {

flag = 0;

res.push(sum);

}

}

return res.reverse().join('');

}复制代码

6、实现一个简单的模版引擎

现在有个模板字符串 '

hello,我是{{name}},年龄:{{info.age}}

,工作经历:{{info.experience.company}},工作时间:{{info.experience.time}}',

数据data = {name: 'abc', info: {age: 24, experience: {company: 'abc', time: 'two years'}}},如何实现模板的数据替换?

这里关键是replace方法的使用,replace方法的第二个参数可以是个回调函数。

function compile(tpl, data) {

const regex = /\{\{([^}]*)\}\}/g; const string = tpl.trim().replace(regex, function(match, $1) {

if ($1) {

const arr = $1.split('.');

return getValue(data, arr);

} else {

return '';

}

});

console.log(string);

}

function getValue(data, arr) {

let attr;

if (arr.length) {

attr = arr.shift();

return getValue(data[attr], arr);

}

return data;

}

const tpl = '

hello,我是{{name}},年龄:{{info.age}}

,工作经历:{{info.experience.company}},工作时间:{{info.experience.time}}';

const data = {name: 'abc', info: {age: 24, experience: {company: 'def', time: 'two years'}}};

compile(tpl, data);

复制代码

bcfdb361226048a9d54eea5a299f1a5d.png

7、闭包的作用

闭包作用一是外部可以读取函数内部的变量;二是函数里声明的变量始终保持在内存中,不会在函数调用后被自动清除。

运用场景比如解决遍历索引,函数柯里化,节流防抖,bind等等。

未完待续~~

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[一些面经的小知识(二)]http://www.zyiz.net/tech/detail-119057.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值