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. 教妹学 Java:难以驾驭的多线程

    00.故事的起源 “二哥,上一篇<集合>的反响效果怎么样啊?”三妹对她提议的<教妹学 Java>专栏很关心. “这篇文章的浏览量要比第一篇<泛型>好得多.” “这是 ...

  2. Spring Security 教程 大牛的教程

    https://www.iteye.com/blog/elim-2247073 Spring Security 教程 Spring Security(20)——整合Cas Spring Securit ...

  3. 屏幕输入转换为int//方法大注释

    可以使用两种方法: using System; namespace 方法测试 { class Program { static void Main(string[] args) { Console.W ...

  4. MySQL学习——操作自定义函数

    MySQL学习——操作自定义函数 摘要:本文主要学习了使用DDL语句操作自定义函数的方法. 了解自定义函数 是什么 自定义函数是一种与存储过程十分相似的过程式数据库对象.它与存储过程一样,都是由SQL ...

  5. Implement Custom Business Classes and Reference Properties 实现自定义业务类和引用属性(XPO)

    In this lesson, you will learn how to implement business classes from scratch. For this purpose, the ...

  6. v8js-在PHP中运行javascript代码

    起因之前写自动登录操作一个网站的PHP脚本,但是发现该网站用js代码做了cookie的计算和验证,所以使用了v8js. 安装安装v8.(Mac:brew install v8)使用pecl insta ...

  7. 证券secuerity英语secuerity安全

    中文名:证券 外文名:security.secuerity 类别:经济权益凭证统称 组成:资本证券.货币证券和商品证券 作用:用来证明持者权益的法律凭证 图集 目录 1 发展历程 ? 世界 ? 中国 ...

  8. Wireshark使用技巧:提取VOIP通话中的音频流

    "Wireshark的RTP流分析功能实战." 在VOIP协议的分析过程中,常常会遇到一些标准协议承载的语音传输,如以SIP.H.323为控制协商协议,RTP为语音数据协议的VOI ...

  9. 微信小程序json与xml互相转换

    1.首先在目录结构中引入必要的js文件 https://files.cnblogs.com/files/qianyou304/x2j.rar 2.js中代码如下:(部分)json 2 xml var ...

  10. 微信小程序底部导航栏(tabbar)

    在app.json处设置“tabBar”,例子如下: { "pages": [ "pages/index/index", "pages/pages1/ ...