五、js算法
1.js随机生成10000个,长度为8 位的数字号码,找出所有靓号(AAAA,AABB,ABAB,并且后四位不含4 )
<script type="text/javascript">
//这里是如何获取八位数
function addNumber(){
var str = '';
for(var i = 0; i < 8; i += 1){
str += Math.floor(Math.random() * 10);
}
return str;
}
console.log(addNumber());
//蒋随机号码存入数组
var addNum = function(){
//要获取1000个 肯定要数组来存 但是我先用100个来实验 1000个就太恐怖了
let arrNum = [];
for(let i =0 ;i<100;i++){
arrNum.push(addNumber());//存入数组中
}
return arrNum;
}
console.log(addNum());
//然后开始对获取到的数组做处理 也就是找出靓号 照样要一个数组来存
//第一步肯定是去掉后四位有4的数字呀
var chooseNum = function(){
const arrNum = addNum();//获取上一步拿到的数组
for(let i of arrNum.keys()){//循环对每一个数组里面的数字做判断
for(let j = 4 ;j<8;j++){
if(arrNum[i][j]==4){
// console.log('4');//这里可以打印有多少个数字后四位存在4
arrNum.splice(i,1);//删掉这个数字
break;//退出循环
}
}
}
console.log(arrNum);//打印除掉后四位有4的数字
//拿到后四位没有4的数字了 就可以开始做aabb aaaa abab的判断了
let endNum =[];//存储最后的数字
for(let i of arrNum.keys()){
if(arrNum[i][0]==arrNum[i][1]&&arrNum[i][1]==arrNum[i][2]&&arrNum[i][2]==arrNum[i][3]){
// console.log(arrNum[i]);//有没有aaaa的呢
endNum.push(arrNum[i]);
}else if(arrNum[i][0]==arrNum[i][1]&&arrNum[i][2]==arrNum[i][3]){
// console.log(arrNum[i]);
endNum.push(arrNum[i]);
}else if(arrNum[i][0]==arrNum[i][2]&&arrNum[i][1]==arrNum[i][3]){
// console.log(arrNums[i]);
endNum.push(arrNum[i]);
}
}
return endNum;
}
console.log(chooseNum());
</script>
2. 写一个原型链继承的例子
//DOM封装查询
function Elem(id){
this.elem = document.getElementById(id);
}
Elem.prototype.html = function(val){
var elem = this.elem;
if(val){
elem.innerHTML = val;
return this;
}else{
return elem.innerHTML;
}
}
Elem.prototype.on = function (type,fn){
var elem = this.elem;
elem.addEventListener(type,fn);
return this;
}
var div1 = new Elem('div1');
div1.html('<p>hello world</p>').on('click',function(){
alert('clicked');
}).html('<p>hello javascript</p>');
3.用js创建10个<a>标签,点击的时候弹出来对应的序号
var i;
for(i=0;i<10;i++){
(function(i){
var a = document.createElement('a');
a.innerHTML = i + '<br>';
a.addEventListener('click',function(e){
e.preventDefault();
alert(i);
});
document.body.appendChild(a);
})(i);
}
4.获取2018-4-26格式的日期
function formatDate(dt){
if(!dt){
dt = new Date();
}
var year = dt.getFullYear();
var month = dt.getMonth() + 1;
var date = dt.getDate();
if(month<10){
month = '0' + month;
}
if(date<10){
date = '0' +date;
}
return year + '-' + month + '-' + date;
}
var dt = new Date();
var formatDate = formatDate(dt);
console.log(formatDate);
5.写一个能遍历对象和数组的通用的forEach函数
function forEach(obj,fn){
var key;
if(obj instanceof Array){
obj.forEach(function(item,index){
fn(index,item);
});
}else{
for(key in obj){
fn(key,obj[key]);
}
}
}
var arr = [1,2,3];//数组
forEach(arr,function(index,item){
console.log(index,item);
})
var obj = {x:1,y:2};//对象
forEach(obj,function(key,val){
console.log(key,val);
})
6.冒泡排序
function bubbleSort(arr) {
for(let i = 0,l=arr.length;i<l-1;i++) {
for(let j = i+1;j<l;j++) {
if(arr[i]>arr[j]) {
let tem = arr[i];
arr[i] = arr[j];
arr[j] = tem;
}
}
}
return arr;
}
module.exports = bubbleSort;
//es6写法
let arr = [43, 32, 1, 5, 9, 22];
const sort = arr => {
arr.forEach((v, i) => {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
[arr[i],arr[j]] = [arr[j],arr[i]]
}
}
})
return arr
}
console.log(sort(arr)) // [1, 5, 9, 22, 32, 43]
7.字符串转驼峰
var str="border-bottom-color";
function Change(str){
var arr=str.split("-");
for(var i=1;i<arr.length;i++){
arr[i]=arr[i].charAt(0).toUpperCase()+arr[i].substring(1);
}
str=arr.join("");
return str;
}
console.log(Change(str));//borderBottomColor
8.查找字符串中出现次数最多的字符和次数
解决方法一:
var str = "sdddrtkjsfkkkasjdddj";
var max = 0;
var char;
function Search(str) {
var obj = {};
for (var i = 0; i < str.length; i++) {
if (!obj[str[i]]) {
obj[str[i]] = str[i];
} else {
obj[str[i]] += str[i];
}
}
for (var i = 0; i < str.length; i++) {
if (obj[str[i]].length > max) {
max = obj[str[i]].length;
char = str[i];
}
}
console.log("出现次数最多的字符是" + char + ",出现了" + max + "次")
}
Search(str);
解决方法二:
function repeatCharNum(str){
var arr = str.split('');
str = arr.sort().join('');
var re = /(\w)\1+/g;
var index = 0;
var value = '';
str.replace(re,function($0,$1){
if(index < $0.length){
index = $0.length;
value = $1 ;
}
});
alert ('最多字符'+value+'出现的次数'+index);
}
9.编写一个函数,将输入的参数中的数字字符追加为一个数字字符串,参数输入不确定
function getStrChange(){
var len = arguments.length;//参数不确定时使用arguments关键字
var re = /^\d+$/;
var str = '';debugger;
for(var i =0; i< len; i++){
if(!(re.test(arguments[i]))){
continue;
}
if(i == len-1){
str = str+arguments[i];
}else{
str = str+arguments[i]+',';
}
}
return str;
}
alert(getStrChange('1','a','45','b','3',1));//('1,45,3,1')
10.JS 把url的参数解析成对象
function parseUrl(str) {
// 判断是否传入参数
if (str) {
var obj = {};
var queryArr = [];
// 正则表达式规则
var re = /^(http\w?):\/\/([0-9a-zA-Z\.]+)([a-zA-Z0-9\/]+)\?([a-zA-Z0-9\=\&]+)#([0-9a-zA-Z\.]+)/;
// 利用正则表达式将字符串分组
var reArr = re.exec(str);
if (reArr) {
obj.peotocol = reArr[1];
obj.host = reArr[2];
obj.path = reArr[3];
queryArr = reArr[4].split(/[\&\=]+/);
obj.query = {};
for (var i = 0; i < queryArr.length; i += 2) {
obj.query[queryArr[i]] = queryArr[i + 1];
}
obj.hash = reArr[5]
return obj;
} else {
return null;
}
} else {
return null;
}
}
方法二:
// url参数解析
function getUrlkey(url) {
var params = {};
var urls = url.split("?"); console.log('1_分割url:', urls)
var arr = urls[1].split("&"); console.log('2_分割urls[1]:', arr)
for (var i = 0, l = arr.length; i < l; i++) {
var a = arr[i].split("="); console.log('3_遍历 arr 并分割后赋值给a:', a[0], a[1])
params[a[0]] = a[1]; console.log('4_a给params对象赋值:', params)
} console.log('5_结果:', params)
return params;
}
console.log(6,getUrlkey('http//aaa/txt.php?a=1&b=2&c=3'))
11.JS实现add(1)(2)(3)(4)的调用方式
第一种:
var add = function (m) {
var temp = function (n) {
return add(m + n);
}
temp.toString = function () {
return m;
}
return temp;
};
add(3)(4)(5); // 12
add(3)(6)(9)(25); // 43
这个add函数可以无限次调用循环调用,并且把所有传进去的值相加,最后返回相加总数。这道题咋一看有点特别,但代码量极其少而精,重点技术在于:作用域、交替、匿名函数、toString的巧妙。
让我们来解释这个过程:add(3)(4)(5)
1、先执行add(3),此时m=3,并且返回temp函数;
2、执行temp(4),这个函数内执行add(m+n),n是此次传进来的数值4,m值还是上一步中的3,所以add(m+n)=add(3+4)=add(7),此时m=7,并且返回temp函数
3、执行temp(5),这个函数内执行add(m+n),n是此次传进来的数值5,m值还是上一步中的7,所以add(m+n)=add(7+5)=add(12),此时m=12,并且返回temp函数
4、关键性一步来了,后面没有传入参数,等于返回的temp函数不被执行而是打印,了解JS的朋友都知道对象的toString是修改对象转换字符串的方法,因此代码中temp函数的toString函数return m值,而m值是最后一步执行函数时的值m=12,所以返回值是12。
看到这其实就很明白了,代码中temp.toString的重写只是为了函数不执行时能够返回最后运算的结果值,所以这个地方是可以任意修改的,你让它返回什么它就返回什么,比如改写:
temp.toString = function () {
return “total : ” + m;
}
执行结果:add(3)(4)(5); //total : 12
第二种:
function add(x) {
var sum = x;
var tmp = function (y) {
sum = sum + y;
return tmp;
};
tmp.toString = function () {
return sum;
};
return tmp;
}
console.log(add(1)(2)(3)); //6
console.log(add(1)(2)(3)(4)); //10
首先要一个数记住每次的计算值,所以使用了闭包,在tmp中记住了x的值,第一次调用add(),初始化了tmp,并将x保存在tmp的作用链中,然后返回tmp保证了第二次调用的是tmp函数,后面的计算都是在调用tmp, 因为tmp也是返回的自己,保证了第二次之后的调用也是调用tmp,而在tmp中将传入的参数与保存在作用链中x相加并付给sum,这样就保证了计算;
但是在计算完成后还是返回了tmp这个函数,这样就获取不到计算的结果了,我们需要的结果是一个计算的数字那么怎么办呢,首先要知道JavaScript中,打印和相加计算,会分别调用toString或valueOf函数,所以我们重写tmp的toString和valueOf方法,返回sum的值。
12.js中0.1+0.2不等于0.3问题,解决方法
因为js使用的双精度浮点,所以在计算机内部存储数据的编码会出现误差,导致0.1+0.2=0.30000000000000004。和0.3相比较结果为false。
我目前所知道的解决方法有以下几种:
1.将其先转换成整数,再相加之后转回小数。具体做法为先乘10相加后除以10.如下图
let x=(0.1*10+0.2*10)/10;
console.log(x===0.3)
2.使用number对象的toFixed方法,toFixed方法可以指定运算结果的小数点后的指定位数的数字,使保留一位小数就是toFixed(1)。
//let x=(0.1+0.2).toFixed(1)
//因为使用toFixed方法将number类型转换成了字符串类型
//,所以使用parseFloat将字符串转回number类型
let x=parseFloat((0.1+0.2).toFixed(1));
console.log(x===0.3);
3.使用es6新增的Number.EPSILON方法,这个方法表示js的最小精度,使用这个方法通常只是对0.1+0.2是否=0.3做判断,并不像前两种改变0.1+0.2的值。
function equal(a, b) {
return Math.abs(a - b) < (Number.EPSILON ? Number.EPSILON : Math.pow(2, -52));
//此处使用了三目运算符对IE进行兼容,也可以使用if(Number.EPSILON)进行兼容判断。
}
/*不考虑兼容
function equal(a,b){
return Math.abs(a-b)<Number.EPSILON;
//相当于把比较的boolean值返回
}
*/
console.log(equal(0.1 + 0.2, 0.3))
13.数组中两项之和等于某个固定值
算法一:遍历每一个元素,让指定值减去每一个元素,得到的数再进行判断是否有在该数组中,返回对应的索引
function addToTarget(arr,target){
let result = []
for (let i = 0; i < arr.length; i++) {
const val = target - arr[i];
//这里用slice(i + 1)截取i之后的字符串,避免取出重复数据
const index = arr.slice(i + 1).indexOf(val);
if (index !== -1) {
result.push([arr[i],val]);
}
}
return result
}
const arr = [1,4,5,3,8,9];
addToTarget(arr,13)
算法二: Map