FE-DSHUI / DSHUI

前端王者小分队读书会
4 stars 1 forks source link

《你不知道的JavaScript(上卷)》-原型相关知识(2)-2021-3-1 #57

Open AwakenedSomeone opened 3 years ago

AwakenedSomeone commented 3 years ago

这里记一下原型继承相关的知识点:

  1. js中的原型继承和其他语言中的继承不一样,其他的继承是通过复制一份父类实现的,js不是,js是通过关联对象之间的关系,也就是prototype属性来实现的。所以准确的说是一种委托机制。
  2. 我们有两种方法实现两个对象的关联: Object.create 和 new操作符。
  3. 绝大多数浏览器支持一种非标准的访问[[prototype]]的方法,通过proto拿到。比如:
    function Foo () {
    console.log(2)
    }
    var a = Object.create(Foo)
    a.__proto__ === Foo // true
    var b = new Foo()
    b.__proto__ === Foo.prototype // true

    从上面的例子我们可以看出来。Object.create和new的实现方式有很大不同,create创建出来的对象a,a.proto指向了Foo,而new 出来的对象b,b.proto 指向的是prototype。 我们来分析一下原因:先来看看Object.create的polyfill代码:

    if (!Object.create) { 
    Object.create = function(o) {
        function F(){}
        F.prototype = o;
       return new F(); 
    };
    }

    从这段代码可以看出来,create函数比new 多做了一个操作,那就是先将F.prototype关联到了传入的对象上,也就是上例的Foo,然后再返回了 new F()的实例。因为a.proto === F.prototype (下面说new的时候会说到), 而F.prototype 又在create内部指向了o(即是Foo),所以a.proto=== Foo 为true。 再来分析一下new Foo(),熟悉new这个过程的小伙伴知道: ①创建一个空对象 obj。 ②让空对象obj.proto指向Foo.prototype。 ③将Foo的执行上下文绑定到obj上,并存起来result。 ④如果Foo是一个对象,则返回result,如果不是则返回新创建的这个对象obj。 从这个流程可以看到,new执行构造函数调用的过程中,将返回的对象的proto指向了Foo的prototype上,这就是为啥上一个例子中:b.proto === Foo.prototype, 而a.proto === F.prototype 进而推导出a.proto === Foo. 4.委托机制: 由于原型链的存在,让我们可以查找到部署以当前对象,但是属于原型链上的方法或者属性,这样的行为可以称为行为委托,将方法或者属性委托到了原型上。

isbaselvy commented 3 years ago

今天刚好看到一个东西,可用用上对应的 用代码模拟new的过程,首先还是步骤:new调用函数过程中到底发生了什么

用代码来实现一个new

function Constructor(fn, args) {
    // fn的prototype属性内容作为新对象的原型内容
    var _this = Object.create(fn.prototype);
    var res = fn.apply(_this, args);
    return res ? res : _this;
}

接下来用上述知识验证

function Foo() {
    console.log(2)
}
var a = Object.create(Foo)
console.log('a.__proto__ === Foo:', a.__proto__ === Foo) // true
var b = new Foo()
console.log('b.__proto__ === Foo.prototype:', b.__proto__ === Foo.prototype) // true
// 调用自定义得new
var d = Constructor(Foo)
console.log('d.__proto__ === Foo.prototype:', d.__proto__ === Foo.prototype) // true