js经典题目

1闭包

链接:学习Javascript闭包(Closure)

function close(){
    var arr = [1,2,3,4]
	for( var i = 0; i < arr.length; i ++){
		setTimeout(function(){
			console.log(i)
		})
	}
} 
close(arr)//4,4,4,4
复制代码

setTimeout在js单线程中只是放在队列中并未调用,等到主线程任务完成才会执行
链接:JavaScrip同步、异步、回调执行顺序之经典闭包setTimeout分析

function close(){
    var arr = [1,2,3,4];
    for( var i = 0; i < arr.length; i ++){
    	(function(i){
    		setTimeout(function(){
    			console.log(i)
    		})
	})(i)
}
} 
close()//0,1,2,3
复制代码

立即执行函数在每一次循环中执行setTimeout函数并将值传到setTimeout函数中

function close(){
	var arr = [1,2,3,4]
	for( let i = 0; i < arr.length; i ++){
		setTimeout(function(){
			console.log(i)
		})
	}
} 
close()//0,1,2,3
复制代码

es6区块作用域变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

2排序

快排

var arr = [1,3,6,2,8,7]
function quickSort(arr){
	if (arr.length<=0) {return arr} ;
	let mid = arr.splice((arr.length/2),1),
	left = [],
	right = [];
	arr.forEach(function(item){
		item < mid ? left.push(item) : right.push(item)
	})
	return quick(left).concat(mid,quick(right))
}
console.log(qucikSort(arr))//1,2,3,6,7,8
复制代码

"快速排序"的思想很简单,整个排序过程只需要三步:
(1)在数据集之中,选择一个元素作为"基准"(pivot)。
(2)所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边。
(3)对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。

冒泡排序

var arr = [1,3,6,2,8,7]
function bullSort(arr){
    var temp= [];
    for(var i = 0; i < arr.length-1; i++){
        for(var j = i+1; j < arr.length; j++){
            if(arr[i] > arr[j]){
                var temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr
}
console.log(bullSort(arr))//1,2,3,6,7,8
复制代码

随便从数组中拿一位数和后一位比较,如果是想从小到大排序,那么就把小的那一位放到前面,大的放在后面,简单来说就是交换它们的位置,如此反复的交换位置就可以得到排序的效果。

3js继承

类继承

var Father = function(){
	this.name = "xiaowang";
	this.age = 18;
}
Father.prototype.run = function(){
	console.log(this.name+this.age)
}
var Child = function(){
	
}
Child.prototype = new Father() 
var child1 = new Child();
 child1.run();//xiaowang18
复制代码

构造函数Child通过prototype(原型)等于构造函数Father的一个实列来继承构造函数Father的所有属性和方法 Child.prototype = new Father() = Father._proto

构造函数继承

//构造函数继承
var Father = function(){
	this.name = "xiaowang";
	this.age = 18;
};
Father.prototype.run = function(){
	console.log(this.name+this.age)
};
var Child = function(){
	Father.call(this)
};
var child1 = new Child();
// console.log(child1);
复制代码

构造函数Child通过改变call函数改变this指向来继承构造函数Father的所有属性和方法
Child = this = Father

组合式继承

var Father = function(){
	this.name = "xiaowang";
	this.age = 18;
};
Father.prototype.run = function(){
	console.log(this.name+this.age)
};
var Child = function(){
	Father.call(this)
};
Child.prototype = new Father() 
var child1 = new Child();
// console.log(child1);
复制代码

链接:js:面向对象编程,带你认识封装、继承和多态

class Father{  
    constructor(color){  
        this.color = 'red';  
    };  
}  
class Child extends Animal{  
    constructor(){  
        super();//Father.apply(this)  
    }  
}
var Child1 = new Child()
console.log(Child1) 
复制代码

4 this,call,apply,bind

call,apply,bind干什么的?为什么要学这个?在没有学之前,通常会有这些问题。

var a = {
    user:"xiaowang",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b(); //undefined
复制代码

b方法执行的this是全局window而window是没有定义user这个属性的所以最后结果是undefined。
apply 和 call 的区别:
apply 和 call 基本类似,他们的区别只是传入的参数不同。apply只能传入一个参数但可以是一个数组,而call可以传入多个参数

var a = {
    user:"xiaowang",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b.call(a); //xiaowang
复制代码
var a = {
    user:"xiaowang",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b.apply(a); //xiaowang
复制代码

bind方法可以理解为定义了一个方法想要有效果的话必须执行该方法,即后面再加一个括号

var a = {
    user:"xiaowang",
    fn:function(){
        console.log(this.user);
    }
}
var b = a.fn;
b.bind(a)(); //xiaowang
复制代码
function log(){
	console.log.apply(console, arguments);
};
log("aa","bb")
复制代码

5数组一些方法

1去重

根据json特性不能有相同key值实现

function unique(arr){
	var json = {};
	for(var i = 0; i < arr.length; i ++){
		if(json[arr[i]]){
			json[arr[i]]++;
		}else{
			json[arr[i]]=1;
		}
	}
console.log(json) 
}
复制代码

es6特性数组不可以有相同数字

function unique(arr){
	console.log(...new Set(arr))
}
复制代码

第一个和第二个数字对比如果相同则跳过

function unique(arr){
	var result = [],
  	i,
  	j,
  	len = arr.length;
 	for(i = 0; i < len; i++){
 	 	for(j = i + 1; j < len; j++){
	   		if(arr[i] === arr[j]){
	    		j = ++i;
   			}
  		}
  		result.push(arr[i]);
  	}
  }
复制代码

2扁平化数组

根据toString将数组变为用,分割的数组字符串然后再转为数字

var flatt= function(){
 	var arr = [1,2,3,[1,2,3,[1,2,3]]];
 	var arrstr = arr.toString().split(",")
 	var arr1 = [];
 	for(var i = 0; i < arrstr.length; i ++){
 		arr1.push(Number(arrstr[i]))
 	}
 	console.log(arr1)
 }
复制代码

使用数组判断方法Array.isArray判断是否为数组,递归操作数组

var arr = [1,2,3,[1,2,3,[1,2,3]]];
var flatt= function(arr){
    var res = [];
 	for(var i = 0; i < arr.length; i ++){
 		if(Array.isArray(arr[i])){
 			res = res.concat(flatt(arr[i]))
 		}else{
 			res.push(arr[i])
 		}
 	}
 	console.log(res)
 }
复制代码

3删除数组中指定的数字

找到要删除数字的索引,使用数组splice方法删除

var delArr = function(){
	var arr = [1,2,3,[1,2]];
	var res = [1,2]
	function getI(arr,res){
		for(var i = 0; i < arr.length; i ++){
			if(res.toString() == arr[i].toString()){
				return i
			}
		}
	}
	arr.splice(getI(arr,res),1);
	return arr;
}
复制代码

4一个数组中出现次数最多的数字

循环数组使用json统计数字出现的次数,然后枚举json对比一个最大值

var maxNum = function(arr){
	var json = {};
	for(var i = 0; i < arr.length; i ++){
		if(json[arr[i]]){
			json[arr[i]]++;
		}else{
			json[arr[i]]=1;
		}
	};
	// return json
	var maxKey = null;
	var maxVal = null;
	for(name in json){
		if(maxVal < json[name]){
			maxVal = json[name];
			maxKey = name;
		}
	}
	return "出现次数最多的数"+maxKey+"出现了"+maxVal+"次"
};
复制代码

5字符串反转

function reverse(){
 	var str = "abc";
 	console.log([...str])
 	let strarr = [...str].reverse().join("");
 	console.log(strarr)
}
复制代码

6 浅拷贝深拷贝

浅拷贝只拷贝第一层对象值

function shallowCopy(obj){
 	let newObj = {}
 	for(let key in obj){
 		newObj[key] = obj[key]
 	}
 	return newObj
}
复制代码

深拷贝判断对象值是否是对象,是则递归拷贝

function deepCopy(obj){
     let newObj = {}
     for(let key in obj){
     	newObj[key] = typeof obj[key] === "object" ? deepCopy(obj[key]) : obj[key]
     	
     }
     return newObj
}
复制代码

深拷贝新建对象改变值不会影响到原来对象

let obj={
 	name:"xiaoming",
 	age:{
 		name:"xiaolv"
 	}
 }
 var a = shallowCopy(obj);
 a.age.name= "xiao1"
 console.log(a)
 console.log(obj)
复制代码

7判断数据类型方式

1 typeof

typeof 是解释器内部实现,根据 ECMA-262规定的几种类型的值来返回类型名称,基本上只能判断出来使用字面量方式赋值的基本数据类型

2 instanceof

instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性,instanceof的局限性应该也就是不能检测基本数据类型了吧,

var arr = []; 
arr instanceof Array; // true
复制代码

3 Object.prototype.toString

所有的数据类型都可以用 Object.prototype.toString 来检测,而且非常的精准。 返回'[object object]'字符串

function type(obj) {
	var toString = Object.prototype.toString;
	var map = {
	    '[object Boolean]'  : 'boolean', 
	    '[object Number]'   : 'number', 
	    '[object String]'   : 'string', 
	    '[object Function]' : 'function', 
	    '[object Array]'    : 'array', 
	    '[object Date]'     : 'date', 
	    '[object RegExp]'   : 'regExp', 
	    '[object Undefined]': 'undefined',
	    '[object Null]'     : 'null', 
	    '[object Object]'   : 'object'
	};
	return map[toString.call(obj)];
}
复制代码

4 construtor

constructor 属性返回对创建此对象的数组函数的引用,就是返回对象相对应的构造函数。

var arr = []; 
arr.constructor == Array; //true
复制代码

链接:数据类型检测

8 原生事件

return 一个实例在原型上添加方法并return this

var navtive = function(){
	var G=function(el){
		return new G_(el);
	}
	var G_=function(el){
		this.el = document.querySelector(el);
	}
	G_.prototype.on=function(ev,callback){
		this.el.addEventListener(ev,callback,false)
		return this
	}
	G(".native").on("mouseover",function(){
		alert(1)
	}).on("mouseout",function(){
		alert(2)
	})
}
// navtive();
复制代码

9 手写一个原生Bind方法

//context为需要被绑定上的对象,arguments是参数  
Function.prototype.bind = function(context){
  var self = this; //this => Function
  return function(){
      return self.apply(context,arguments)
  }
}
复制代码
//复杂一点的
Function.prototype.bind = function(){
  var self = this; //this => Function
  var context = [].shift.call(arguments); //arguments 的第一个为需要绑定的this上下文
  console.log(context)
  var args = [].slice.call(arguments)// arguments除了第一个,成为一个数组
  console.log(args)
  return function(){
      return self.apply(context,[].concat.call(args,[].slice.call(arguments)))
  }
}
复制代码

ES6版

Function.prototype.bind = function(that, ...argv) {
  if (typeof this !== 'function') {
    throw new TypeError(`${this} is not callable`);
  }
  // 保存原函数
  let self = this;
  // 获取bind后函数传入的参数
  return function(...argu) {
    return self.apply(that, [...argv, ...argu]);
  };
};
let func1 = function(a, b, c) {
  console.log(this.ll);
  console.log([a, b, c]);
}.bind(obj, 1, 2);

func1(3); // seve
// [ 1, 2, 3 ]
复制代码
Function.prototype.bind = function() {
  if (typeof this !== 'function') {
    throw new TypeError(`${this} is not callable`);
  }
  var self = this;
  var slice = [].slice;
  // 模拟es6的解构效果
  var that = arguments[0];
  var argv = slice.call(arguments, 1);
  return function() {
    // slice.call(arguments, 0)将类数组转换为数组
    return self.apply(that, argv.concat(slice.call(arguments, 0)));
  };
};
let func2 = function(a, b, c) {
  console.log(this.ll);
  console.log([a, b, c]);
}.bind(obj, 1, 2);

func2(3); // seve
// [ 1, 2, 3 ]
复制代码
//运行
var obj = {name: 'shaojingjing'}
var func = function(a,b,c,d){
  alert(this.name); // shaojingjing
  alert([a,b,c,d]) // [1,2,3,44]
}.bind(obj,1,2)(3,4)
复制代码

10原生Ajax

 function ajax(){
    var ajax = new XMLHttpRequest();
    //步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数,动态的传递参数starName到服务端
    ajax.open('get','getStar.php?starName='+name);
    //步骤三:发送请求
    ajax.send();
    //步骤四:注册事件 onreadystatechange 状态改变就会调用
    ajax.onreadystatechange = function () {
        if (ajax.readyState==4 &&ajax.status==200) {
            //步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
            console.log(xml.responseText);//输入相应的内容
            
        }
    }
}
复制代码

11获取一个className

function getObjsByClass(tagName, className){
    if(document.getElementsByClassName){
        alert("document.getElementsByClassName");
        return document.getElementsByClassName(className);
    }else{
        var el = [];
        var _el = document.getElementsByTagName(tagName);
        for(var i=0; i<_el.length; i++){
            if(_el[i].className.indexOf(className) > -1){
                alert(_el[i]);
                el[_el.length] = _el[i];
            }
        }
        alert(el);
        return el;
    }
}
复制代码

12数组转换

1 取值[[1,2]['xiaowang',xiaohong]]

var arr = [{'id':1,'name':'xiaowang'},{'id':2,'name':'xiaohong'},{'id':3,'name':'xiaolv'}]
 function getArr(arr){
 	var newjson = {}
	for(var i = 0; i < arr.length; i ++){
	 	for(var key in arr[i]){
	 		if(!newjson[key]){
	 			newjson[key]=[]
	 		}
	 		newjson[key].push(arr[i][key])
	 	}
	}
	return newjson
 }
复制代码

2 1234567890->1,234,567,890

//1黑科技
(123456789).toLocaleString('en-US')  // 1,234,567,890
//2js
var test = '1234567890'
function formatCash(str) {
    var arr = []
    for(var i = 1; i < str.length; i++) {
        if(str.length % 3 && i == 1) {
            arr.push(str.substr(0, str.length % 3))
        }
        if(i % 3 === 0) {
            arr.push(str.substr(i - 2, 3))
        }
    }
    return arr.join(',')
}
console.log(formatCash(test)) // 1,234,567,890
复制代码

13js获取url参数

function getParams(){
  	var params = {}
  	var search = location.search;
  	search.slice(1).split('&').forEach(function(val){
  		var arr = val.split('=');
  		console.log(arr)
  		params[arr[0]]=arr[1]
  	})
  	return params
}
console.log(getParams());**
复制代码

转载于:https://juejin.im/post/5a5c776df265da3e303c7856

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值