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';
}
}

最新文章

  1. sublime text 3 配置php开发环境
  2. PBX220 测评一
  3. ios8版本地图定位注意点
  4. STM32 (战舰)
  5. 我所理解的JavaScript闭包
  6. IOS基础之 (四) OC对象
  7. python三种数据库连接池方式
  8. javascript三种创建对象的方式
  9. poj2752Seek the Name, Seek the Fame
  10. 初探 discuz
  11. 中软卓越IT培训:给IT程序员的18个忠告
  12. 看完48秒动画,让你不敢再登录HTTP网站(附完整示例代码)
  13. 判断字符串中是否包含指定的内容&&字符串截取方法比较说明
  14. Android Notification setLatestEventInfo方法已废弃
  15. javaScript(7)---函数
  16. .NET MVC全局异常处理(一)
  17. Javascript高级编程学习笔记(70)—— 事件(14)内存和性能
  18. ES5-ES6-ES7_class类
  19. python主流测试框架的简介
  20. Git分支操作——查看、新建、删除、提交、合并

热门文章

  1. Linux 安装 MySQL 出现 Could NOT find Curses
  2. virtualbox FAIL(0x80004005) VirtualBox VT-x is not available (VERR_VMX_NO_VMX)
  3. Docker - 快速入门(一)
  4. Spring Cloud Alibaba基础教程:Sentinel Dashboard同步Apollo存储规则
  5. 易优CMS:arcview的基础用法
  6. Vue笔记--通过自定义指令实现按钮操作权限
  7. JavaScript之找LHS查询和RHS查询
  8. IOS疯狂基础之屏幕旋转控制,获得当前方向(转)
  9. Python的4个内置数据结构
  10. linux权限管理-特殊权限