`

JavaScript中的继承(高级篇)

阅读更多
本文主要是针对《悟透JavaScript》第7、11章做的笔记。

为了方便,这篇笔记里我直接使用“类”这个名称。

0、JSON

先插点题外话(不是JavaScript的题外话,只是与主题“继承”没有直接关系),说说JSON。
JSON是JavaScript对象的另外一种表示方式,可以算是JavaScript对象的字面量吧。习惯上,我们是这样创建对象并给它添加属性:
var object = new Object
object.name = "an object"
object.age = 0

实际上,我们还有另外一种表示JavaScript对象的方式,也就是JSON,它的格式是这样的:
var object = {name:"an object", age:0}

给它添加个方法吧:
var object = {name:"an object", age:0, sayHi:function(){
		alert("hi")
	}
}

这形式看起来有点像哈希表(HashTable)。只是这个hash只能以字符串为key,来看看都有什么玩法:
var hash = {x:2,y:3}
alert(hash["x"]) //alert: 2
alert(hash.x) //alert: 2
hash["z"] = 4
alert(hash["z"]) //alert: 4
alert(hash.z) //alert: 4


假如有这样的代码:
var d = new Date;
var o = {d:'hello'};
alert(o[d]);
将会弹出什么?hello?不对,是undefined。要想看到hello必须这样:
alert(o['d']);
这个例子进一步说明了这个key只能是字符串,而不能是其它对象。
《JavaScript语言精粹》 写道
属性名可以是包括空字符串在内的任何字符串。在对象字面量中,如果属性名是一个合法的JavaScript标识符且不是保留字,并不强制要求用引号括住属性名。


OK,JSON内容到此为止。

1、原型真谛

之前的JavaScript继承其实还有些美中不足:子类的prototype不但继承了父类的方法,同时也继承了父类的属性,但这些属性对子类的实例来说是没有用的,尽管这些属性的值是undefined,但这也是一种浪费啊(给JavaScript对象的一个属性赋值为undefined不意味着清除了该属性,反而会因此多了一个属性):
var puts = function(content){
	document.write(content + "<br/>")
}
		
//定义Person类
function Person(name, age){
	this.name = name
	this.age = age
}

Person.prototype.sayHello = function(){
	alert("Hello, I'm " + this.name + ".")
}

//定义Employee类
function Employee(name, age, salary){
	//Person.call(this, name, age)
	Person.apply(this, [name, age])
	this.salary = salary
}

Employee.prototype = new Person
Employee.prototype.showMeTheMoney = function(){
	alert(this.name + "$" + this.salary)
}

for(var e in Employee.prototype)
	puts(e) //将会看到输出了name和age两个属性

回想对象创建的过程,构造函数只起到两个作用:1、介绍原型对象;2、初始化对象。那么我们能否自己定义一个对象来当做原型呢?直接用一个对象做原型,并且保证这个对象没有不必要的一些属性,不是就可以避免上面的情况了吗:
var Person = {
	_create:function(name, age){
		this.name = name
		this.age = age
	},
	sayHello:function(){
		alert("Hello, I'm " + this.name)
	},
	howOld:function(){
		alert(this.name + " is " + this.age + " years old.")
	}
}

可以这样利用上面的对象来构造对象:
function anyfun(name, age){
	Person._create.apply(this, [name, age])
}

anyfun.prototype = Person
var yuan = new anyfun("yuan", 24)
yuan.sayHello()

但这个anyfun在构造完对象之后就没有用处了。如果把上面的这几句代码写成一个通用函数,那这个anyfun不就成了函数内的函数了吗?这样一来,当这个通用函数执行完毕,这个anyfun也就被销毁了。
function New(clazz, params){
	function new_(){
		clazz._create.apply(this, params)
	}
	
	new_.prototype = clazz
	return new new_
}

var yuan = New(Person, ["yuan", 24])
yuan.sayHello()

再来加一些东西,让它更像一般的对象语言:
var object = {
	isA:function(type){
		var _self = this
		while(_self){
			if(_self == type)
				return true
			_self = _self._type
		}
		return false
	}
}

function Class(base, define){
	function class_(){ //构造一个原型
		this._type = base //因为是构造原型,所以这个_type属性属于原型,而不是实例。
		for(var member in define) //遍历定义体,把定义体中的每个属性复制给原型
			this[member] = define[member]
	}
	class_.prototype = base //原型的类的原型。给原型的原型传递base对象的所有属性(即定义在基类中的所有方法),相当于间接给原型传递属性。。。。这话怎么这么绕呢
	return new class_ //返回构造好的原型
}

function New(clazz, params){
	function new_(){ //根据原型构造对象
		this._type = clazz //这个对象有个_type,指向原型,供内部使用。
		clazz._create.apply(this, params) //调用原型的构造方法,把参数传进去。
	}
	new_.prototype = clazz //从原型继承方法
	return new new_ //构造并返回对象
}


var Person = Class(object, {
	_create:function(name, age){
		this.name = name
		this.age = age
	},
	sayHello:function(){
		alert("Hello, I'm " + this.name + ".")
	},
	howOld:function(){
		alert(this.name + " is " + this.age + " years old.")
	}
})

var Employee = Class(Person,{
	_create:function(name, age, salary){
		Person._create.call(this, name, age)
		this.salary = salary
	},
	showMeTheMoney:function(){
		alert(this.name + "$" + this.salary)
	}
})

var yuan = New(Employee, ["yuan", 24, 8000])
yuan.sayHello()
yuan.howOld()
yuan.showMeTheMoney()
alert(yuan.isA(Employee))
alert(yuan.isA(Person))

很好很强大!

书上说这样的做法会使JavaScript程序效率更高,因为其原型对象里既没有了毫无用处的那些对象级的成员,而且还不存在constructor属性体,少了与构造函数间的牵连,但依旧保持了方法的共享性。这让JavaScript在追溯原型链和搜索属性及方法时少费许多工夫。
分享到:
评论

相关推荐

    JavaScript高级篇视频教程

    在JavaScript的高级篇中,首先会讲解面向对象编程(OOP)的概念。这包括类与对象的创建,封装、继承和多态等面向对象的基本特征。学习者将了解如何通过构造函数、原型链以及ES6引入的class语法来创建和操作对象,...

    一头扎进 JavaScript (高级篇) 视频教程 java1234出品

    在“一头扎进 JavaScript (高级篇) 视频教程”中,java1234出品的课程旨在深入探讨JavaScript的高级特性,帮助开发者提升技能水平。在这个高级篇教程中,我们可以期待学习到以下几个关键知识点: 1. **闭包...

    JavaScript高级教程(完整版)

    这篇《JavaScript高级教程》全面深入地探讨了这门语言的核心概念和技术,旨在帮助开发者从初级水平跃升至高级阶段。 首先,JavaScript的基础部分涵盖了变量、数据类型(包括基本类型和引用类型)、操作符、流程控制...

    JavaScript高级程序设计2,学习笔记---第一篇

    这篇学习笔记将带你探索JavaScript的核心概念,包括变量、数据类型、控制流、函数、对象和类等,这些都是构建复杂应用程序的基础。 首先,我们要了解JavaScript的基础语法。在JavaScript中,变量是存储数据的容器,...

    javascript高级教程 pdf,学javascript必读

    此外,教程还涵盖了原型和原型链,这是理解JavaScript继承机制的关键。JavaScript使用原型来实现对象的继承,每个对象都有一个内部[[Prototype]]属性,通常通过`__proto__`或`Object.getPrototypeOf()`访问。理解这...

    javascript高级教程2.txt

    根据提供的文件信息,我们可以推断出这是一篇关于JavaScript高级应用的文章或教程。尽管原文存在大量乱码,但我们可以从可识别的部分提炼出关键知识点。接下来,将详细阐述这些知识点。 ### JavaScript高级教程概览...

    网络编程基础篇之javascript

    另外,JavaScript支持闭包,这是一种高级特性,允许函数访问并操作其外部作用域的变量,即使在其外部作用域已执行完毕的情况下。 面向对象是JavaScript的另一大特性,包括构造函数、原型链和实例化。构造函数用于...

    javascript 高级程序设计 读书笔记(3)

    原型是JavaScript中实现继承的关键机制。每个对象都有一个`__proto__`属性,指向其构造函数的原型。原型链允许我们访问对象的父对象上的属性和方法。此外,`Object.create()`方法可以用来创建具有指定原型的新对象。...

    13、JavaScript继承实现(二) —— zInherit、xbObjects

    zInherit是一种常用的JavaScript继承实现方式,它通过修改对象的`__proto__`属性来实现继承。`__proto__`指向父对象的原型,从而使得子对象能够访问父对象的属性和方法。但是,`__proto__`并不是所有浏览器都支持的...

    Javascript忍者的秘密

    《JavaScript忍者的秘密》这篇博文主要探讨了JavaScript编程中的高级技巧和不为人知的细节,旨在帮助开发者提升在JavaScript领域的专业技能。通过学习这些“秘密”,开发者可以更好地理解和利用JavaScript的强大功能...

    javascript中的类理解

    虽然在提供的内容中没有直接涉及继承,但在 JavaScript 中,类可以通过 `extends` 关键字实现继承。子类可以继承父类的属性和方法,并可以添加自己的特性。例如: ```javascript class MaleUser extends ...

    深入理解JavaScript系列

    面向对象编程是现代软件开发的重要思想,这部分内容讲解了JavaScript中的类、对象、继承、构造函数等OOP概念,以及如何在ECMAScript环境中实现这些概念。 4. **设计模式之代理模式** 设计模式是解决常见编程问题...

    网络编程基础篇之Javascript(EXE)

    了解并掌握以上JavaScript基础知识后,可以进一步学习更高级的主题,如闭包、模块化、ES6新特性、前端框架(如React、Vue、Angular)以及Node.js后端开发,从而成为一名全面的Web开发者。这个“网络编程基础篇之...

    JavaScript 高级篇之闭包、模拟类,继承(五)

    【JavaScript 高级篇之闭包、模拟类、继承(五)】 一、JavaScript中的闭包 闭包是JavaScript中的一个重要概念,它涉及到函数的作用域和内存管理。函数的作用域决定了变量的可见性和生命周期,而闭包则允许内部...

    JavaScript_Demo,文章《JavaScript笔记》配套代码

    此外,闭包是JavaScript中的一个高级概念,它允许内部函数访问并操作外部函数的变量,即使外部函数已经执行完毕。理解闭包对于优化代码和实现某些特定功能非常有用。 事件处理是前端开发中不可或缺的部分。在...

    javascript文档

    这篇详尽的文档“javascript文档”深入探讨了JavaScript的各个方面,包括基础语法、对象、函数、DOM操作以及高级特性,旨在帮助读者熟练掌握这门语言。 一、基础语法 JavaScript的基础语法包括变量声明(var、let、...

    Javascript总结导图

    本篇内容将围绕"JavaScript总结导图"展开,深入探讨JavaScript的基础知识、核心概念以及高级特性。 1. **基础语法** JavaScript的基础包括变量声明(var、let、const)、数据类型(如字符串、数字、布尔值、null、...

    JavaScript语言精粹经典实例(整理篇)

    在深入探讨JavaScript语言精粹和经典实例之前,首先需要理解JavaScript是一种高级的、解释型的编程语言,它是Web开发中不可或缺的一部分。它的主要特点是动态、弱类型、原型继承,以及函数是一等公民的特性。...

    javascript教程,javascript入门,javascript资料

    除此之外,JavaScript还有许多高级话题,如模块化(CommonJS、ES6模块)、Promise和async/await用于异步编程、以及ES6及以后版本引入的众多新特性,如箭头函数、模板字符串、解构赋值、类和继承等。 最后,随着Node...

    JavaScript模式(中文版带目录)

    在JavaScript中,由于其独特的原型继承和动态类型,理解并运用设计模式能帮助开发者编写更高效、更易于维护的代码。 二、基本技巧 这部分可能涵盖变量作用域、闭包、异步编程(如回调函数、Promise、async/await)...

Global site tag (gtag.js) - Google Analytics