1闭包
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)
};
Child.prototype = new Father()
var child1 = new Child();
// console.log(child1);
构造函数Child通过改变call函数改变this指向来继承构造函数Father的所有属性和方法
Child = this = Father
组合式继承
ar 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);
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 flatt= function(){
var arr = [1,2,3,[1,2,3,[1,2,3]]];
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)
}
使用数组判断方法Array.isArray判断是否为数组,递归操作数组
var flatt= function(){
var arr = [1,2,3,[1,2,3,[1,2,3]]];
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])
}
}
return 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的局限性应该也就是不能检测基本数据类型了吧,
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 属性返回对创建此对象的数组函数的引用。
链接:数据类型检测
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();
网友评论