1. Javascript继承

1.1 原型链继承

    function Parent() {
this.name = 'zhangsan';
this.children = ['A', 'B', 'C'];
}
Parent.prototype.getName = function() {
console.log(this.name);
} function Child() { }
Child.prototype = new Parent();
var child = new Child();
console.log(child.getName());

[!NOTE]

主要问题:

  1. 引用类型的属性被所有实例共享(this.children.push('name'))
  2. 在创建Child的实例的时候,不能向Parent传参

1.2 借用构造函数(经典继承)

    function Parent(age) {
this.names = ['zhangsan', 'lisi'];
this.age = age; this.getName = function() {
return this.names;
} this.getAge = function() {
return this.age;
}
} function Child(age) {
Parent.call(this, age);
}
var child = new Child(18);
child.names.push('haha');
console.log(child.names); var child2 = new Child(20);
child2.names.push('yaya');
console.log(child2.names);

[!NOTE]

优点:

  1. 避免了引用类型的属性被所有实例共享
  2. 可以直接在Child中向Parent传参

[!DANGER]

缺点:

  • 方法都在构造函数中定义了,每次创建实例都会创建一遍方法

1.3 组合继承(原型链继承和经典继承双剑合璧)

    /**
* 父类构造函数
* @param name
* @constructor
*/
function Parent(name) {
this.name = name;
this.colors = ['red', 'green', 'blue'];
} Parent.prototype.getName = function() {
console.log(this.name);
} // child
function Child(name, age) {
Parent.call(this, name);
this.age = age;
} Child.prototype = new Parent();
// 校正child的构造函数
Child.prototype.constructor = Child; // 创建实例
var child1 = new Child('zhangsan', 18);
child1.colors.push('orange');
console.log(child1.name, child1.age, child1.colors); // zhangsan 18 (4) ["red", "green", "blue", "orange"] var child2 = new Child('lisi', 28);
console.log(child2.name, child2.age, child2.colors); // lisi 28 (3) ["red", "green", "blue"]

[!NOTE]

优点: 融合了原型链继承和构造函数的优点,是Javascript中最常用的继承模式

2. 多种方式实现继承及优缺点总结

2.1 原型式继承

    function createObj(o) {
function F(){};
// 关键:将传入的对象作为创建对象的原型
F.prototype = o;
return new F();
} // test
var person = {
name: 'zhangsan',
friends: ['lisi', 'wangwu']
}
var person1 = createObj(person);
var person2 = createObj(person); person1.name = 'wangdachui';
console.log(person1.name, person2.name); // wangdachui, zhangsan person1.friends.push('songxiaobao');
console.log(person2.friends); // lisi wangwu songxiaobao

[!DANGER]

缺点:

  • 对于引用类型的属性值始终都会共享相应的值,和原型链继承一样

2.2 寄生式继承

    // 创建一个用于封装继承过程的函数,这个函数在内部以某种形式来增强对象
function createObj(o) {
var clone = Object.create(o);
clone.sayName = function() {
console.log('say HelloWorld');
}
return clone;
}

[!DANGER]

缺点:与借用构造函数模式一样,每次创建对象都会创建一遍方法

2.3 寄生组合式继承

2.3.1 基础版本

    function Parent(name) {
this.name = name;
this.colors = ['red', 'green', 'blue'];
} Parent.prototype.getName = function() {
console.log(this, name);
} function Child(name, age) {
Parent.call(this, name);
this.age = age;
} // test1:
// 1. 设置子类实例的时候会调用父类的构造函数
Child.prototype = new Parent();
// 2. 创建子类实例的时候也会调用父类的构造函数
var child1 = new Child('zhangsan', 18); // Parent.call(this, name); // 思考:如何减少父类构造函数的调用次数呢?
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F(); // 思考:下面的这一句话可以吗?
/* 分析:因为此时Child.prototype和Parent.prototype此时指向的是同一个对象,
因此部分数据相当于此时是共享的(引用)。
比如此时增加 Child.prototype.testProp = 1;
同时会影响 Parent.prototype 的属性的。
如果不模拟,直接上 es5 的话应该是下面这样吧
Child.prototype = Object.create(Parent.prototype);*/
Child.prototype = Parent.prototype; // 上面的三句话可以简化为下面的一句话
Child.prototype = Object.create(Parent.prototype); // test2:
var child2 = new Child('lisi', 24);

2.3.2 优化版本

    // 自封装一个继承的方法
function object(o) {
// 下面的三句话实际上就是类似于:var o = Object.create(o.prototype)
function F(){};
F.prototype = o.prototype;
return new F();
} function prototype(child, parent) {
var prototype = object(parent.prototype);
// 维护原型对象prototype里面的constructor属性
prototype.constructor = child;
child.prototype = prototype;
} // 调用的时候
prototype(Child, Parent)

3. JS创建对象的方法

  • 字面量创建
  • 构造函数创建
  • Object.create()
var o1 = {name: 'value'};
var o2 = new Object({name: 'value'}); var M = function() {this.name = 'o3'};
var o3 = new M(); var P = {name: 'o4'};
var o4 = Object.create(P)

4. 原型和原型链

4.1 原型

  1. JavaScript 的所有对象中都包含了一个 __proto__ 内部属性,这个属性所对应的就是该对象的原型
  2. JavaScript 的函数对象,除了原型 __proto__ 之外,还预置了 prototype 属性
  3. 当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 __proto__

4.2 原型链

  1. 任何一个实例对象通过原型链可以找到它对应的原型对象,原型对象上面的实例和方法都是实例所共享的。

  2. 一个对象在查找以一个方法或属性时,他会先在自己的对象上去找,找不到时,他会沿着原型链依次向上查找。

[!NOTE]

注意: 函数才有prototype,实例对象只有有__proto__, 而函数有的__proto__是因为函数是Function的实例对象

4.3 instanceof原理

[!NOTE]

判断实例对象的__proto__属性与构造函数的prototype是不是用一个引用。如果不是,他会沿着对象的__proto__向上查找的,直到顶端Object。

4.4 判断对象是哪个类的直接实例

[!NOTE]

使用对象.construcor直接可判断

4.5 构造函数,new时发生了什么?

   var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
  1. 创建一个新的对象 obj;
  2. 将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
  3. Base函数对象的this指针替换成obj, 相当于执行了Base.call(obj);
  4. 如果构造函数显示的返回一个对象,那么则这个实例为这个返回的对象。 否则返回这个新创建的对象

4.6 类

// 普通写法
function Animal() {
this.name = 'name'
} // ES6
class Animal2 {
constructor () {
this.name = 'name';
}
}

【前端知识体系-JS相关】深入理解JavaScript原型(继承)和原型链的更多相关文章

  1. 【前端知识体系-JS相关】JS基础知识总结

    1 变量类型和计算 1.1 值类型和引用类型的区别? 值类型:每个变量都会存储各自的值.不会相互影响 引用类型:不同变量的指针执行了同一个对象(数组,对象,函数) 1.2 typeof可以及检测的数据 ...

  2. 【前端知识体系-JS相关】深入理解JavaScript异步和单线程

    1. 为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Jav ...

  3. 【前端知识体系-JS相关】对移动端和Hybrid开发的理解?

    1.hybrid是什么,为何使用hybrid呢? 概念: hybrid就是前端和客户端的混合开发 需要前端开发人员和客户端开发人员配合完成 某些环节也可能会涉及到server端 大前端:网页.APP. ...

  4. 【前端知识体系-JS相关】深入理解MVVM和VUE

    1. v-bind和v-model的区别? v-bind用来绑定数据和属性以及表达式,缩写为':' v-model使用在表单中,实现双向数据绑定的,在表单元素外使用不起作用 2. Vue 中三要素的是 ...

  5. 【前端知识体系-JS相关】10分钟搞定JavaScript正则表达式高频考点

    1.正则表达式基础 1.1 创建正则表达式 1.1.1 使用一个正则表达式字面量 const regex = /^[a-zA-Z]+[0-9]*\W?_$/gi; 1.1.2 调用RegExp对象的构 ...

  6. 【前端知识体系-JS相关】你真的了解JavaScript编译解析的流程吗?

    1. JS编译解析的流程 1.1 JS运行分三步 语法分析(通篇扫描是否有语法错误),预编译(发生在函数执行的前一刻),解释执行(一行行执行). 1.2 预编译执行分五步 创建AO对象(Activat ...

  7. 【前端知识体系-JS相关】组件化和React

    1. 说一下使用jQuery和使用框架的区别? 数据和视图的分离,(jQuery数据和视图混在一起,代码耦合)-------开放封闭原则 以数据驱动视图(只关注数据变化,DOM操作被封装) 2.说一下 ...

  8. 【前端知识体系-JS相关】ES6专题系列总结

    1.如何搭建ES6的webpack开发环境? 安装Node环境 node -v // 10.14.1 安装NPM环境 npm -v // 6.4.1 安装babel npm install @babe ...

  9. 【前端知识体系-JS相关】JS-Web-API总结

    2.1 DOM操作 2.1.1 DOM的本质是什么? <!-- DOM树:二叉树 --> /* <?xml version="1.0" encoding=&quo ...

随机推荐

  1. rsync免交互方法

    添加-e "ssh -o StrictHostKeyChecking=no" rsync -avzP -e "ssh -o StrictHostKeyChecking=n ...

  2. 打开excel打印时报“不能使用对象链接和嵌入”

    解决思路: 1.以WIN + R 打开命令行, 在命令行中输入dcomcnfg,打开组件服务. 2.在组件服务窗口中,点击到[控制根节点]->[组件服务]->[计算机]->[我的电脑 ...

  3. 适合初学者的Python爬取链家网教程

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: TinaLY PS:如有需要Python学习资料的小伙伴可以加点击下 ...

  4. LeetCode题解002:两数相加

    两数相加 题目 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字 如果,我们将这两个数相加起来,则会返回一个新的链表 ...

  5. js 时分秒转化为秒

    var time = '00:02:10'; var hour = time.split(':')[0]; var min = time.split(':')[1]; var sec = time.s ...

  6. Dynamics CRM中的操作(action)是否是一个事务(transaction)?

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复168或者20151104可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! 以前的博文 微软Dynamics ...

  7. MySQL数据库(一)索引

    索引的作用是操作数据库时避免全表扫描. 索引的机制 B Tree与B+Tree索引 B(blance) 树可以看作是对2-3查找树的一种扩展,即他允许每个节点有M-1个子节点. 根节点至少有两个子节点 ...

  8. BayaiM__SQLLDR_linux_shell高级版

    BayaiM__SQLLDR_linux_shell高级版   备注:1.因公司在职,商业机密,顾IP地方加了"*"号,你可以任意写一个数字做IP做就好.2.不要瞎BB,哥自己写的 ...

  9. Mysql—配置文件my.ini或my.cnf的详解

    [mysqld] log_bin = mysql-bin binlog_format = mixed expire_logs_days = # 超过7天的binlog删除 slow_query_log ...

  10. [Go] gocron源码阅读-空接口类型interface{}

    gocron源代码中的Action那个地方,就是个空接口类型Action interface{},可以传递任意类型进去,这里是传了个函数进去 command := cli.Command{ Name: ...