就面试笔试题的一些笔记:
- 闭包( 实现add(2)(5) )
- 深复制和浅复制
- 原生js实现Promise
△ –>闭包知识:
实现add(2)(5)
function add (x) {
return function(y) { return x + y; };
}
△ –>深复制和浅复制:
深拷贝 与 浅拷贝: 循环引用和函数是不能通过 stringify 进行深拷贝的
- 对于循环引用和函数是无法通过stringify和parse的方法进行深拷贝的,关于循环引用,可以通过查找循环点来断掉这个循环,再进行深拷贝。
遇到的问题 :
* 解决数组浅拷贝的问题:
直接等于 = arr1=arr2;
slice和concat方法可以进行简单素组的深拷贝
由于数组内部属性值为引用对象,因此使用slice和concat对对象数组的拷贝,整个拷贝还是浅拷贝,拷贝之后数组各个值的指针还是指向相同的存储地址。
因此,slice和concat这两个方法,仅适用于对不包含引用对象的一维数组的深拷贝
解决数组深拷贝的问题:
也是通过 stringify 和 parse 的方法进行深拷贝,解决深拷贝的问题:
先把数据进行stringify转换 ,再进行一次parse转换。
JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串
JSON.parse() 方法解析JSON格式数据并构造一个由字符串描述的JavaScript对象/值总结:
- 浅拷贝相当于引用地址的复制,两个变量指针是共享(引用)同一个对象。obj1 === obj2
- 深拷贝相当于为另外一个对象开辟内存空间,并进行递归复制内部属性。两个对象的引用地址是不一样的(即不是引用同一个对象)。obj1 !== obj2
- 可以通过”赋值操作符”、Object.assign()、数组遍历赋值等实现浅拷贝。
- 可以通过自定义代码、JSON对象的方法(JSON.parse和JSON.stringify)、JQuery.extend()等实现深拷贝。
- 目前来说,并没有统一的标准方法来解决”循环引用”,从而实现真正的深拷贝。
比如 react 里面有大量的对象复制,用 immutable 就很好。
对付 deep clone, 最好的办法是抛弃需要 deep clone 的代码实际开发中 除了通过 stringify 和 parse 的方法进行深拷贝,
eg:
let item = JSON.parse(JSON.stringify(temp));
item[‘recharge_principal’] = FormatMoneyByM(temp[‘recharge_principal’]);
为此还采用了其他方式对数据做了处理,
为了避免改变数据的值,直接将通过格式化函数后,加入数组中。不采用中间变量来传递值。
eg:
let temp = data.list [ key ] || { } ;
principal_arr.push ( CalculateMoneyByMm ( temp[ ’ principa l’ ] || 0 ) );
△ –> 用原生js实现promise:
ES6中Promise可以说很大情况下改善了异步回调的嵌套问题
第一:Promise构造函数接受一个函数作为参数,函数里面有两个参数resolve和reject分别作为执行成功或者执行失败的函数
var promise=new Promsie(function(resolve,rejec){
if(/*异步执行成功*/){
resolve(value);
}else{
reject(error);
}
})
第二:可以通过then设置操作成功之后的操作,接受两个函数作为参数
.then(function(){
//回调执行成功之后的操作
},function(){
//回调执行失败之后的操作,可以没有
});
Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected
function Promise(){
this.status='pending'; //待定
this.msg='';
var process=arguments[0];
var that=this;
process(function(){
that.status='resolve';
that.msg=arguments[0];
},function(){
that.status='reject';
that.msg=arguments[0];
});
return this;
}
Promise.prototype.then=function(){
if(this.status=='resolve'){
arguments[0](this.msg);
}
if(this.status=='reject '&& arguments[1]){
arguments[1](this.msg);
}
}
//测试
var promise =new Promise(function(resolve,reject){
resolve('success!!!');
});
promise.then(function(success){
console.log('success');
},function(){
console.log('failed');
});
以上只是最基本的实现,在代码结构结构和容错方面没有进行考虑。
Promise对象的缺点:
1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
3、当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
/* 我们要满足状态只能三种状态:PENDING,FULFILLED,REJECTED三种状态,
且状态只能由PENDING=>FULFILLED,或者PENDING=>REJECTED */
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
/* value状态为执行成功事件的入参,deferreds保存着状态改变之后的需要处理的函数以及promise子节点,
构造函数里面应该包含这三个属性的初始化 */
function Promise(callback) {
this.status = PENDING;
this.value = null;
this.defferd = [];
setTimeout(callback.bind(this, this.resolve.bind(this), this.reject.bind(this)), 0);
}
Promise.prototype = {
constructor: Promise,
//触发改变promise状态到FULFILLED
resolve: function (result) {
this.status = FULFILLED;
this.value = result;
this.done();
},
//触发改变promise状态到REJECTED
reject: function (error) {
this.status = REJECTED;
this.value = error;
},
//处理defferd
handle: function (fn) {
if (!fn) {
return;
}
var value = this.value;
var t = this.status;
var p;
if (t == PENDING) {
this.defferd.push(fn);
} else {
if (t == FULFILLED && typeof fn.onfulfiled == 'function') {
p = fn.onfulfiled(value);
}
if (t == REJECTED && typeof fn.onrejected == 'function') {
p = fn.onrejected(value);
}
var promise = fn.promise;
if (promise) {
if (p && p.constructor == Promise) {
p.defferd = promise.defferd;
} else {
p = this;
p.defferd = promise.defferd;
this.done();
}
}
}
},
//触发promise defferd里面需要执行的函数
done: function () {
var status = this.status;
if (status == PENDING) {
return;
}
var defferd = this.defferd;
for (var i = 0; i < defferd.length; i++) {
this.handle(defferd[i]);
}
},
/*储存then函数里面的事件
返回promise对象
defferd函数当前promise对象里面
*/
then: function (success, fail) {
var o = {
onfulfiled: success,
onrejected: fail
};
var status = this.status;
o.promise = new this.constructor(function () {
});
if (status == PENDING) {
this.defferd.push(o);
} else if (status == FULFILLED || status == REJECTED) {
this.handle(o);
}
return o.promise;
}
};