手写一个call函数
es5实现
Function.prototype.call2 = function() {
var args = arguments;
var context = args[0] || window;
context.fn = this;
var newArr = [];
for(var i=0; i<args.length; i++) {
newArr.push(args[i]);
}
context.fn(newArr.slice(1).join(','));
delete context.fn;
}
var test = function(a, b) {console.log(a, b);}
test.call2({}, 1, 2);
// 1, 2
es6实现
Function.prototype.call2 = function() {
const args = [...arguments];
const context = args.shift();
context.fn = this;
context.fn(...args);
delete context.fn;
}
const test = function(a, b) {
console.log(a, b);
}
test.call2({}, 1, 2);
// 1, 2
手写一个apply
es5实现
Function.prototype.apply2 = function() {
var args = arguments;
var context = args[0] || window;
var param = agrs[1];
context.fn = this;
context.fn(param.join(','));
delete context.fn;
}
const test = function(a, b) {
console.log(a, b);
}
test.apply2({}, [1, 2]);
// 1, 2
es6实现
Function.prototype.apply2 = function() {
var args = [...arguments];
var context = args[0] || window;
context.fn = this;
var param = args[1];
context.fn(param.join(','));
delete context.fn;
}
const test = function(a, b) {
console.log(a, b);
}
test.apply2({}, [1, 2]);
// 1, 2
手写一个bind
es5实现
Function.prototype.bind = function(context) {
var fn = this;
var argsParent = Array.prototype.slice.call(arguments, 1);
return function() {
fn.call(context, ...argsParent.concat(Array.prototype.slice.call(arguments)));
}
}
var test1 = function(a, b) {
console.log(a, b);
}
test1.bind({})(1, 2)
// 1 2
es6实现
Function.prototype.bind = function() {
const fn = this;
const argsParent = [...arguments];
return function() {
fn.call(...argsParent, ...arguments);
}
}
const test1 = funciton(a, b) {console.log(a, b);}
test1.bind({})(1, 2);
// 1, 2
遍历dom树
function traversal(node) {
if (node && node.nodeType === 1) {
console.log(node.tagName);
}
var i = 0,
childNodes = node.childNodes,
item;
for (; i<childNodes.length; i++) {
item = childNodes[i];
if (item.nodeType === 1) {
traversal(item);
}
}
}
一次性插入1000个div
createDocumentFragment方法创建了一虚拟的节点对象,节点对象包含了所有属性和方法。 当你想要提取文档的一部分,改变、增加,或者删除某些内容及插入到文档末尾可以使用 createDocumentFrament方法
var oFrag = document.createDocumentFragment();
for (var i=0; i<1000; i++) {
var op = document.createElement("div");
var oText = document.createTextNode(i);
op.appendChild(oText);
oFrag.appendChild(op);
}
document.body.appendChild(oFrag);
简述new的实现过程
function new(func) {
let target = {};
target._proto_ = func.prototype;
let res = func.call(target);
if (typeof(res) === 'object' || typeof(res) === 'function') {
reuturn res;
}
return target;
}
手写一个promise
大体思路: 1 定义一个构造函数Promise2,传递一个函数参数 2 构造函数里面定义一个resolve、reject方法,用于传递出去给外面函数参数调用 3 构造函数定义一个then方法用于处理结果,也可以返回promise2 4 构造函数定义catch、finally分别处理错误回调和失败回调
function Promise2(fn) {
this.onCatchCb = null;
this.onFinallyCb = null;
this.promiseValue = null;
this.onFulfilledCb = null;
this.onRejectedCb = null;
this.thenResultPromise = null;
this.promiseStatus = 'pending'; // pending, fulfilled, rejected
this.timer = null;
var _this = this;
var resolve = function(data) {
_this.promiseValue = data;
try {
_this.onFulfilledCb &&
(_this.thenResultPromise = _this.onFulfilledCb(data));
} catch(e) {
_this.onCatchCb && _this.onCatchCb(e);
}
_this.onFinallyCb && _this.onFinallyCb();
_this.promiseStatus = 'fulfilled';
};
var reject = function(error) {
_this.promiseValue = error;
try {
_this.onRejectedCb ? (_this.thenResultPromise = _this.onRejectedCb(error)) :
_this.onCatchCb && _this.onCatchCb(error);
} catch(e) {
_this.onCatchCb && _this.onCatchCb(e);
}
_this.onFinallyCb && _this.onFinallyCb();
_this.promiseStatus = 'rejected';
};
if (typeof fn === 'function') {
fn(resolve, reject);
} else {
resolve();
}
}
Promise2.prototype = {
then: function(onFulfilled, onRejected) {
var _this = this;
onFulfilled && (_this.onFulfilledCb = onFulfilled);
onRejected && (_this.onRejectedCb = onRejected);
return new Promise2(function(resolve2, reject2) {
_this.timer = setInterval(function() {
try {
if (_this.promiseStatus !== 'pending' &&
_this.thenResultPromise.promiseStatus !== 'pending') {
if (_this.thenResultPromise.promiseStatus === 'fulfilled') {
resolve2(_this.thenResultPromise.promiseValue);
} else if (_this.thenResultPromise.promiseStatus === 'rejected') {
reject2(_this.thenResultPromise.promiseValue);
}
_this.timer && clearInterval(_this.timer);
}
} catch(e) {
reject2(e);
_this.timer && clearInterval(_this.timer);
}
}, 10);
});
},
catch: function(onCatch) {
this.onCatchCb = onCatch;
return this;
},
finally: function(onFinally) {
this.onFinallyCb = onFinally;
}
};
// test
var myPromise = new Promise2(function(resolve, reject) {
console.log('-----流程开始-----');
setTimeout(function() {
resolve('promise初始化resolve成功');
}, 500);
}).then(function(successMsg) {
return new Promise2(function(resolve, reject) {
setTimeout(function() {
console.log('promise then 1 收到 resolveMessage: ' + successMsg);
reject('from then 1');
}, 3000);
});
}).then(function(successMsg) {
return new Promise2(function(resolve, reject) {
setTimeout(function() {
console.log('myPromise then 2 收到 resolveMessage:'+successMsg);
resolve('from then 2');
}, 2000);
});
}, function(failMsg) {
return new Promise2(function(resolve, reject) {
setTimeout(function() {
console.log('myPromise then 2 收到 rejectMessage:'+failMsg);
resolve('from then 2');
}, 1000);
});
}).then(function(successMessage) {
return new Promise2(function(resolve, reject) {
setTimeout(function() {
console.log(
'myPromise then 3 收到 resolveMessage:' + successMessage
)
reject('from then 3')
}, 1000)
});
}).catch(function(error) {
console.log('caught rejected data:');
console.log(error);
}).finally(function() {
console.log('-----------全部处理完毕!-----------');
});
// 运行过程
深拷贝
shallow clone 与 deep clone 前者是把一个对象的每个值赋值到一个新对象,新对象与源对象是共用一个内存地址,故改变新对象的下的值,源对象的对应的值也会发生改变。 后者是通过递归解决clone问题,这种方式让新对象与源对象摆脱依赖,缺点是拷贝的速度更慢,代价更大。
function deepClone(source) {
if (!source) {
return source;
}
let target = {};
for (const key in source) {
if (typeof source[key] === 'object') {
target[key] = deepClone(source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
总结
任何事物,透过现象看本质,做到知其然更知所以然,放到javascript中也是一样的。原理性的东西虽然不会让你代码看上去简洁,但是反过来想想,如果你是设计api的人,只提供一个接口文档,别人直接调用,简单方便,但是这个过程你已经帮别人做了大部分的事,总结来说,原理性的东西对于一个人提高代码组织、架构设计能力是一个必备过程。目前自己对这方面也是有很大的欠缺,所以勤能补拙、查漏补缺,尽量提高自己在这方面的能力。谨记:万丈高楼平地起,坚实的地基才是重中之重,大厦华丽的外表只不过是点缀罢了。