Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

「评论」前端面试中常考的源码实现 #57

Open
dongyuanxin opened this issue Jun 10, 2019 · 8 comments
Open

「评论」前端面试中常考的源码实现 #57

dongyuanxin opened this issue Jun 10, 2019 · 8 comments

Comments

@dongyuanxin
Copy link
Owner

dongyuanxin commented Jun 10, 2019

前端面试中常考的源码实现:https://xin-tan.com/passages/2019-03-18-interview-js-code/

@purain
Copy link

purain commented Jun 14, 2019

手动实现 call 的函数中使用了 context 的 fn 属性,如果传入的参数 context 中本来就有 fn 属性且调用函数 test 中使用到 fn 的话怕是会出错。比如
function test(arg1, arg2){
console.log(arg1,arg2);
console.log(this.a, this.fn);
}
test.call2({
a: 'a',
fn: 'b'
}, 1, 2);

@purain
Copy link

purain commented Jun 14, 2019

关于深拷贝那段,我在网上看到很多下面的代码,但是我不知道哪里有坑,用了楼主的示例结果也没问题。
function deepCopy(obj){
let result = Array.isArray(obj) ? [] : {};
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] === 'object'){
result[key] = deepCopy(obj[key]);
}else{
result[key] = obj[key];
}
}
}
return result;
}

@dongyuanxin
Copy link
Owner Author

dongyuanxin commented Jun 14, 2019

@purain
手动实现 call 的函数中使用了 context 的 fn 属性,如果传入的参数 context 中本来就有 fn 属性且调用函数 test 中使用到 fn 的话怕是会出错。比如
function test(arg1, arg2){
console.log(arg1,arg2);
console.log(this.a, this.fn);
}
test.call2({
a: 'a',
fn: 'b'
}, 1, 2);

这里确实有问题,输出是:

1 2
a function test(arg1, arg2){
  console.log(arg1,arg2);
  console.log(this.a, this.fn);
  }

原因在于手动实现的call修改了上下文fn,进入函数打印,此时fn不再是b,而是函数本身。目前没有好的办法,可以将call2fn字段换成更不常用的__fn__,或者使用es6的Symbol语法。

修正版:

Function.prototype.call2 = function(context) {
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  context = context || window;
  const fn = Symbol('fn');
  context[fn] = this;

  const args = [...arguments].slice(1);
  const result = context[fn](...args);  
  delete context[fn];
  return result;
};

@dongyuanxin
Copy link
Owner Author

它的没问题,而且实现的比我的精简多了。不过同样没考虑“循环引用”的问题。

@purain
关于深拷贝那段,我在网上看到很多下面的代码,但是我不知道哪里有坑,用了楼主的示例结果也没问题。
function deepCopy(obj){
let result = Array.isArray(obj) ? [] : {};
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] === 'object'){
result[key] = deepCopy(obj[key]);
}else{
result[key] = obj[key];
}
}
}
return result;
}

@yanxj0
Copy link

yanxj0 commented Aug 23, 2019

//deepClone
typeof null === 'object'  //true

@zhou-z-xin
Copy link

//deepClone
typeof null === 'object'  //true

如果obj[key] = null的话, obj[key] && typeof obj[key] === 'object 为false

@kingyaroglek
Copy link

kingyaroglek commented Dec 25, 2019

实现call/apply方法还是有一些不足的。给context添加额外属性会造成调用方法时,如果涉及到例如console.log(this)操作会输出额外属性。我查到的方法是将函数转换成字符串, 并将其中的this替换为context,然后使用eval方法转换成新函数。但是这样又涉及到使用正则判断this串是否为变量this,以及闭包外层变量被引用或context与闭包内变量重名问题。较难实现。

另外Function.prototype.call的参数1,若为空,nullundefined,则绑定上下文至Window。若为基本类型例如1,则绑定至new Number(1),这里的context赋值我是用

context = arguments[0] instanceof Object ? arguments[0] : new arguments[0].__proto__.constructor(arguments[0]);

来实现的。

@xdliyushen
Copy link

使用 ES5 实现的双向绑定有点小问题。功能上完全可以, 但是obj可以直接定义一个空对象。
get函数也有点小问题, value 没有定义, 这样的话想要访问 obj.value 的时候是会报错的。并且 get 与 set 一般都是用来创建伪属性的, 最好不要直接设置在真实属性上。
另外在 set 中, 不需要再去改变 input 的值了, 因为在输入的时候 input 的值就改变过了。
建议改成如下代码:

const obj = {};

// ...

Object.defineProperty(obj, 'value', {
            get: () => {
                return document.querySelector('input').value;
            },
            set: (newValue) => {
                document.querySelector("#value").innerHTML = newValue;
            }
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants