网站首页 > 技术文章 正文
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]
主要问题:
- 引用类型的属性被所有实例共享(this.children.push(‘name’))
- 在创建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]
优点:
- 避免了引用类型的属性被所有实例共享
- 可以直接在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 原型
- JavaScript 的所有对象中都包含了一个 __proto__ 内部属性,这个属性所对应的就是该对象的原型
- JavaScript 的函数对象,除了原型 __proto__ 之外,还预置了 prototype 属性
- 当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 __proto__。
4.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);
- 创建一个新的对象 obj;
- 将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
- Base函数对象的this指针替换成obj, 相当于执行了Base.call(obj);
- 如果构造函数显示的返回一个对象,那么则这个实例为这个返回的对象。 否则返回这个新创建的对象
4.6 类
// 普通写法 function Animal() { this.name = 'name' } // ES6 class Animal2 { constructor () { this.name = 'name'; } }
喜欢小编的可以点个赞关注小编哦,小编每天都会给大家分享文章。
我自己是一名从事了多年的前端老程序员,小编为大家准备了新出的前端编程学习资料,免费分享给大家!
如果你也想学习前端,那么帮忙转发一下然后再关注小编后私信【1】可以得到我整理的这些前端资料了(私信方法:点击我头像进我主页有个上面有个私信按钮)
猜你喜欢
- 2024-11-10 这样理解 JS 原型链,通透 js原型链的理解
- 2024-11-10 JavaScript-原型链 javascript 原型,原型链 ? 有什么特点?
- 2024-11-10 javascript原型链 js原型链的用处
- 2024-11-10 js 原型/原型链/构造函数/实例/继承
- 2024-11-10 【JavaScript 高级】深入了解原型链
- 2024-11-10 快速读懂JavaScript中的原型链 js的原型和原型链是什么
- 2024-11-10 你可能不太理解的JavaScript - 原型与原型链
- 2024-11-10 我在jacascript中学习到的那些原型链,你知道吗?
- 2024-11-10 JavaScript中的原型prototype和__proto__的区别及原型链概念
- 2024-11-10 面试问题分享 - 5:解释一下 原型、构造函、实例、原型链 之间的关系
- 标签列表
-
- content-disposition (47)
- nth-child (56)
- math.pow (44)
- 原型和原型链 (63)
- canvas mdn (36)
- css @media (49)
- promise mdn (39)
- readasdataurl (52)
- if-modified-since (49)
- css ::after (50)
- border-image-slice (40)
- flex mdn (37)
- .join (41)
- function.apply (60)
- input type number (64)
- weakmap (62)
- js arguments (45)
- js delete方法 (61)
- blob type (44)
- math.max.apply (51)
- js (44)
- firefox 3 (47)
- cssbox-sizing (52)
- js删除 (49)
- js for continue (56)
- 最新留言
-