js算法與應(yīng)用
排序部分
快速排序
// 從小到大的快速排序
function sort(array){
//slice用于截取數(shù)組,通過(guò)slice,從0到arr.length 復(fù)制出一個(gè)新的數(shù)組
var temp_array = array.slice(0)
quickSort = function(arr){
//數(shù)組已經(jīng)為空了
if(arr.length<=1){
return arr;
}
//數(shù)組可以繼續(xù)分割
//獲取中間元素坐標(biāo),并取出該元素
var provIndex = Math.floor(arr.length/2),
prov = arr.splice(provIndex,1)[0],
left = [],
right = [];
for(var i = 0 ; i<arr.length ; i++){
if(arr[i]>prov){
//大于中間元素向右
right.push(arr[i])
}else{
left.push(arr[i])
}
}
return quickSort(left).concat([prov],quickSort(right))
}
return quickSort(temp_array);
}
優(yōu)化過(guò)的冒泡排序
//優(yōu)化后的冒泡排序
function baboSort(arr){
//復(fù)制數(shù)組
var temp_arr = arr.slice(0),tag,temp;
for(var i = 0 ;i<temp_arr.length ;i++){
tag = 0;
for(var j =temp_arr.length-1 ;j>i ;j--){
if(temp_arr[j]>temp_arr[j+1]){
temp = temp_arr[j];
temp_arr[j] = temp_arr[j+1];
temp_arr[j+1] = temp ;
tag = 1;
}
}
if(tag === 0 ){break}
}
return temp_arr;
}
數(shù)組去重
//消除數(shù)組重復(fù)
var array = [4,2,5,2,8,4,9,1,1]
//方法一耍铜、現(xiàn)代瀏覽器方法(IE9春叫,chrome,edge,firefox..)
var newArray = array.filter(function(ele, pos,self){
return pos === self.indexOf(ele)
})
//方法二噪矛、
function unique(arr) {
var ret = [];
var len = arr.length;
var tmp = {};
var tmpKey;
for(var i=0; i<len; i++){
//序列成一個(gè)鍵進(jìn)行去重
tmpKey = typeof arr[i] + JSON.stringify(arr[i]);
if(!tmp[tmpKey]){
tmp[tmpKey] = 1;
ret.push(arr[i]);
}
}
return ret;
}
console.log(unique(array))
//方法三小渊、(es6 IE 11 CHROME 38)
function unique(arr){
//set元素都是唯一的
var set =new Set(arr);
return Array.from(set)
}
編寫一個(gè)JavaScript函數(shù)放可,輸入指定類型的選擇器(僅需支持id谒臼,class,tagName三種簡(jiǎn)單CSS選擇器耀里,無(wú)需兼容組合選擇器)可以返回匹配的DOM節(jié)點(diǎn)蜈缤,需考慮瀏覽器兼容性和性能。
var query = function(selector) {
var reg = /^(#)?(\.)?(\w+)$/img;
var regResult = reg.exec(selector);
var result = [];
//如果是id選擇器
if(regResult[1]) {
if(regResult[3]) {
if(typeof document.querySelector === "function") {
result.push(document.querySelector(regResult[3]));
}
else {
result.push(document.getElementById(regResult[3]));
}
}
}
//如果是class選擇器
else if(regResult[2]) {
if(regResult[3]) {
if(typeof document.getElementsByClassName === 'function') {
var doms = document.getElementsByClassName(regResult[3]);
if(doms) {
result = converToArray(doms);
}
}
//如果不支持getElementsByClassName函數(shù)
else {
var allDoms = document.getElementsByTagName("*") ;
for(var i = 0, len = allDoms.length; i < len; i++) {
if(allDoms[i].className.search(new RegExp(regResult[2])) > -1) {
result.push(allDoms[i]);
}
}
}
}
}
//如果是標(biāo)簽選擇器
else if(regResult[3]) {
var doms = document.getElementsByTagName(regResult[3].toLowerCase());
if(doms) {
result = converToArray(doms);
}
}
return result;
}
function converToArray(nodes){
var array = null;
try{
array = Array.prototype.slice.call(nodes,0);//針對(duì)非IE瀏覽器
}catch(ex){
array = new Array();
for( var i = 0 ,len = nodes.length; i < len ; i++ ) {
array.push(nodes[i])
}
}
return array;
}
實(shí)現(xiàn)對(duì)象的clone
// 方法一:
Object.prototype.clone = function(){
//根據(jù)構(gòu)造函數(shù)判斷是數(shù)組還是對(duì)象,分別初始化
var o = this.constructor === Array ? [] : {};
for(var e in this){
//是對(duì)象就遞歸調(diào)用clone 是數(shù)組就根據(jù)(e)index 賦值
o[e] = typeof this[e] === "object" ? this[e].clone() : this[e];
}
return o;
}
//方法二:
/**
* 克隆一個(gè)對(duì)象
* @param Obj
* @returns
*/
function clone(Obj) {
var buf;
//判斷實(shí)例
if (Obj instanceof Array) {
buf = []; //創(chuàng)建一個(gè)空的數(shù)組
var i = Obj.length;
while (i--) {
buf[i] = clone(Obj[i]);
}
return buf;
}else if (Obj instanceof Object){
buf = {}; //創(chuàng)建一個(gè)空對(duì)象
for (var k in Obj) { //為這個(gè)對(duì)象添加新的屬性
buf[k] = clone(Obj[k]);
}
return buf;
}else{ //普通變量直接賦值
return Obj;
}
}
小題合集
生成[x,y]范圍的隨機(jī)整數(shù)
function Random(min,max){
return Math.random()*(max-min)+min+1
}
//random產(chǎn)生[0,1) 如果要達(dá)到1的便捷需要+1
小數(shù)精度問(wèn)題 0.2+0.1?
console.log(0.2 + 0.1);//0.30000000000000004 精度丟失
//解決辦法
function add(num1, num2){
let r1, r2, m;
//轉(zhuǎn)換為字符串來(lái)獲取小數(shù)位數(shù)
r1 = (''+num1).split('.')[1].length;
r2 = (''+num2).split('.')[1].length;
//取位數(shù)最長(zhǎng)的
m = Math.pow(10,Math.max(r1,r2));
return (num1 * m + num2 * m) / m;
}
console.log(add(0.2+0.1)) //0.3
已知數(shù)組var stringArray = [“This”, “is”, “Baidu”, “Campus”]冯挎,Alert出”This is Baidu Campus”
var stringArray = ['This', 'is', 'Baidu', 'Campus']
console.log(stringArray.join(" "))
已知有字符串foo=”get-element-by-id”,寫一個(gè)function將其轉(zhuǎn)化成駝峰表示法”getElementById”
function hump(str){
var newStr = "", flag = false;
for(var i = 0 ; i<str.length; i++){
if(str[i]==='-'){
flag = true;
}else{
if(flag){
newStr += str[i].toUpperCase();
flag = false;
}else{
newStr += str[i];
}
}
}
return newStr;
}
var numberArray = [3,6,2,4,1,5]; 實(shí)現(xiàn)倒排底哥,排序。
//順排,倒排
var numberArray = [3,6,2,4,1,5];
//sort實(shí)現(xiàn)
var sortArr = numberArray.sort(function(a,b){
return a - b;
})
//倒排
var sortArr = numberArray.sort(function(a,b){
return b - a;
})
怎樣添加房官、移除趾徽、移動(dòng)、復(fù)制翰守、創(chuàng)建和查找節(jié)點(diǎn)
createDocumentFragment() //創(chuàng)建一個(gè)DOM片段
createElement() //創(chuàng)建一個(gè)具體的元素
createTextNode() //創(chuàng)建一個(gè)文本節(jié)點(diǎn)
//添加孵奶、移除、替換蜡峰、插入
appendChild()
removeChild()
replaceChild()
insertBefore()
//查找
getElementsByTagName() //通過(guò)標(biāo)簽名稱
getElementsByName() //通過(guò)元素的Name屬性的值
getElementById() //通過(guò)元素Id了袁,唯一性
querySelector() // 查找單個(gè)元素
querySelectorAll() //查找所有元素
將一個(gè)#fffff類型的數(shù)據(jù)轉(zhuǎn)換為rgb(255,255,255)形式
遍歷ul中l(wèi)i的內(nèi)容
(function(){
var liList = document.getElementsByTagName("li");
for(var i = 0 ; i<liList.length ;i++){
console.log(liList[i].innerHTML);
}
})()
查找一個(gè)對(duì)象是否具有某個(gè)屬性

function getNodeById(data,id){
if(data['id']==id){
return data;
}else{
if(data.hasOwnProperty("children")){
var node = null ;
data["children"].every(function(element){
node = getNodeById(element,id);
if(node){
return ;
}else{
return true;
}
})
return node;
}else{
//找不到節(jié)點(diǎn)
return ;
}
}
}
請(qǐng)寫出以下執(zhí)行結(jié)果
var myObject = {
foo: "bar",
func: function() {
//指向?qū)ο髆yObject
var self = this;
console.log("outer func: this.foo = " + this.foo);
console.log("outer func: self.foo = " + self.foo);
(function() {
//this指向windows 嚴(yán)格模式指向undefined
console.log("inner func: this.foo = " + this.foo);
//指向?qū)ο? console.log("inner func: self.foo = " + self.foo);
}());
}
};
myObject.func();
請(qǐng)寫出以下執(zhí)行結(jié)果
function foo1()
{
return {
bar: "hello"
};
}
function foo2()
{
return
{
bar: "hello"
};
}
console.log(foo1())//{bar:"hello"}
console.log(foo2())//undefined
//why?,等價(jià)于
function foo3()
{
return;
{
bar: "hello"
};
}
console.log(foo3())
關(guān)于NaN ,NaN是一個(gè)數(shù)字嗎朗恳? 判斷NaN
console.log(typeof NaN);//number
console.log(Number.isNaN(NaN))//true
console.log(NaN === NaN);//false
console.log(NaN == NaN);// fals
變量問(wèn)題
//2、變量問(wèn)題
(function(){
var a = b = 3;
//a是局部變量,b是全局變量
//等價(jià)于 var a = b ,b = 3 ;
})();
console.log("a defined? " + (typeof a !== 'undefined'));
console.log("b defined? " + (typeof b !== 'undefined'));
var a = {
n:1
},
b = a ;
a.x = a = {n:2}
/*
(先尋找變量再賦值)第一階段初始化的時(shí)候值已經(jīng)保存下來(lái)了 a.x是a的引用指向x,此時(shí)x未聲明所以此時(shí)指向null,a已經(jīng)聲明了,a指向堆中的常量{n:1},
第二階段賦值, a指向堆中的常量{n:2},a.x指向a即指向常量{n:2}
需要注意的是此時(shí)a.x在第一階段保存的引用是一開(kāi)始a的變量位置,跟賦值過(guò)來(lái)的a已經(jīng)不是一個(gè)變量了
*/
console.log(b)//{n:1}
console.log(a)//{n:2}
console.log(a.x)//undefined
var a = 2, b=1;
function temp(a){
//a有聲明所以作為局部變量處理
a = 4 ;
console.log(a)//4
//b無(wú)聲明所以當(dāng)做全局變量
b = 4
console.log(b)//4
//全局變量處理
c = 5
console.log(c)//5
}
// temp()
// temp(4)
//如果將所在函數(shù)注釋后會(huì)如何载绿?ReferenceError: c is not defined
console.log(a)//2
console.log(b)//4
console.log(c)//5
寫一個(gè)按照下面方式調(diào)用都能正常工作的 sum 方法
console.log(sum(2,3)); // Outputs 5
console.log(sum(2)(3)); // Outputs 5
function sum(){
var sum =0;
if(arguments.length<=1){
sum = arguments[0];
//只有一個(gè)情況下需要儲(chǔ)存當(dāng)前參數(shù)用作下次累加
return function(value){
sum += value
return sum;
}
}else{
return [].reduce.call(arguments,function(sum,value){
return sum+value;
},0)
}
}
//由此引出
/*
由此延伸call apply call,apply的不同點(diǎn)
call(context,arguments...) //arguments... 是若干個(gè)參數(shù)
apply(context,arguments) //arguments 是 數(shù)組
call的調(diào)用速度比apply快
相同點(diǎn) 改變函數(shù)執(zhí)行的環(huán)境
第一次參數(shù)為null的時(shí)候指向windows
模擬實(shí)現(xiàn)call,apply僻肖?
見(jiàn)https://github.com/mqyqingfeng/Blog 獲益良多
最關(guān)鍵的是
模擬的步驟可以分為:
將函數(shù)設(shè)為對(duì)象的屬性
執(zhí)行該函數(shù)
刪除該函數(shù)
*/
IIFE (Immediately-Invoked Function Expression)
for(var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
//輸出的是5個(gè)5
//解決方式
for(var i = 0; i < 5; i++) {
(function(i){
setTimeout(function() {
console.log(i);
}, 1000);
})(i)
}
//1 2 3 4 5
//那這個(gè)呢?
for(var i = 0; i < 5; i++) {
(function(){
setTimeout(function() {
console.log(i);
}, 1000);
})(i)
}
//i此時(shí)使用的還是外部的i 因?yàn)檫@樣就是提供參數(shù),但是函數(shù)本身沒(méi)有形參
//es6解決辦法卢鹦?
for(let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
//可以延伸到什么部分臀脏?
console.log(5)
for(let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
console.log(5)
//執(zhí)行順序 5->5->1~4
//原因?eventLoop,再看一個(gè)
var start = new Date();
setTimeout(function(){
console.log(4)
var time = start - new Date();
console.log(`time is `)
},2)
setTimeout(function(){
console.log(4)
var time = start - new Date();
console.log(`time2 is `)
},0)
//time 是多少? 還有這個(gè)又是多少冀自?
//基于 chrome 版本 59.0.3071.115(正式版本) (64 位)
/* 像定時(shí)器揉稚、計(jì)時(shí)器 Promise 這類的異步操作 是放在任務(wù)隊(duì)列中的,只有js主進(jìn)程棧中的任務(wù)執(zhí)行完才會(huì)執(zhí)行。詳情見(jiàn) http://www.ruanyifeng.com/blog/2014/10/event-loop.html
(基于0秒的setTimeout立即執(zhí)行已過(guò)期)
*/
/*在nodejs中進(jìn)行實(shí)驗(yàn)
hello
4
time2 is
4
time is
結(jié)果相同
但是在nodejs中 eventloop的運(yùn)行機(jī)制與瀏覽器不一樣(暫未深入了解,詳情見(jiàn)阮老師的文章)
*/
IIFE還有用處熬粗?
防止變量污染
類型問(wèn)題
簡(jiǎn)便的類型轉(zhuǎn)換
var num1 ="1a9c",num2 = 19,num3 ="20"
console.log(parseInt(num1)+num2) //20
num1 = "a1"
console.log(parseInt(num1)+num2) //NaN
console.log(num3-0) //20
真假值
極假(falsy)
false
null
undefined
' '
0
NaN
其他都是真值