贵州建设项目门户网站,社交模板网站建设,建设一个网站需要用到几个语言,wordpress本地 域名绑定简述 JavaScript 中 prototype
这篇笔记主要捋一下这么几个概念#xff1a;
JS 的继承构造函数new 的作用及简易实现__proto__ prototype同样的方法#xff0c;class 和 prototype 中分别是怎么实现的
基础概念
JS 是通过 prototype chaining 实现继承的语言#…简述 JavaScript 中 prototype
这篇笔记主要捋一下这么几个概念
JS 的继承构造函数new 的作用及简易实现__proto__ prototype同样的方法class 和 prototype 中分别是怎么实现的
基础概念
JS 是通过 prototype chaining 实现继承的语言所有的基类都会绑定在 prototype chain 上如
class Base {constructor() {}
}class Extended extends Base {constructor() {super();}
}class Descendant extends Extended {constructor() {super();}
}const descedant new Descendant();
console.log(descedant.__proto__);__proto__ 本身就暴露了当前对象的 [[Prototype]]它所指向的是另一个对象也就是 prototype chain 上的继承 (粗暴的理解一下就是父类)。返回的对象又可以通过调用 __proto__ 继续获得父类的 [[Prototype]]一步步向上追溯一直到 [[Prototype]] 为 null 为止一般到这个时候也是获取到 Object 了——JS 之中除了 primitive type万物皆对象。
需要注意的是__proto__ 返回的对象是 [[Prototype]] 也是 prototype二者是一样的只不过前者是 chrome 的称呼后者是 Firefox 的这里为了一致就使用 [[Prototype]]。获取当前 [[Prototype]] 的方法有两种 __proto__ 已经 Deprecated 了deno 中甚至不支持实现 Object.getPrototypeOf()/Reflect.getPrototypeOf() 推荐使用这个函数
构造函数
class 是 ES6 新出的语法糖在 ES6 之前都是使用构造函数去实现的如
function Person(name, age) {this.name name;this.age age;
}// equivalent to
class Person {constructor(name, age) {this.name name;this.age age;}
}实现结果都是一致的 同样constructor 也不是一定需要大写小写也是可以实现同样的功能
function person3(name, age) {this.name name;this.age age;
}const person3Instance new person3(Deborah, 99);
console.log(person3Instance);大写只是一个约定俗成的规范。
new 关键字
new 在使用构造函数的时候是必须的否则它只是返回了一个 undefined:
function Person(name, age) {this.name name;this.age age;this.greet function () {console.log(Hi there);};
}const person Person(Tylor, 26);
console.log(person);
person.greet();new 的作用在于
它创建了一个新的对象它关联了对应的原型链继承它绑定了 this 的指向它执行了构造函数内的部分
一个简单的实现 new 的函数为
function myNew(constructorFn, ...args) {// 创建一个新的对象const obj {};// 关联对应的原型链继承Object.setPrototypeOf(obj, constructorFn.prototype);// 执行了构造函数同时使用 apply 也确定了 this 的指向const res constructorFn.apply(obj, args);return typeof res object res ! null ? res : obj;
}__proto__ 和 prototype 的区别
简单的说就是__proto__ 作用于实例上而 prototype 作用于构造函数上。
如准确的说函数的实现不是像上面那样实现的而是
Person.prototype.greet function () {console.log(Hi there, I am ${this.name},and I am ${this.age} years old);
};从自动提示上也可以看到实例化的对象是无法访问内部的 [[Prototype]] 的 另外所有的函数实现其实都是绑定在 prototype 上的 主要的原因就是因为函数本质上也是对象而在每次实例化的时候都创建一个新的对象是一个非常昂贵的事情。因此 JS 会将函数绑定到 [[Prototype]] 上这样所有的实例化的对象可以共享一个函数。
如果想要每次实例化的时候都创建一个新的函数则可以使用 arrow function在 class 中使用这也是 ES6 语法的 pro and con 了。
super 与 this
到这一步基本上使用 prototype 去实现 class 都实现的差不多了除了继承这一部分以下面代码为例
class Parent {constructor() {this.name parent;}greet() {console.log(This is ${this.name});}
}class Child extends Parent {constructor() {this.name Child;}greet() {}
}const child new Child();事实上 JS 会报错 在当调用了 super 之后就会发现this 的指向被绑定到了 Child 中
class Parent {constructor() {this.name parent;}greet() {console.log(This is ${this.name});}
}class Child extends Parent {constructor() {super();this.name Child;}greet() {super.greet();}
}const child new Child();
child.greet();接下来要模拟实现的就是这一步其中需要注意的就是 实现继承关系 这点可以通过修改 prototype 进行实现已知 [[Prototype]] 中包含了所有的 prototype chain这里也只需要将 Child.prototype 指向 Parent.prototype并且绑定对应的 构造函数即可。 修改 this 的指向
function Parent() {this.name Parent;
}Parent.prototype.greet function () {console.log(This is ${this.name});
};function Child() {// bind child to parentParent.call(this);this.name Child;
}// set up inheritance
Child.prototype Object.create(Parent.prototype);
Child.prototype.constructor Child;Child.prototype.greet function () {Parent.prototype.greet.call(this);
};const child new Child();
child.greet();这样prototype 中的继承关系也实现了。
这也是为什么 JS 推荐使用 class 而非重新实现一个 prototype 的原因主要还是因为使用 class 的代码更加简洁易读。