当前位置:网站首页>面试官问:JS的继承
面试官问:JS的继承
2022-06-27 23:08:00 【InfoQ】
JSnew、call、apply、this、继承面试官问系列ReactextendsReact.Component// 部分源码
function Component(props, context, updater) {
// ...
}
Component.prototype.setState = function(partialState, callback){
// ...
}
const React = {
Component,
// ...
}
// 使用
class index extends React.Component{
// ...
}
JSES6class构造函数、原型对象和实例之间的关系
function F(){}
var f = new F();
// 构造器
F.prototype.constructor === F; // true
F.__proto__ === Function.prototype; // true
Function.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true
// 实例
f.__proto__ === F.prototype; // true
F.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true

ES6 extends
继承做了什么操作
ES6// ES6
class Parent{
constructor(name){
this.name = name;
}
static sayHello(){
console.log('hello');
}
sayName(){
console.log('my name is ' + this.name);
return this.name;
}
}
class Child extends Parent{
constructor(name, age){
super(name);
this.age = age;
}
sayAge(){
console.log('my age is ' + this.age);
return this.age;
}
}
let parent = new Parent('Parent');
let child = new Child('Child', 18);
console.log('parent: ', parent); // parent: Parent {name: "Parent"}
Parent.sayHello(); // hello
parent.sayName(); // my name is Parent
console.log('child: ', child); // child: Child {name: "Child", age: 18}
Child.sayHello(); // hello
child.sayName(); // my name is Child
child.sayAge(); // my age is 18
// 1、构造器原型链
Child.__proto__ === Parent; // true
Parent.__proto__ === Function.prototype; // true
Function.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true
// 2、实例原型链
child.__proto__ === Child.prototype; // true
Child.prototype.__proto__ === Parent.prototype; // true
Parent.prototype.__proto__ === Object.prototype; // true
Object.prototype.__proto__ === null; // true

ES6 extends- 把子类构造函数(
Child)的原型(__proto__)指向了父类构造函数(Parent),
- 把子类实例
child的原型对象(Child.prototype) 的原型(__proto__)指向了父类parent的原型对象(Parent.prototype)。
- 子类构造函数
Child继承了父类构造函数Parent的里的属性。使用super调用的(ES5则用call或者apply调用传参)。也就是图中用不同颜色标记的两条线。
6.3继承2和3小点第1小点1和2小点__proto____proto__new
、
Object.create
和
Object.setPrototypeOf
可以设置
__proto__
__proto__newnewprototypenewnew
做了什么:
- 创建了一个全新的对象。
- 这个对象会被执行
[[Prototype]](也就是__proto__)链接。
- 生成的新对象会绑定到函数调用的
this。
- 通过
new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
- 如果函数没有返回对象类型
Object(包含Functoin,Array,Date,RegExg,Error),那么new表达式中的函数调用会自动返回这个新的对象。
Object.create
ES5提供的
Object.create(proto, [propertiesObject])undefinedES5MDNployfill// 简版:也正是应用了new会设置__proto__链接的原理。
if(typeof Object.create !== 'function'){
Object.create = function(proto){
function F() {}
F.prototype = proto;
return new F();
}
}
Object.setPrototypeOf
ES6提供的
Object.setPrototypeOfMDNObject.setPrototypeOf()[[Prototype]]nullObject.setPrototypeOf(obj, prototype)`ployfill`
// 仅适用于Chrome和FireFox,在IE中不工作:
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
}
nodejsfunction inherits(ctor, superCtor) {
if (ctor === undefined || ctor === null)
throw new ERR_INVALID_ARG_TYPE('ctor', 'Function', ctor);
if (superCtor === undefined || superCtor === null)
throw new ERR_INVALID_ARG_TYPE('superCtor', 'Function', superCtor);
if (superCtor.prototype === undefined) {
throw new ERR_INVALID_ARG_TYPE('superCtor.prototype',
'Object', superCtor.prototype);
}
Object.defineProperty(ctor, 'super_', {
value: superCtor,
writable: true,
configurable: true
});
Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
}
ES6
的
extends
的
ES5
版本实现
ES6 extends__proto__ES6ES5// ES5 实现ES6 extends的例子
function Parent(name){
this.name = name;
}
Parent.sayHello = function(){
console.log('hello');
}
Parent.prototype.sayName = function(){
console.log('my name is ' + this.name);
return this.name;
}
function Child(name, age){
// 相当于super
Parent.call(this, name);
this.age = age;
}
// new
function object(){
function F() {}
F.prototype = proto;
return new F();
}
function _inherits(Child, Parent){
// Object.create
Child.prototype = Object.create(Parent.prototype);
// __proto__
// Child.prototype.__proto__ = Parent.prototype;
Child.prototype.constructor = Child;
// ES6
// Object.setPrototypeOf(Child, Parent);
// __proto__
Child.__proto__ = Parent;
}
_inherits(Child, Parent);
Child.prototype.sayAge = function(){
console.log('my age is ' + this.age);
return this.age;
}
var parent = new Parent('Parent');
var child = new Child('Child', 18);
console.log('parent: ', parent); // parent: Parent {name: "Parent"}
Parent.sayHello(); // hello
parent.sayName(); // my name is Parent
console.log('child: ', child); // child: Child {name: "Child", age: 18}
Child.sayHello(); // hello
child.sayName(); // my name is Child
child.sayAge(); // my age is 18
ES6的例子babeljsES5// 对转换后的代码进行了简要的注释
"use strict";
// 主要是对当前环境支持Symbol和不支持Symbol的typeof处理
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
// _possibleConstructorReturn 判断Parent。call(this, name)函数返回值 是否为null或者函数或者对象。
function _possibleConstructorReturn(self, call) {
if (call && (_typeof(call) === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
// 如何 self 是void 0 (undefined) 则报错
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
// 获取__proto__
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
// 寄生组合式继承的核心
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
// Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
// 也就是说执行后 subClass.prototype.__proto__ === superClass.prototype; 这条语句为true
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
// 设置__proto__
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
// instanceof操作符包含对Symbol的处理
function _instanceof(left, right) {
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
return right[Symbol.hasInstance](left);
} else {
return left instanceof right;
}
}
function _classCallCheck(instance, Constructor) {
if (!_instanceof(instance, Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
// 按照它们的属性描述符 把方法和静态属性赋值到构造函数的prototype和构造器函数上
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
// 把方法和静态属性赋值到构造函数的prototype和构造器函数上
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
// ES6
var Parent = function () {
function Parent(name) {
_classCallCheck(this, Parent);
this.name = name;
}
_createClass(Parent, [{
key: "sayName",
value: function sayName() {
console.log('my name is ' + this.name);
return this.name;
}
}], [{
key: "sayHello",
value: function sayHello() {
console.log('hello');
}
}]);
return Parent;
}();
var Child = function (_Parent) {
_inherits(Child, _Parent);
function Child(name, age) {
var _this;
_classCallCheck(this, Child);
// Child.__proto__ => Parent
// 所以也就是相当于Parent.call(this, name); 是super(name)的一种转换
// _possibleConstructorReturn 判断Parent.call(this, name)函数返回值 是否为null或者函数或者对象。
_this = _possibleConstructorReturn(this, _getPrototypeOf(Child).call(this, name));
_this.age = age;
return _this;
}
_createClass(Child, [{
key: "sayAge",
value: function sayAge() {
console.log('my age is ' + this.age);
return this.age;
}
}]);
return Child;
}(Parent);
var parent = new Parent('Parent');
var child = new Child('Child', 18);
console.log('parent: ', parent); // parent: Parent {name: "Parent"}
Parent.sayHello(); // hello
parent.sayName(); // my name is Parent
console.log('child: ', child); // child: Child {name: "Child", age: 18}
Child.sayHello(); // hello
child.sayName(); // my name is Child
child.sayAge(); // my age is 18
pdf推荐阅读JS继承相关的书籍章节
githubdemoES6JavaScriptJavaScriptES6中的class总结
- 子类构造函数的
__proto__指向父类构造器,继承父类的静态方法。
- 子类构造函数的
prototype的__proto__指向父类构造器的prototype,继承父类的方法。
- 子类构造器里调用父类构造器,继承父类的属性。行文到此,文章就基本写完了。文章代码和图片等资源放在这里github inhert和
demo展示es6-extends,结合console、source面板查看更佳。
边栏推荐
- 章凡:飞猪基于因果推断技术的广告投后归因
- Alchemy (2): why use issue management software
- 现在网上开股票账户安全吗?选择上市券商,最快8分钟开户成功
- Deepmind | pre training of molecular property prediction through noise removal
- 去哪儿网(Qunar) DevOps 实践分享
- FB、WhatsApp群发消息在2022年到底有多热门?
- . Mp4 video test address
- The flutter slivereappbar is fully parsed. All the effects you want are here!
- plot_model报错:没有安装pydot, graphviz
- 独立站卖家都在用的五大电子邮件营销技巧,你知道吗?
猜你喜欢

Esxi based black Qunhui DSM 7.0.1 installation of VMware Tools
最新MySQL高级SQL语句大全

Cloud assisted privacy collection intersection (server assisted psi) protocol introduction: Learning

深入解析kubernetes controller-runtime

单晶炉导电滑环的应用范围和作用是什么

FB、WhatsApp群发消息在2022年到底有多热门?
![Software engineering job design (1): [personal project] implements a log view page](/img/95/0c3f0dde16d220ddecb5758a4c31e7.png)
Software engineering job design (1): [personal project] implements a log view page

. Mp4 video test address

Leetcode 720. 词典中最长的单词(为啥感觉这道题很难?)

Redis主从复制、哨兵模式、集群的概述与搭建
随机推荐
Taro--- day1--- construction project
打新债注册账户安全吗,会有风险吗?
Redis configuration and optimization of NoSQL
哪个证券炒股开户佣金是最便宜,最安全的
独立站卖家都在用的五大电子邮件营销技巧,你知道吗?
SPuG - lightweight automatic operation and maintenance platform
单晶炉导电滑环的应用范围和作用是什么
Alchemy (7): how to solve problems? Only reconstruction
Is it safe to open an account for mobile stocks? Where can I open an account for buying stocks?
LabVIEW连续采样与有限采样模式
[DNS resolution] set the name DNSPod resolution for domain name access of COM
网页鼠标点击特效案例收集(直播间红心同理)
Informatics Olympiad all in one 1359: enclosed area
Golang monkeys eat peaches and ask for the number of peaches on the first day
券商买股票用什么app是比较好的,比较安全的
剑指 Offer 65. 不用加减乘除做加法
Squid代理服务器(缓存加速之Web缓存层)
SQL Server 2016 detailed installation tutorial (with registration code and resources)
The flutter slivereappbar is fully parsed. All the effects you want are here!
【DNS 解析】将Name.com的域名接入DNSPod解析