函数节流的代码实现:
let throttle = function (fn, interval) {
let _self = fn, //保存需要被延迟执行的函数引用
timer, //定时器
firstTime = true; //是否第一次调用
return function () {
let args = arguments;
let _me = this;
if(firstTime){
_self.apply(_me,args);
return firstTime = false;
}
if(timer){
return false;
}
timer = setTimeout(function () {
clearTimeout(timer);
timer = null;
_self.apply(_me, args);
}, interval || 500);
};
};
window.onresize = throttle(function () {
console.log(1);
},500);
throttle 函数的原理是: 将即将被执行的函数 setTimeout 延迟一段时间执行,如果该次延迟执行还没有完成,则忽略接下来调用该函数的请求。fn 为需要被延迟执行的函数,interval 为延迟执行的时间。
4、分时函数 timeThunk
let timeChunk = function (ary,fn,count) {
let obj,t;
let len = ary.length;
let start = function () {
for(let i = 0; i
fn(obj);
}
};
return function () {
t = setInterval(function () {
if(ary.length === 0 ){
return clearInterval();
}
start();
}, 200);
};
}
timeThunk 接受三个参数,第一个是创建节点需要用到的数据,第二个参数是封装了节点逻辑的函数,第三个参数是表示每一批创建的节点数量。
降低全局变量带来的命名污染:
1、动态创建命名空间:
2、使用闭包封装私有变量
let user = (function () {
let _name = 'Shrijin',
_age = 21;
return {
getUserInfo: function () {
return _name + '-' + _age;
}
}
})();
把一些变量封装在闭包的内部,只暴露一些接口和外界通信,外部就访问不到私有变量,这样就避免了全局的命名污染。
以下代码在不同的浏览器控制台有不同的输出
function Foo(){}
let fn = new Foo();
fn;
在Chrome的控制台输入 fn ,回车得到的是 Foo{ }
在Firefox控制台输出的是 Object { }
在《You don't know JS》中,提到Chrome想说的是 { } 是一个空对象,由名为Foo的函数构造; 而Firefox想说的是{ }是一个空对象,由Object 创建。之所以有这种细微的差别,是因为Chrome会动态跟踪并把实际执行构造过程的函数名当作一个内置属性,而其他浏览器并不会跟踪这些额外的信息。
隐藏滚动条的CSS3样式解决兼容写法:
html { overflow: -moz-hidden-unscrollable; height: 100%; }
body::-webkit-scrollbar { display: none; }
body { -ms-overflow-style: none; height: 100%; width: calc(100vw + 18px); overflow: auto; }有时内容还要根据需要来添加width:100vw
Generator 函数实现斐波那契数列:
function* fibonacci() {
let [prev, curr] = [0, 1];
for (;;) {
[prev, curr] = [curr, prev + curr];
yield curr;
}
}
for (let n of fibonacci()) {
// 输出1000以内的斐波那契数列项
if (n > 1000) break;
console.log(n);
}
yield* 语句可以方便快捷地取出嵌套数组中的成分
function* iterTree(tree) {
// debugger;
if (Array.isArray(tree)) {
for (let i = 0; i < tree.length; i++) {
yield* iterTree(tree[i]);
}
} else {
yield tree;
}
}
const tree = ['a', ['b', 'c'], ['d', 'e']];
for (let x of iterTree(tree)) {
console.log(x);
}
利用Generator 函数,可以在任意对象上部署Iterator接口
function* iterEnties(obj) {
let keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
yield [key, obj[key]];
}
}
let myObj = { foo: 3, bar: 7};
for (let [key, value] of iterEnties(myObj)) {
console.log(key, value);
}
setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log(’one‘)则是立即执 行
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// 输出
// one
// two
// three
Promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误不会冒泡到 全局)。提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。
Promise.prototype.done = function (onFulfilled, onRejected) {
this.then(onFulfilled, onRejected)
.catch(function (reason) {
// 抛出一个全局错误
setTimeout(() => { throw reason }, 0);
});
};
finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不 管怎样都必须执行。
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
任何函数,只要参数有回调函数,就能写成Thunk函数的形式。es5 和ES6版本的Thunk 函数转换器
let ThunkEs5 = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return function (callback) {
args.push(callback);
return fn.apply(this, args);
}
};
};
// es6版本
let ThunkEs6 = function (fn) {
return function (...args) {
return function (callback) {
return fn.call(this, ...args, callback);
}
};
};