js經典題目

lonelyRoad發表於2018-04-17

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());**
複製程式碼

相關文章