浅谈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 相关文章推荐
纯JS实现的批量图片预览加载功能
Aug 14 Javascript
点击弹出层外区域关闭弹出层jquery特效示例
Aug 25 Javascript
javascript分页代码实例分享(js分页)
Dec 13 Javascript
jquery如何通过name名称获取当前name的value值
Dec 20 Javascript
jQuery选择器源码解读(七):elementMatcher函数
Mar 31 Javascript
使用JavaScript实现旋转的彩圈特效
Jun 23 Javascript
JavaScript实现图片轮播的方法
Jul 31 Javascript
JS处理json日期格式化问题
Oct 01 Javascript
jQuery防止重复绑定事件的解决方法
May 14 Javascript
批量下载对路网图片并生成html的实现方法
Jun 07 Javascript
JavaScript oncopy事件用法实例解析
May 13 Javascript
解决vue使用vant下拉框van-dropdown-item 绑定title值不变问题
Aug 05 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
PHP 安全检测代码片段(分享)
2013/07/05 PHP
PHP命名空间namespace用法实例分析
2016/09/27 PHP
Zend Framework入门教程之Zend_Session会话操作详解
2016/12/08 PHP
老生常谈PHP数组函数array_merge(必看篇)
2017/05/25 PHP
PHP获取本周所有日期或者最近七天所有日期的方法
2018/06/20 PHP
ThinkPHP框架实现定时执行任务的两种方法分析
2018/09/04 PHP
锋利的jQuery 要点归纳(三) jQuery中的事件和动画(上:事件篇)
2010/03/24 Javascript
解释&&和||在javascript中的另类用法
2014/07/28 Javascript
浅谈Unicode与JavaScript的发展史
2015/01/19 Javascript
JS实战篇之收缩菜单表单布局
2016/12/10 Javascript
利用VUE框架,实现列表分页功能示例代码
2017/01/12 Javascript
javaScript中封装的各种写法示例(推荐)
2017/07/03 Javascript
AngularJS常见过滤器用法实例总结
2017/07/06 Javascript
Angularjs 1.3 中的$parse实例代码
2017/09/14 Javascript
最实用的JS数组函数整理
2017/12/05 Javascript
解决Angular.js中使用Swiper插件不能滑动的问题
2018/02/26 Javascript
JavaScript实现Tab标签页切换的最简便方式(4种)
2020/06/28 Javascript
利用node.js开发cli的完整步骤
2020/12/29 Javascript
[01:14:35]DOTA2上海特级锦标赛B组资格赛#1 Alliance VS Fnatic第一局
2016/02/26 DOTA
python数据结构之二叉树的建立实例
2014/04/29 Python
Anaconda多环境多版本python配置操作方法
2017/09/12 Python
django配置连接数据库及原生sql语句的使用方法
2019/03/03 Python
python 命名规范知识点汇总
2020/02/14 Python
Python如何获取文件指定行的内容
2020/05/27 Python
Jupyter notebook命令和编辑模式常用快捷键汇总
2020/11/17 Python
CSS3解决移动页面上点击链接触发色块的问题
2016/06/03 HTML / CSS
CSS3 transforms应用于背景图像的解决方法
2019/04/16 HTML / CSS
Delphi工程师笔试题
2013/09/21 面试题
医药代表个人求职信范本
2013/12/19 职场文书
25岁生日感言
2014/01/13 职场文书
销售求职信范文
2014/05/26 职场文书
见习报告格式范文
2014/11/08 职场文书
2015年教师节慰问信
2015/03/23 职场文书
保密法制宣传月活动总结
2015/05/07 职场文书
2016年秋季运动会通讯稿
2015/11/25 职场文书
2016教师校本研修心得体会
2016/01/08 职场文书