判断this
现在我们可以根据优先级来判断函数在某个调用位置应用的是哪条规则。可以按照下面的 顺序来进行判断:
- 函数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。 var bar = new foo()
- 函数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是 指定的对象。 var bar = foo.call(obj2)
- 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上 下文对象。 var bar = obj1.foo()
- 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到 全局对象。 var bar = foo() 就是这样。对于正常的函数调用来说,理解了这些知识你就可以明白 this 的绑定原理了。 不过......凡事总有例外。
作用域闭包
定义: 当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。
原型
模板编译函数
let tem = '我是{{obj.name}},我爱{{ obj.hobby?"singing":"dance"}}'
let obj = {
name: "gp",
hobby: 0
}
compile(tem, obj) // 我是gp,我爱dance
function compile(tem, obj){
let reg = /\{\{(.*?)\}\}/g
let strFun = '""'
var strArr = tem.split(reg)
var regArr = tem.match(reg)
console.log(strArr) // ["我是", "obj.name", ",我爱", "obj.hobby?"singing":"dance"", ""]
console.log(regArr) // ["{{obj.name}}", "{{obj.hobby?"singing":"dance"}}"]
strArr.forEach((item, index)=>{
if(item !== "" && regArr.toString().includes(item)){
strFun += "+(" + item +")"
}else{
strFun += "+"+ '"' + item +'"'
}
})
console.log(strFun) // ""+"我是"+(obj.name)+",我爱"+(obj.hobby?"singing":"dance")+""
var fun = new Function( 'obj','return ' + strFun)
return fun(obj)
}
判断对象为空
# 自身没有可枚举的
function isObjectEmpty(obj) {
if (obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
return false;
}
}
}
return true;
}
判断类数组
function isLength(value) {
return typeof value == 'number' &&
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
function isArrayLike(value) {
return value != null && isLength(value.length) && !isFunction(value);
}
柯里化
function curry(fn, ...args) {
return args.length < fn.length
? (...restArgs) => curry(fn, ...args, ...restArgs)
: fn(...args)
}
//test
function add(a, b, c) {
return a + b + c
}
var add1 = curry(add)
console.log(add1(1)(2)(3))
const foo = curry( (a,b,c,d) => {
console.log(a, b, c, d)
})
foo(1)(2)(3)(4)
全排列
function permutate(str) {
var result=[];
if(str.length==1){
return [str]
}else{
var preResult=permutate(str.slice(1));
for (var j = 0; j < preResult.length; j++) {
for (var k = 0; k < preResult[j].length+1; k++) {
var temp=preResult[j].slice(0,k)+ str[0]+ preResult[j].slice(k);
result.push(temp);
}
}
return result;
}
}
console.log(permutate("abc"));
debounce
const debounce = (func, delay) => {
let inDebounce
return function() {
const context = this
const args = arguments
clearTimeout(inDebounce)
inDebounce = setTimeout(() => func.apply(context, args), delay)
}
}
throttle
const throttle = (func, limit) => {
let lastFunc
let lastRan
return function() {
const context = this
const args = arguments
if (!lastRan) {
func.apply(context, args)
lastRan = Date.now()
} else {
clearTimeout(lastFunc)
lastFunc = setTimeout(function() {
if ((Date.now() - lastRan) >= limit) {
func.apply(context, args)
lastRan = Date.now()
}
}, limit - (Date.now() - lastRan))
}
}
}
bind
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound;
};
四舍五入-原生toFixed() 方法不准确
function toFixed(num, s) {
var times = Math.pow(10, s);
var des = num * times + 0.5;
des = parseInt(des, 10) / times;
return des + '';
}
小数相乘
function accMul(arg1, arg2) {
let m = 0,
s1 = arg1.toString(),
s2 = arg2.toString()
try {
m += s1.split('.')[1].length
} catch (e) {} // eslint-disable-line
try {
m += s2.split('.')[1].length
} catch (e) {} // eslint-disable-line
return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m)
}
使对象拥有 iterator
var myObject = { a: 2,
b: 3 };
Object.defineProperty( myObject, Symbol.iterator, { enumerable: false,
writable: false,
configurable: true,
value: function() { var o = this;
var idx = 0;
var ks = Object.keys( o ); return {
next: function() { return {
value: o[ks[idx++]],
done: (idx > ks.length)
};
} };
} } );
// 手动遍历 myObject
var it = myObject[Symbol.iterator]();
it.next(); // { value:2, done:false }
it.next(); // { value:3, done:false }
it.next(); // { value:unde ned, done:true }
// 用 for..of 遍历 myObject
for (var v of myObject) { console.log( v );
}
// 2
// 3
待续。。。