一步步学习javascript基础篇(5):面向对象设计之对象继承(原型链继承)

上一篇介绍了对象创建的几种基本方式,今天我们看分析下对象的继承。

一、原型链继承

1.通过设置prototype指向“父类”的实例来实现继承。

function Obj1() {
    this.name1 = "张三";
}
function Obj2() {
}
Obj2.prototype = new Obj1();
var t2 = new Obj2();
alert(t2.name1);

这里有个明显的缺点就是:(如果父类的属性是引用类型,那么我们在对象实例修改属性的时候会把原型中的属性修改,这样会在每个实例对象中改变数据,而这不是我们想要的效果)

function Obj1() {
    this.arr = ["张三"];
}
function Obj2() {
}
Obj2.prototype = new Obj1();
var t2 = new Obj2();
alert(t2.arr);//打印“张三”
t2.arr[t2.arr.length] = "李四";
var t1 = new Obj2();
alert(t1.arr);//打印“张三,李四”

例:

function Obj1() {
this.arr = ["张三"];
}
function Obj2() {
}
Obj2.prototype = new Obj1();
var t2 = new Obj2();
alert(t2.arr);//打印“张三”
t2.arr[t2.arr.length] = "李四";
var t1 = new Obj2();
alert(t1.arr);//打印“张三,李四”

那我们怎样规避这种问题呢?接着往下看。

2. 利用构造函数来实现继承

function Obj1() {
    this.arr = ["张三"];
}
function Obj2() {
    Obj1.call(this);//【1.新增】
}
//Obj2.prototype = new Obj1();【2.注释这行】
var t2 = new Obj2();
alert(t2.arr);//打印“张三”
t2.arr[t2.arr.length] = "李四";
var t1 = new Obj2();
alert(t1.arr);//打印“张三,李四”

我们看到上面代码,就注释了一行,新增了以后。打印出来的效果完全不一样了。现在的arr属性是每个实例对象独有的了。(之前是定义到原型上的,而原型的属性对每个实例都是共享的)

例:

function Obj1() {
this.arr = ["张三"];
}
function Obj2() {
Obj1.call(this);//【1.新增】
}
//Obj2.prototype = new Obj1();【2.注释这行】
var t2 = new Obj2();
alert(t2.arr);//打印“张三”
t2.arr[t2.arr.length] = "李四";
var t1 = new Obj2();
alert(t1.arr);//打印“张三,李四”

同样,单纯的这种方式也是有问题的。因为我们这样就无法继承对象的方法了。如:

function Obj1() {
    this.arr = ["张三"];
}
Obj1.prototype.sayHi = function () { alert(this.arr); }////【1.新增】
function Obj2() {
    Obj1.call(this);
}
var t2 = new Obj2();
//t2里面是没有sayHi方法的

我们可以使用原型和构造的混用来解决,如下:

3.通过原型和构造来实现继承

function Obj1() {
    this.arr = ["张三"];
}
Obj1.prototype.sayHi = function () { alert(this.arr); }
function Obj2() {
    Obj1.call(this);
}
Obj2.prototype = new Obj1();//【1.新增】
var t2 = new Obj2();
t2.sayHi();

如上,通过构造函数中的  Obj1.call(this); 和设置原型属性 Obj2.prototype = new Obj1(); 结合使用,完美解决问题。

这里需要注意一个地方,如果把 Obj2.prototype = new Obj1(); 改成 Obj2.prototype = Obj1.prototype ; 的话,会有你想不到的问题。如:

function Obj1() {
    this.arr = ["张三"];
}
Obj1.prototype.sayHi = function () { alert(this.arr); }
function Obj2() {
    Obj1.call(this);
}
Obj2.prototype = Obj1.prototype;//【1.新增】
var t2 = new Obj2();
t2.constructor.prototype.sayHi = function () { alert("test") };//修改Obj2中的原型的方法
var t1 = new Obj1();
t1.sayHi();
//影响到了Obj1中的原型的方法。因为 Obj2.prototype = Obj1.prototype;让两个对象的原型指向了同一处。
//所以还是只能用Obj2.prototype = new Obj1();

例:

function Obj1() {
this.arr = ["张三"];
}
Obj1.prototype.sayHi = function () { alert(this.arr); }
function Obj2() {
Obj1.call(this);
}
Obj2.prototype = Obj1.prototype;//【1.新增】
var t2 = new Obj2();
t2.constructor.prototype.sayHi = function () { alert("test") };//修改Obj2中的原型的方法
var t1 = new Obj1();
t1.sayHi();

4.什么是原型链

如:

//*************Obj1****
function Obj1() {
    this.arr = ["张三"];
}
Obj1.prototype.sayHi = function () { alert(this.arr); }

//*************Obj2****
function Obj2() {
    Obj1.call(this);
    this.name = "张三";
}
Obj2.prototype = new Obj1();
Obj2.prototype.sayHi2 = function () { alert(this.name); };

//*************Obj3****
function Obj3() {
    Obj2.call(this);
}
Obj3.prototype = new Obj2();
Obj3.prototype.sayHi3 = function () { };

//*******************
var t3 = new Obj3();
t3.sayHi();

Obj3继承Obj2,Obj2继承Obj1。我们的Obj3的实例对象访问sayHi的时候,会先去Obj3的实例对象中找sayHi方法(没找到),然后去Obj3的原型中找(没找到),然后去父类Obj2的原型中找(没找到),然后去Obj1的原型中找(找到了)。这个找的路径就是原型链。

这是学习记录,不是教程。文中错误难免,您可以指出错误,但请不要言辞刻薄。

原文链接:http://haojima.net/zhaopei/517.html

本文已同步至目录索引:一步步学习javascript

欢迎上海“程序猿/媛”、"攻城狮"入群:【沪猿】229082941 入群须知

欢迎对个人博客感兴趣的道友加入群:【嗨-博客】469075305 入群须知

如果您觉得文章对您有那么一点点帮助,那么麻烦您轻轻的点个赞,以资鼓励。

时间: 2024-10-20 22:00:56

一步步学习javascript基础篇(5):面向对象设计之对象继承(原型链继承)的相关文章

一步步学习javascript基础篇(3):Object、Function等引用类型

我们在<一步步学习javascript基础篇(1):基本概念>中简单的介绍了五种基本数据类型Undefined.Null.Boolean.Number和String.今天我们主要介绍下复杂数据类型(即引用数据类型) Object类型 我们用的最多的引用类型就属object类型了,一般用来存储和传输数据是再好不过的.然,它的两种创建方式我们是否了解呢? 1.通过构造函数来创建 如: var obj = new Object(); 在js中的引用类型有个非常灵活的用法,可以动态的附加属性和赋值.

一步步学习javascript基础篇(8):细说事件

终于学到事件了,不知道为何听到“事件”就有一种莫名的兴奋.可能是之前的那些知识点过于枯燥无味吧,说起事件感觉顿时高大上了.今天我们就来好好分析下这个高大上的东西. 可以说,如果没有事件我们的页面就只能阅读了.有了事件,我们可以通过键盘或是鼠标和页面交互了,通过我们不同的操作页面给出不同的响应.好了,开始我们今天的分析吧. DOM0级事件处理方式 什么是DOM0级? 其实世上本来没有DOM0级,叫的人多了就有了DOM0级. 在1998 年 10 月 DOM1级规范成为 W3C 的推荐标准,在此之前

一步步学习javascript基础篇(7):BOM和DOM

一.什么是BOM.什么是DOM BOM即浏览器对象模型,主要用了访问一些和网页无关的浏览器功能.如:window.location.navigator.screen.history等对象. DOM即文档对象模型,针对HTML(或XML)文档的API(应用程序编程接口).描绘的一个层次化的节点树,开发人员可以添加.修改和删除页面的某一部分. 二.细说BOM对象 1.window对象 window对象表示浏览器的一个实例,同时也是ECMAScript 规定的 Global 对象.(Global :所

一步步学习javascript基础篇(6):函数表达式之【闭包】

回顾前面介绍过的三种定义函数方式 1. function sum (num1, num2) { return num1 + num2; }  //函数声明语法定义 2. var sum = function(num1, num2){ return num1 + num2; }; //函数表达式定义 3. var sum = new Function("num1", "num2", "return num1 + num2"); //Function

一步步学习javascript基础篇(2):作用域和作用域链

作用域和作用域链 js的语法用法非常的灵活,且稍不注意就踩坑.这集来分析下作用域和作用域链.我们且从几道题目入手,您可以试着在心里猜想着答案. 问题一. if (true) { var str = "李四"; } alert(str);//弹出值是? 问题二. function add(num1, num2) { var sum = num1 + num2; } add(1,2); alert(sum) //弹出值是? 问题三. var str1 = "张三"; v

一步步学习javascript基础篇(9):ajax请求的回退

需求1: ajax异步请求 url标识请求参数(也就是说复制url在新页面打开也会是ajax后的效果) ajax异步请求没问题,问题一般出在刷新url后请求的数据没了,这就是因为url没有记录参数.如果我们改变给url添加参数,这样就改变了url,也就会重新请求整个url.这样一来就没有了ajax的优势和作用了.那么,我们应该怎么保持参数而又不重新请求url呢?做过单页面SPA (Single-page Application)的都知道,我们可以使用描点来实现(因为修改描点的时候,不会发送url

Javascript 组合继承 原型链继承 寄生继承

Javascript继承通常有三种方式. 第一种:组合式继承: function SuperType(name) { this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function() { console.log(this.name); }; function SubType(name, age) { //通过ca

MDN——javascript——入门——第三章对象——对象.构造函数.原型链.继承——知识点总结

对象Object 由属性property(变量).方法method(函数)组成 var objectName = { member1Name : member1Value, member2Name : member2Value, member3Name : member3Value } member(成员)的值是任意的, 一个如上所示的对象被称之为对象的字面量(literal)——手动的写出对象的内容来创建一个对象.不同于从类实例化一个对象,我们会在后面学习这种方式. 访问对象成员 1.点表示法

JavaScript概念总结:作用域、闭包、对象与原型链

1 JavaScript变量作用域 1.1 函数作用域 没有块作用域:即作用域不是以{}包围的,其作用域完成由函数来决定,因而if /for等语句中的花括号不是独立的作用域. 如前述,JS的在函数中定义的局部变量只对这个函数内部可见,称之谓函数作用域. 嵌套作用域变量搜索规则:当在函数中引用一个变量时,JS会搜索当前函数作用域,如果没有找到则搜索其上层作用域,一直到全局作用域. [javascript] view plain copy print? var  value = 'global';