浅谈Javascript中的对象和继承


Posted in Javascript onApril 19, 2019

Javascript是一门函数式编程语言,Javascript当中函数是核心,在Javascript中函数也是对象,函数对象在创建的时候会被添加属性和方法。

在Javascript中函数对象有两种调用方式,一种是new关键字的调用,另一种是没有new关键字的调用,前者会返回一个对象,后者会返回return语句中的内容。

function Obj (name) {
 this.name = name;
 return name;
}

用new关键字来调用如下:

var obj = new Obj('张三') // 返回 { 'name': '张三' }

不用new关键字调用如下:

var obj = Obj('张三') // 返回 '张三'

说完了js当中的对象和调用方式,那让我们来理解下什么是对象。

什么是对象?

对象是类的一个实例(对象可不是女朋友),有状态和行为。例如:一个电脑就是一个对象,它的状态有:大小、颜色、品牌等,他的行为有:播视频、听音乐、聊天等。

而类是对象的抽象,可以理解为类是一个模板,它来描述一类对象的状态和行为。软件对象也有状态和行为,软件对象的状态就是属性,行为就是方法。在软件开发中,在方法中可以操作对象的内部状态,对象的相互调用也是通过方法来完成。

类既然可以理解为一个模板,我们通过一个Person的简单例子来理解下:

function Person (name, age, sex) {
 this.name = name;
 this.age = age;
 this.sex = sex;
 run = function () {
 console.log('Run')
 }
}

 在这个类中name,age,sex为这个类的属性,而run为这个类的方法;Person的职责是构造对象,进行对象的初始化。

接下来我们看下在js中如何声明并调用对象。

对象的创建(多种方法)

块级对象

var person = {
 name: '王小端coder',
 age: 29
}
console.log(person.name); // 王小端coder

构造函数 --- 系统自带

var obj = new Object();
obj.name = '王小端coder'

console.log(obj.name); // 王小端coder

系统自带的对象有:Object、Array、Number、Boolean、Date等

构造函数 --- 自定义

function Obj (name) {
 this.name = name;
}
var obj = new Obj('王小端coder');
console.log(obj.name); // 王小端coder

对象的增删改查

增:为对象添加一个属性

var person = {};
person.name = '王小端coder';
console.log(person.name);

删:通过delete操作符删除一个对象的属性

var person = {
 name: '王小端coder'
};
console.log(person.name); // 王小端coder
delete person.name;
console.log(person.name); // undefined

改:直接通过赋值来修改一个对象的属性

var person = {
 name: '王小端coder'
};
console.log(person.name); // 王小端coder
person.name = '王小端JS'
console.log(person.name); // 王小端JS

查:查询对象的属性,有两种方法

var person = {
 name: '王小端coder'
};
console.log(person['name']); // 第一种方法
console.log(person.name); // 第二种方法

原型的定义

原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过构造函数产生的对象,可以继承该原型的属性和方法,原型也是对象。

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

Person.prototype = {
 eat: function (food) {
 console.log('eat ' + food);
 },
 sleep: function () {
 console.log('sleeping');
 }
}
var person = new Person ('王小端coder', 29);
console.log(person.name); // 王小端coder
person.eat('apple') // eat apple

我们定义了一个Person构造函数,而属于Person构造对象共有的方法,则定义到了Person原型上。

查看构造函数原型的接口:隐士属性__proto__(其实我们能够访问原型的属性,或者说继承原型,靠的就是__proto__属性连接着构造函数和原型,可以说没有__proto__属性的存在,就无法实现原型的继承)直接通过new操作符创建的对象访问__proto__属性即可查看到原型。

原型链

原型链就是将一个个原型串联起来,形成一条原型继承的链子。Child继承Parent, Parent继承GrandParent, 而GrandParent没有自定义原型,所以默认为原型链的最顶端new Object();

对象的继承(多种方式)

创建的子类将继承超类的所有属性和方法,包括构造函数及方法的实现。记住,所有属性和方法都是公用的,因此子类可直接访问这些方法。子类还可添加超类中没有的新属性和方法,也可以覆盖超类的属性和方法。和其他功能一样,JavaScript实现继承的方式不止一种。这是因为JavaScript中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。作为开发者,你有权决定最适用的继承方式。

我们先定义一个父类

// 定义一个父类
function Person (name) {
 this.name = name;
 this.sleep = function () {
 console.log('朕正在睡觉!');
 }
}
// 在父类原型上面增加一个方法
Person.prototype.eat = function (food) {
 console.log('朕现在吃的食物是:' + food);
}

下面为您介绍几种具体的继承方式:

原型链继承

// 定义一个婴儿来继承人的父类
function Baby () {
}
Baby.prototype = new Person();
Baby.prototype.name = '小端';

var baby = new Baby()
console.log(baby.name); // 小端
baby.eat('milk'); // 朕现在吃的食物是:milk

优点: 简单、易于实现;父类新增的原型方法和属性子类都能访问到;

缺点: 无法实现多继承;来自原型的对象的所有属性被所有实例共享;如果为子类增加属性和方法,无法放倒构造器中;创建子类实例时无法向父类构造函数传参;

构造继承

// 定义一个婴儿来继承人的父类
function Baby (name) {
 Person.call(this);
 this.name = name || 'Coder'
}

let baby = new Baby();
console.log(baby.name); // Coder
baby.sleep(); // 朕正在睡觉!
console.log(baby instanceof Person); // false
console.log(baby instanceof Baby); // true

优点: 可以实现多继承;创建子类时可以向父类传递参数;子类可以共享父类引用的属性;

缺点: 实例不是父类的实例;只能继承父类的实例属性和方法;无法实现函数复用,每个子类都有父类实例函数的副本,影响性能;

实例继承

function Baby (name) {
 var instance = new Person();
 instance.name = name || 'Coder';
 return instance;
}
let baby = new Baby();
console.log(baby.name); // Coder
baby.sleep() // 朕正在睡觉!

优点: 不限制调用方式,返回的对象具有相同的效果;

缺点: 不支持多继承;实例是父类的实例,不是子类的实例;

拷贝继承

// 定义一个婴儿来继承人的父类
function Baby (name) {
 var person = new Person();
 for (let p in person){
  Baby.prototype[p] = person[p];
 }
 Baby.prototype.name = name || 'Coder';
}
let baby = new Baby();
console.log(baby.name); // Coder
baby.sleep() // 朕正在睡觉!

优点: 支持多继承;

缺点: 效率较低,内存占用高;无法获取父类不可枚举的方法;

注意:不可枚举的方法是不能使用for in访问到的方法

组合继承

// 定义一个婴儿来继承人的父类
function Baby (name) {
 Person.call(this);
 this.name = name || 'Coder';
}
Baby.prototype = new Person();
Baby.prototype.constructor = Baby;

let baby = new Baby();
console.log(baby.name); // Coder
baby.eat('milk'); // 朕现在吃的食物是:milk

优点: 不存在引用属性共享问题,可以传参,函数可复用;

缺点: 调用两次构造函数,生成了两份实例;

寄生组合继承

// 定义一个婴儿来继承人的父类
function Baby (name) {
 Person.call(this);
 this.name = name || 'Coder';
}
(function () {
 let Super = function () {};
 Super.prototype = Person.prototype;
 Baby.prototype = new Super();
})();

let baby = new Baby();
console.log(baby.name); // Coder
baby.eat('milk'); // 朕现在吃的食物是:milk

优点: 整合了以上几种继承的优点;

缺点: 实现复杂;

ES6的class

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

可以像如下定义:

class Person {
 constructor (name) {
  this.name = name;
 }
 sleep () {
  console.log('朕正在睡觉!');
 }
 eat (food) {
  console.log('朕现在吃的食物是:' + food);
 }
}

let person = new Person('小端');
console.log(person.name); // 小端
person.eat('milk'); // 朕现在吃的食物是:milk

ES6 class的继承

// 定义一个婴儿来继承人的父类
class Baby extends Person {
 constructor(name){
  super(name);
 }
}
let baby = new Baby('小端');
console.log(baby.name); // 小端
baby.eat('milk'); // 朕现在吃的食物是:milk

我们可以看到Class可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。

我之后会单独用一章来详细讲ES6中的Class和继承。

以上所述是小编给大家介绍的Javascript中的对象和继承详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
图片连续滚动代码[兼容IE/firefox]
Jun 11 Javascript
javascript 简练的几个函数
Aug 29 Javascript
js replace正则表达式应用案例讲解
Jan 17 Javascript
jQuery焦点图切换特效插件封装实例
Aug 18 Javascript
JS身份证信息验证正则表达式
Jun 12 Javascript
Vue源码学习之初始化模块init.js解析
Nov 02 Javascript
vue 使用ref 让父组件调用子组件的方法
Feb 08 Javascript
VueJS 组件参数名命名与组件属性转化问题
Dec 03 Javascript
教你使用vue-cli快速构建的小说阅读器
May 13 Javascript
vue使用recorder.js实现录音功能
Nov 22 Javascript
vue过滤器实现日期格式化的案例分析
Jul 02 Javascript
vue如何在项目中调用腾讯云的滑动验证码
Jul 15 Javascript
详解如何在Vue项目中导出Excel
Apr 19 #Javascript
vue cli使用融云实现聊天功能的实例代码
Apr 19 #Javascript
详解vue中使用微信jssdk
Apr 19 #Javascript
vue router导航守卫(router.beforeEach())的使用详解
Apr 19 #Javascript
this.$toast() 了解一下?
Apr 18 #Javascript
Vue-input框checkbox强制刷新问题
Apr 18 #Javascript
vue axios封装及API统一管理的方法
Apr 18 #Javascript
You might like
《忧国的莫里亚蒂》先导宣传图与STAFF公开
2020/03/04 日漫
Windows下PHP的任意文件执行漏洞
2006/10/09 PHP
php若干单维数组遍历方法的比较
2011/09/20 PHP
Laravel 修改验证异常的响应格式实例代码详解
2020/05/25 PHP
jquery快捷动态绑定键盘事件的操作函数代码
2013/10/17 Javascript
jQuery处理xml格式的返回数据(实例解析)
2013/11/28 Javascript
JQuery中$(document)是什么意思有什么作用
2014/07/21 Javascript
浅析javascript的间隔调用和延时调用
2014/11/12 Javascript
Bootstrap每天必学之缩略图与警示窗
2015/11/29 Javascript
jquery.cookie.js用法实例详解
2015/12/25 Javascript
移动端js触摸事件详解
2016/09/18 Javascript
BootStrap入门教程(二)之固定的内置样式
2016/09/19 Javascript
理解JavaScript原型链
2016/10/25 Javascript
jQuery实现多张图片上传预览(不经过后端处理)
2017/04/29 jQuery
vue组件中使用iframe元素的示例代码
2017/12/13 Javascript
如何在JavaScript中谨慎使用代码注释
2019/06/21 Javascript
javascript设计模式 ? 观察者模式原理与用法实例分析
2020/04/22 Javascript
vue data对象重新赋值无效(未更改)的解决方式
2020/07/24 Javascript
javascript如何使用函数random来实现课堂随机点名方法详解
2020/07/28 Javascript
基于p5.js 2D图像接口的扩展(交互实现)
2020/11/30 Javascript
[46:12]完美世界DOTA2联赛循环赛 DM vs Matador BO2第一场 11.04
2020/11/04 DOTA
Python中标准库OS的常用方法总结大全
2017/07/19 Python
利用selenium爬虫抓取数据的基础教程
2019/06/10 Python
python实现websocket的客户端压力测试
2019/06/25 Python
python 普通克里金(Kriging)法的实现
2019/12/19 Python
PHP面试题-$message和$$message的区别
2015/12/08 面试题
写一个函数返回1+2+3+…+n的值(假定结果不会超过长整型变量的范围)
2014/09/05 面试题
如何进行Linux分区优化
2016/09/13 面试题
外贸业务员求职自荐信分享
2013/09/21 职场文书
安全大检查反思材料
2014/01/31 职场文书
汉语言文学毕业求职信
2014/07/17 职场文书
会计工作岗位职责
2015/02/03 职场文书
小学班主任自我评价
2015/03/11 职场文书
观后感格式
2015/06/19 职场文书
市直属机关2016年主题党日活动总结
2016/04/05 职场文书
Java GUI编程菜单组件实例详解
2022/04/07 Java/Android