资讯专栏INFORMATION COLUMN

【笔记】JavaScript高级篇——面向对象、原型、继承

OBKoro1 / 849人阅读

摘要:继承传统的面向对象语言,继承是类与类之间的关系。原型继承原型定义原型就是指构造函数的属性所引用的对象。创建构造函数创建的实例对象张三李四就是对象的原型也是的原型在原型上创建一个属性运行和,并对比是否为同一个方法。

原文链接:http://www.hansmkiii.com/2018/07/06/javascript-node-1/

" 面向对象、原型、继承 "

1、面向对象 1.1 什么是面向对象程序设计

为了了解 面向对象面向过程 的区别,我们先看案例1。

案例1:一辆汽车以60km/h,在一条长度1200km的公路上行驶,求其行驶完全程需要的时间。

/* 面向过程 */
var time = 1200 / 60; // 计算汽车行驶时间
console.log(time); // 打印结果
/* 面向对象 */
// 创建公路对象
var road = {
    long: 1200 // 公路长度
};

// 创建小汽车对象
var car = {
    speed: 60, // 汽车速度
    road: road, // 汽车在公路上行驶,与公路对象关联(road已声明)
    run: function(){ // 汽车行驶的方法,返回行驶速度
        return this.road.long / this.speed;
    }
}

var r = car.run(); // 执行汽车行驶的方法,返回行驶速度
console.log(r); // 打印结果(30)

虽然看上去面向对象比面向过程要复杂了很多,但是如果考虑到以后可能会改变某个变量(公路长度或汽车行驶速度),面向过程需要修改运算过程中的值,而面向对象只需要在执行运算方法之前通过car.speed = 40修改 car 对象的 speed 属性即可,可以有效避免修改错误和修改多处。

当程序复杂程度到达一定的量级,面向对象可以提高程序的可维护性。

如果后面我们的需求改变了,依旧需要汽车对象,但是要返回汽车的颜色。
如果是面向过程开发,我们需要删除掉面向过程的所有代码,重新写代码返回汽车的颜色。而面向对象则不需要删除原来定义的对象,只需要给 car 对象增加一个 color 属性,扩展 car 对象。

所以,面向对象程序设计的优势有:

提高代码的可维护性

提高代码的可扩展性

1.2 面向对象的方式操作DOM

HTML

111
222
333
444

JS

// 给div添加背景颜色
// 面向过程
var divs = document.getElementsByTagName("div");
for (var i=0; i

如果多处需要相同的功能,面向对象的方法可以提高代码的复用性

2、继承

传统的面向对象语言,继承是 之间的关系。而JS中,由于没有 的概念。所以是 对象对象 之间的关系。

定义:在JS中,继承就是指使一个对象有权去访问另一个对象的能力。
比如:对象A能继承对象B的成员(属性和方法),那么,对象A就继承于对象B。

2.1 原型继承 原型

定义:原型就是指构造函数的prototype属性所引用的对象。
目的:解决同类对象数据共享问题。

示例:

// 创建构造函数 Person
function Person(name, age){ 
    this.name = name;
    this.age = age;
    this.say = function(){
        console.log("hello!")
    }
} 
// 创建 Person 的实例对象
var p1 = new Person("张三", 19);
var p2 = new Person("李四", 20);
// Person.prototype 就是对象 p1 的原型
// p1.__proto__ 也是 p1 的原型
console.log(Person.prototype === p1.__proto__); // true

此时,p1和p2都有继承了构造函数 Person 的 say 属性,在控制台打印查看:

p1.say(); // hello!
p2.say(); // hello!

这是 构造函数继承,那么 p1 的 say 和 p2 的 say 是不是同一个方法呢?

// 打印查看
console.log(p1.say === p2.say); // false

查看结果发现两个 say 方法并不是同一个,所以在创建实例对象的时候开辟了两块内存分别存放了 p1.say 和 p2.say,这就导致了内存的浪费,所以我们需要通过原型共享数据来解决这个问题。

// 创建构造函数 Person
function Person(name, age){ 
    this.name = name;
    this.age = age;
} 
// 创建 Person 的实例对象
var p1 = new Person("张三", 19);
var p2 = new Person("李四", 20);
// Person.prototype 就是对象 p1 的原型
// p1.__proto__ 也是 p1 的原型
// 在原型上创建一个 say 属性
Person.prototype.say = function(){
    console.log("hello!");
}
// 运行 p1.say 和 p2.say,并对比是否为同一个方法。
p1.say(); // hello!
p2.say(); // hello!
console.log(p1.say === p2.say); // true

如此便通过原型继承实现了数据共享。

构造函数中可以显式的指定return语句,但是如果返回的数据类型为简单数据类型,或者null undefined值都会被忽略,依旧返回的是构造函数的实例对象
2.2 类式继承

类式继承通过call(this, ... , ...)apply(this, arguments)方法改变this指向实现继承。

// 创建 Person 构造函数
function Person(name, age) {
    this.name = name;
    this.age = age;
}
// 创建 Student 构造函数
function Student(name, age, id){
    this.name = name;
    this.age = age;
    this.id = id;
}

Student对象是 Person 对象的一个分支,可以继承Person的属性。
所以Student 属性可以这样写:

function Student(name, age, id){
    Person.call(this, name, age);
    this.id = id;
}

var s = new Student("张三","20","123456789");
console.log(s); // {name: "张三", age: "20", id: "123456789"}

或者

function Student(name, age, id){
    Person.apply(this, arguments); // arguments 是一个数组 也可以写成 [name, age]
    this.id = id;
}

var s = new Student("张三","20","123456789");
console.log(s); // {name: "张三", age: "20", id: "123456789"}
2.3 组合继承

通过前面对 原型继承类式继承 的了解,我们发现 原型继承 用于继承静态数据, 类式继承 用于继承动态参数,所以我们有时候需要同时使用 原型继承类式继承,也就是 组合继承

function Person(name, age) {
    this.name = name;
    this.age = age;
}
// 类式继承
function Student(name, age, id){
    Person.call(this, name, age);
    this.id = id;
}
// 原型继承
Student.prototype.class = function(){
    console.log("English");
}
var s = new Student("张三", 20, "123456");
s.class();
2.4 extend方法
var a = {
    name: "g"
};

var b = {
    print: function() {
        console.log("Hello,JS!")
    }
}
// 将 parent 对象上的成员赋值给 child
function extend(child, parent) {
    for (var pro in parent) {
        // child[pro] = parent[pro];
        // 缺点:会将parent对象的原型上的成员一同复制过来,所以需要先判断属性是否为parent私有的
        if (parent.hasOwnProperty(pro)){
            child[pro] = parent[pro];
        }
    }
}
extend(a,b);
a.print();

以上四种继承方式是开发过程中最常见的几种,具体应用场景视情况而定,甚至可以多个组合使用

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96051.html

相关文章

  • 读《javaScript高级程序设计-第6章》之继承

    摘要:此时的原型对象包括一个指向另一个原型的指针,相应的,另一个原型中的指向另一个构造函数。这种关系层层递进,就通过一个原型对象链接另一个构造函数的原型对象的方式实现了继承。 读这篇之前,最好是已读过我前面的关于对象的理解和封装类的笔记。第6章我一共写了3篇总结,下面是相关链接:读《javaScript高级程序设计-第6章》之理解对象读《javaScript高级程序设计-第6章》之封装类 一...

    villainhr 评论0 收藏0
  • JavaScript面向对象精要(二)

    摘要:使用时,会自动创建对象,其类型为构造函数类型,指向对象实例缺少关键字,指向全局对象。构造函数本身也具有属性指向原型对象。 在JavaScript面向对象精要(一)中讲解了一些与面向对象相关的概念和方法,这篇讲讲原型和继承。 构造函数和原型对象 构造函数也是函数,用new创建对象时调用的函数,与普通函数的一个区别是,其首字母应该大写。但如果将构造函数当作普通函数调用(缺少new关键字...

    wayneli 评论0 收藏0
  • javascript高级程序设计》笔记继承

    摘要:继承和前面两篇文章中的知识非常相关,如果对函数创建原理和原型链不熟悉,请猛戳高级程序设计笔记创建对象高级程序设计笔记原型图解继承,通俗的说,就是将自身不存在的属性或方法,通过某种方式为自己所用文章分别介绍原型链继承继承借用构造函数继承组合继 继承和前面两篇文章中的知识非常相关,如果对函数创建原理和原型链不熟悉,请猛戳:《javascript高级程序设计》笔记:创建对象《javascri...

    JerryC 评论0 收藏0
  • 《你不知道的javascript笔记_对象&原型

    摘要:上一篇你不知道的笔记写在前面这是年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响年是向上的一年在新的城市稳定连续坚持健身三个月早睡早起游戏时间大大缩减,学会生活。 上一篇:《你不知道的javascript》笔记_this 写在前面 这是2019年第一篇博客,回顾去年年初列的学习清单,发现仅有部分完成了。当然,这并不影响2018年是向上的一年:在新的城市稳定、...

    seasonley 评论0 收藏0
  • JavaScript学习笔记第四天_面向对象编程

    摘要:即另外,注意到构造函数里的属性,都没有经过进行初始化,而是直接使用进行绑定。并且在模式下,构造函数没有使用进行调用,也会导致报错。调用构造函数千万不要忘记写。 1. 基础 JavaScript不区分类和实例的概念,而是通过原型来实现面向对象编程。Java是从高级的抽象上设计的类和实例,而JavaScript的设计理念,听起来就好比Heros里的Peter,可以复制别人的能力。JavaS...

    weapon 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<