JavaScript知多少
在一些高频触发的事件中(如onresize,scroll,mousemove等),有时候我们并不希望每次触发事件就执行回调,这时候我们就需要

delete
delete只能删除属性,不能删除变量
用var创建的是变量不能被delete消除。而省略var时声明的是全局对像window的一个属性,可以被delete消除。
js
a = 1; //声明一个全局对像window的属性
var b = 2; //创建一个全局变量
delete a;
delete b;
alert(a); //error: a is not defined
alert(b) //2 变量没有被删除
new
用new操作符创建对像时会改变默认的this,this将指向构造函数
function Fn(){
alert(this);
}
Fn(); //[object Window]
new Fn(); //[object Object]
执行顺序
javascript是一门解释语言,默认情况下是从上到下顺序执行的。 但这也不是绝对的。在没有用关键字var申明的全局函数就会首先被执行(函数声明提升)
js
aF(); //2
aV(); //error: bV is not defined
function aF(){
b(b); //调用全局函数b
}
unction b(){
alert(2);
}
function aV(){
alert(bV); //调用全局变量bV
}
bV = 'bv';
使用var声明的变量会被提到执行环境有最上方,但变量的赋值还是在原来的位置(变量声明提升)
if (true) {
var a = 123;
}
alert(a); //123 外面能够访问到if语句块里面声明的变量
实例属性会覆盖原型属性
javascript变量搜索是沿着作用域链反向查找的。因此,当在构造函数和原型中声明了相同的属性时,构造函数中的属性会优先于原型有的属性被查找,当变量搜索机制在构造函数中找到属性时,变量查询将会停止。
js
function F(name){
this.name = name;
}
F.prototype = {
name: 'javascript:;'
}
var f = new F('Backbone');
console.log(f.name); //Backbone
var fn = new F();
console.log(fn.name); //undefined 即使没有向构造函数传值,由于构造函数已经声明了name属性,所以变量查询也不会继续在原型中查找。
for……in vs Object.keys()
for……in 通常用于遍历对象的key,但原型上的key也会被一并返回
Object.keys() 返回对象实例属性key组成的数组
js
Object.prototype.a = 'aa';
let obj = {
ob: 'bb'
};
for(var i in obj) {
oconsole.log(i);
}
// 输出
// a
// b
console.log(Object.keys(obj)); // [ b ]
for……of vs forEach
for……of 通常用于遍历数组,返回数组value
forEach 也用于遍历数组,但在回调之内,用 break 不能中断循环,return 也不能返回到父级作用域
js
et arr = [3, 5, 7];
// for……of
for(const i of arr) {
oconsole.log(i)
}
// forEach
arr.forEach((item, index) => {
oconsole.log(index + '-----' + item);
});
## 数组克隆
// es5
var a1 = [1,2];
var a2 = a1.concat();
// es6
var a1 = [1,2,3];
var a2 = [...a1];
对象克隆
通过JSON.stringify 和 JSON.parse 克隆
原理:通过JSON.stringify将对象转化成字符串,再将字符串赋值给其它变量,最后再用JSON.parse解析成对象
如果对象中包含函数,刚会被过滤掉。
js
var obj = {a: 1};
var newObj = JSON.parse(JSON.stringify(obj));
newObj.a = 2;
console.log(obj); // { a: 1 }
console.log(newObj); // { a: 2 }
通过遍历对象的 key 克隆
js
function clone(obj) {
var that = this;
var o;
if (obj.constructor == Object){
o = new obj.constructor();
}else{
o = new obj.constructor(obj.valueOf());
}
for(var key in obj){
if ( o[key] != obj[key] ){
if ( typeof(obj[key]) == 'object' ){
o[key] = that.clone(obj[key]);
}else{
o[key] = obj[key];
}
}
}
o.toString = obj.toString;
o.valueOf = obj.valueOf;
return o;
}
var obj = {a:1};
var newObj = clone(obj);
newObj.a = 22;
console.log(obj); // {a: 1}
console.log(newObj); // {a: 22, toString: ƒ, valueOf: ƒ}
函数节流
在一些高频触发的事件中(如onresize,scroll,mousemove等),有时候我们并不希望每次触发事件就执行回调,这时候我们就需要用到函数节流
以函数方式实现函数节流
js
// 节流函数
function throttle(fn, interval = 500){
let timer = null;
return function(...args){
let ctx = this;
if(timer) return;
timer = setTimeout(function(){
clearTimeout(timer)
timer = null;
fn.apply(ctx, args)
}, interval)
}
}
// 绑定onresize
window.onresize = function(){
console.log(Math.random() + '===========')
t(fn,this,200);
}
函数防抖
函数防抖主要用于持续触发某个事件,但我们只希望最后一次触发才执行的回调方法的场景,比如搜索框内容变更时进行实时查询
js
const debounce = function(fn, delay) {
// 此处timer用到了闭包,防止timer被释放掉
let timer = null;
return function(...args){
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args);
}, delay)
}
}
function test(){
console.log(new Date())
}
document.addEventListener('scroll',debounce(test, 500))
Array.from()
将类数组(arguments)和可遍历的对象(Set、Map)转化为数组
js
// arguments
function a(){
console.log(Array.from(arguments));
}
a('a','ss','dd'); // ['a','ss','dd']
// Set
let set = new Set([1, 3, 3, 4, 4, 6]);
console.log(Array.from(set)); // [1, 3, 4, 6]
Array.keys()
返回一个新的Array迭代器,它包含数组中每个索引的键
js
let arr = new Array(5);
console.log(Array.from(arr.keys())); // [0,1,2,3,4]
Array.of()
将一组值转化为数组
console.log(Array.of(1, 2, 3)); // [1,2,3]
Array 原型方法 find()
用法:arr.find(fun)
find方法返回第一个满足条件的元素
js
let arr = [1,2,'a',4,'a',4];
console.log(arr.find(function(value){
return value == 'a'
}));
Array 原型方法 findIndex()
用法:arr.findIndex(fun)
findIndex方法返回第一个满足条件的元素的索引值
js
let arr = [1,2,'a',4,'a',4];
console.log(arr.findIndex(function(value){
return value == 'a'
}));
Array 原型方法 reduce()
用法:arr.reduce(fun)
findIndex返回数组每一项相加的和
js
let arr = [1,2,3,4];
let total = arr.reduce(function(a,b){
return a+b;
});
console.log(total);
Array 原型方法 includes()
es7
用法:arr.includes(value)
includes方法用于检测数组中是否包含某一个值
js
let arr = [1,2,'a',4,'a',4];
console.log(arr.includes('a'));
Array 原型方法 indexOf()
用法:arr.indexOf(value)
indexOf方法用于返回value在当前数组中第一次出现的位置,如果没有则返回-1。
js
let arr = [3, 4, 5, 3];
console.log(arr.indexOf(3));
Array 原型方法 fill()
用法:arr.fill(value)
fill 方法使用给定值,填充一个数组。
js
let arr = new Array(4);
arr.fill(5);
console.log(arr); //[ 5, 5, 5, 5 ]
Object.keys()
es8
用法:Object.keys(obj);
返回obj的索引值组成的数组
js
let obj = {
a: 'aaa',
b: 'bbb',
c: 'ccc'
};
console.log(Object.keys(obj)); // [ 'a', 'b', 'c' ]
Object.values()
用法:Object.values(obj);
返回obj的value组成的数组
js
let obj = {
a: 'aaa',
b: 'bbb',
c: 'ccc'
};
console.log(Object.values(obj)); // [ 'aaa', 'bbb', 'ccc' ]
Object.assign()
用法:Object.assign(obj[,obj]);
把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
js
llet obj1 = {
a: 1
};
let obj2 = Object.assign({}, obj1);
console.log(obj2); // { a: 1 }
obj2.a = 2;
console.log(obj1); // { a: 1 }
console.log(obj2); // { a: 2 }
console.log(Object.values(obj)); // [ 'aaa', 'bbb', 'ccc' ]