玩转JavaScript OOP[1]——复杂类型

概述

在JavaScript中,我们可以使用函数、数组、对象,以及日期、正则等一些内置类型的实例,它们都是复杂类型的表现。从本质上讲,这些复杂类型都是Object类型。本篇主要的内容有3点:函数、数组和对象。

函数

函数是JavaScript的一大重点,它非常的灵活。不像C#这种强类型语言,可以显式地声明"class",JavaScript没有"class"的概念,但借助函数我们可以实现"class"的概念。类和对象是面向对象编程的基础,所以掌握函数是掌握JavaScript面向对象编程的前提。

定义函数

JavaScript的函数有两种定义方式:函数声明和表达式声明。

方式1:函数声明

// 函数声明
function sum(a,b){
	return a + b;
}

var result = sum(3,5); // 8;

函数声明function关键字后面跟着函数名称,参数放在一对小括号中,函数内容放在大括号内。
这段代码中,sum是函数的名称,如果指定了return语句,则可以通过变量来接收。

方式2:表达式声明

// 表达式声明
var hello = function(){
	console.log(‘Hello!‘);
}
hello();

表达式声明function关键字后面没有函数名称,这种函数也被称作匿名函数,匿名函数通常会被一个变量引用。
这段代码中,hello不是函数的名称,它是一个指向匿名函数的指针变量。
函数可以没有return语句,这时JavaScript引擎会自动地返回一个undefined。

两种方式的区别

虽然这两种方式比较相似,但它们有一个较大的区别——声明的提升
使用方式1声明的函数会被会被提升至函数所处上下文的顶部,使用方式2则不会。

下面这段代码在浏览器中是可以工作的,并且不会报错。

var result = sum(3,5); // 8;

// JavaScript引擎将函数声明提升到顶部
function sum(a,b){
	return a + b;
}

上面这段代码会被JavaScript引擎解释为下面这段代码。

function sum(a,b){
	return a + b;
}

var result = sum(3,5); // 8;

使用表达式声明的函数不会被提升,下面这段代码会报错。

// 会报错:hello is not a function
hello();

var hello = function(){
	consol.log(‘Hello!‘);
}

函数声明使得JavaScript引擎提前获知了函数的名称,匿名函数由于没有名称,JavaScript引擎无法对它进行提升。

小提示:无论使用哪种方式,应该先声明函数再使用,这样才不会出错。

函数的类型

使用typeof查看函数的类型时,得到的结果是"function"。
在JavaScript中,函数是一种特殊的引用类型,所有非函数的引用类型使用typeof都会返回"object"。

之前提到了JavaScript只有一种复杂类型(引用类型)——Object类型,函数既然是引用类型,那么怎么证明他是属于Object类型的呢?

使用instanceof操作符

虽然JavaScript没有类的概念,但是它有构造函数的概念,JavaScript是通过构造函数来创建对象实例的。
instanceof操作符可以用来判断某个构造函数的prototype属性所指向的對象是否存在于另外一个要检测对象的原型链上。
后面的文章会讲到prototype和原型链,如果你不理解这句话,则可以将这个操作符看成C#中的is操作符(判断对象是否为某个类的实例)。

下面这幅图揭示了sum函数是Function的实例,Function又是Object的实例,sum也是Object的实例。


Function()和Object()是JavaScript内置的两个构造函数。

sum()函数同样可以通过Function()函数来实现:

var sum = new Function(‘a‘,‘b‘, ‘return a + b;‘);

Function()构造函数的前面几个参数都表示函数的参数,最后一个参数表示函数的内容。
不管是函数参数还是函数内容,都是用字符串表示的,JavaScript引擎在运行时才需要先解析这种方式声明的函数,才能确定其形式。
虽然Function()构造函数可用于创建函数,但不建议这么做,因为它会使代码难以理解和调试。

小提示:在JavaScript中,new后面接的肯定是一个构造函数,例如new Function()、new Object()。

函数的本质是数据

函数本质上是数据,这是一个比较重要的概念。
函数可以用表达式声明,并将其赋给一个变量。
变量用于存储数据,变量要么存储基础类型的值,要么存储引用类型的地址。

下面这段代码,sum是一个变量,存储的却是函数指针。
同时,这个匿名函数被当成一般的值,并赋给了变量add。

var sum = function (a, b) {
	return a + b;
};

var add = sum;
add(6,4);	// 10

JavaScript的函数就是数据,但它们是一种特殊的数据:

  • 包含代码

  • 这些代码可以被执行或被调用

对象

使用基础类型时,我们只能一个变量存储一个值,如果要将多个值存储在一个变量中,可以使用对象。
JavaScript中的对象是动态的,对象中包含属性,属性以key-value形式存在。
由于JavaScript的灵活性,使得我们可以为在任意地方指定对象的属性,对象的属性也可以被指定为任意类型。

创建对象

在使用对象前,我们应该先创建对象。
对象有两种创建方式:使用{}Object()构造函数。

// 方式1:使用{}创建对象
var person = {
	name: ‘keepfool‘,
	job: ‘developer‘,
	say: function() {
		return ‘Hello! I am ‘ + this.name + ‘, I am a ‘ + this.job;
	}
};

// 方式2:使用Object()构造函数
var player = new Object();
player.name = ‘Stephen Cury‘;
player.age = 28;
player.play = function() {
	return ‘I am ‘ + this.name + ‘, ‘ + this.age + ‘ years old, I play basketball very well!‘;
}

这两种方式本质上没有什么区别,使用方式1声明对象时,JavaScript引擎背后做的工作和new Object()是一样的。
方式1相当于方式2的快捷方式,建议使用方式1来创建。

另外,在对象初始化后,你可以在任意时间给对象追加新的属性。

// 方式1:使用{}创建对象
var person = {
	name: ‘keepfool‘,
	job: ‘developer‘,
	say: function() {
		return ‘Hello! I am ‘ + this.name + ‘, I am a ‘ + this.job;
	}
};

// 追加新的属性
person.weigh = ‘70kg‘;
person.run = function() {
	return ‘I am running!‘;
}

注意:person对象的say属性是一个函数,当函数作为对象的一个属性时,我们称之为“方法”。
对象的属性就是数据,JavaScript的属性可以是方法,方法本质上是函数,从这个层面又印证了“函数就是数据”的说法。

访问属性

访问对象属性的方式也有两种:使用object.propertyobject[‘property‘]

object.property方式:

object[‘property‘]方式:

注意:person的say属性和player的play属性都是方法,通过person.say和player.play得到的是方法的指针(函数的指针),使用()才是调用对象的方法。
由于数组也提供了[]方式访问元素,为了区分数组和对象,建议使用object.property方式访问属性。

对象的类型

使用typeof查看对象的类型,得到的结果都是"object"。

使用instanceof检测是否为Object类型,得到的结果都是true。

数组

在C#中,数组中的元素是同一个类型的,JavaScript则不然。
在JavaScript中,你可以在数组中存储任意类型的值,数组元素可以是数字、字符、日期、对象、数组等等。
这和C#中的ArrayList有些相似。

创建数组

在JavaScript中,创建数组有两种方式:

// 方式1:使用[]创建数组
var arr1 = [1,"Hello", true, {id : 1, name : "keepfool"}];

// 方式2:使用Array()构造函数创建数组
var arr2 = new Array(1, "Hello", true, {id : 1, name : "keepfool"});

方式1和方式2本质上是一样的,在使用方式1声明数组时,JavaScript引擎做的事情和new Array()也是一样的。
方式1比方式2更加便捷直观一些,建议使用方式1。

访问数组元素

数组是一个有序的数据集合,通过[]索引器可以访问数组元素。

数组的类型

使用typeof查看数组的类型时,得到的结果是"object"。

数组的检测

如果你定义了多个变量,有些变量用于表示数组,有些变量用于表示数组。
将typeof操作符应用于对象或数组变量,得到的结果都是"object"。
我们怎么区别哪个变量是对象,哪个变量时数组呢?有两种方式可以鉴别。

方式1:使用instanceof

方式2:使用isArray()方法

数组是否为Object?

instanceof操作符检测函数的类型是Object的,那么数组也可以用这种方式来检测。

所以数组本质上也是Object类型的。

复杂类型总结

  • 函数、对象和数组都是Object类型的实例,使用Instanceof操作符可以检测它们

  • 函数的本质是数据,function是Function的实例,Function又是Object的实例
  • 对象是由属性构成的,对象的属性可以是任意类型的
  • 数组是有序的数据集合,数组元素可以是任意类型的,Array是Object的实例

【关注】keepfool

时间: 2024-08-26 10:57:07

玩转JavaScript OOP[1]——复杂类型的相关文章

玩转JavaScript OOP[0]——基础类型

前言 long long ago,大家普遍地认为JavaScript就是做一些网页特效的.处理一些事件的.我身边有一些老顽固的.NET程序员仍然停留在这种认知上,他们觉得没有后端开发肯定是构建不了系统的. 编程语言和技术的结合使用,就像一个男人娶了好几个妞一样.在旧的时代,.NET是大房,JavaScript是偏房.大房是"后宫之主",不仅要操持家业,还能给你生娃,娃将来也要继承家业的.偏房就没那么幸运了,在"后宫"没什么地位,虽然衣食无忧,但不能管理家族事务,生的

玩转JavaScript OOP[0]——基础类型

前言 long long ago,大家普遍地认为JavaScript就是做一些网页特效的.处理一些事件的.我身边有一些老顽固的.NET程序员仍然停留在这种认知上,他们觉得没有后端开发肯定是构建不了系统的. 编程语言和技术的结合使用,就像一个男人娶了好几个妞一样.在旧的时代,.NET是大房,JavaScript是偏房.大房是“后宫之主”,不仅要操持家业,还能给你生娃,娃将来也要继承家业的.偏房就没那么幸运了,在“后宫”没什么地位,虽然衣食无忧,但不能管理家族事务,生的娃也只能算是庶出,没有继承家业

玩转JavaScript OOP[2]——类的实现

概述 当我们在谈论面向对象编程时,我们在谈论什么?我们首先谈论的是一些概念:对象.类.封装.继承.多态.对象和类是面向对象的基础,封装.继承和多态是面向对象编程的三大特性. JavaScript提供了对象却缺乏类,它不能像C#一样能显式地定义一个类.但是JavaScript的函数功能非常灵活,其中之一就是构造函数,结合构造函数和原型对象可以实现"类". 对象和类的概念 对象 "对象"是面向对象编程中非常重要的一个概念,一个对象是一个"东西"(某个

玩转JavaScript OOP[4]——实现继承的12种套路

概述 在之前的文章中,我们借助构造函数实现了"类",然后结合原型对象实现了"继承",并了解了JavaScript中原型链的概念. 理解这些内容,有助于我们更深入地进行JavaScript面向对象编程. 由于JavaScript是一门基于对象和原型的弱语言,灵活度非常高,这使得JavaScript有各种套路去实现继承.本篇文章将逐一介绍实现继承的12种套路,它们可以适用于不同的场景,总一种套路适合你. (亲:文章有点长,请点击右侧的「显示文章目录」按钮,以便导航和阅读

玩转JavaScript OOP[3]——彻底理解继承和原型链

概述 首先,我们简单描述一下继承的概念:当一个类和另一个类构成"is a kind of"关系时,这两个类就构成了继承关系.继承关系的双方分别是子类和基类,子类可以重用基类中的属性和方法. 上一篇我们介绍了通过构造函数和原型可以实现JavaScript中的"类",由于构造函数和原型是对象,所以JavaScript的"类"本质上也是对象.这一篇我们将介绍JavaScript中的一个重要概念原型链,以及如何经原型链实现JavaScript中的继承.

JavaScript之基础-15 JavaScript OOP(概述、对象模板)

一.JavaScript OOP 概述 OOP 概述 - 面向对象的语言 - 封装 - 把相关的信息(无论数据或方法)存储在对象中 - 继承 - 从其它对象获得属性和方法 - 多态 - 能以多种不同的形式运行函数或方法 - ECMAScript支持这些要求,因此可被是看做面向对象的 封装 - 回顾直接量创建对象 - 使用new调用Object构造函数创建对象语法 继承 - 对象方法 - toString() - toLocaleString() - valueOf() 二.JavaScript

由浅入深JavaScript——变量和原始类型

JavaScript变量 JavaScript变量标识符标识符 var + 变量名称来定义变量.变量名称以字母,下划线_,美元$符号开头,余下字符可以是字母,数字,下划线,美元符号.eg: var  name = 'hello';     var  a1 = 'hello';    var  _test = 'hello';    var  $test = 'hello';    以上变量名称均为正确.    var  1a = 'hello'; //数字开头错误.    JavaScript允

用Javascript清空(重置)文件类型的INPUT元素的值

之前在StackOverflow回答了这个问题,现在整理到Blog里. 因为安全限制,脚本是不能随意设置其value值的,所以并不能像其它表单输入域那样用属性来设置使其重置. 重置一个文件域的值,归纳起来主要有 3 种方法. 本文分析这三种方法的浏览器兼容性以及优缺点,并给出一个比较完美的综合方案的代码和Demo. 重置文件域的三种方法: 设置value属性为空. 对于IE11以上和其它较新的非IE的现代浏览器Chrome/Firefox/Opera...有效. 克隆或创建一个新的文件输入元素进

(转)JavaScript中判断对象类型的种种方法

我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一个说明运算数类型的字符串.如:"number","string","boolean","object","function","undefined"(可用于判断变量是否存在). 但 type