目录
- 1. Vue常用特性
- 1.1 表单输入绑定
- 1.2 自定义指令
- 1.3 计算属性
- 1.3.1 基本使用
- 1.3.2 计算属性缓存 vs 方法
- 1.4 侦听属性及侦听器
- 1.4.1 基本使用
- 1.5 过滤器
- 1.5.1 基本使用
- 1.6 音乐播放器
- 1.6.1 功能演示
- 1.6.2 前置知识
- 1.6.3 示例代码
- 2. 综合案例
- 2.1 前置知识-数组
- 2.1.1 概念
- 2.1.2 元素
- 2.1.3 定义数组
- 2.1.4 数组元素的输入和输出
- 2.1.5 数组元素的添加和删除
- 2.1.6 length属性
- 2.1.7 prototype属性
- 2.1.8 数组的添加和删除
- 2.1.9 设置数组的排列顺序
- 2.1.10 获取某段数组元素
- 2.1.11 数组转换成字符串
- 2.1.12 高阶函数
- 2.2 Vue之数组更新检测
1. Vue常用特性
1.1 表单输入绑定
在 Vue全家桶之Vue基础(1) 一文中我们已经学习过 v-model
的用法。我们可以用 v-model
指令在表单 <input>
、<textarea>
及 <select>
元素上创建 双向数据绑定
。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model
本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model
会忽略所有表单元素的 value
、checked
、selected
attribute 的初始值而总是将 Vue
实例的数据作为数据来源。你应该通过 JavaScript
在组件的 data
选项中声明初始值。如下图所示:
v-model
在内部为不同的输入元素使用不同的 property
并抛出不同的事件:
- text 和 textarea 元素使用
value
property 和input
事件 - checkbox 和 radio 使用
checked
property 和change
事件 - select 字段将
value
作为 prop 并将change
作为事件
对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现 v-model
不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用 input
事件。
在后续关于表单输入绑定操作中用到的 js
代码如下:
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
message: "", //文本以及多行文本
checked: false, //单个复选框绑定到bool值
checkedNames: [], //多个复选框绑定到同一个数组
picked: "", //单选按钮
selected: "", //选择框单选
selected2: [], //选择框多选
selected3: "A", //动态渲染选项
options: [{
text: 'One',
value: 'A'
}, {
text: 'Two',
value: 'B'
}, {
text: 'Three',
value: 'C'
}]
}
});
</script>
文本:
<!-- placeholder:向用户显示描述性说明或者提示信息 -->
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
演示效果如下:
多行文本:
<span>Multiline message is:</span>
<!-- white-space: pre-line: 合并空白符序列,但是保留换行符。 -->
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
演示效果如下:
在文本区域插值 <textarea>{{text}}</textarea>)
并不会生效,应用 v-model
来代替。
单个复选框,绑定到布尔值:
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
演示效果如下:
多个复选框,绑定到同一个数组:
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
演示效果如下:
单选按钮:
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
演示效果如下:
补充:
<label>
标记用于在表单元素中定义标签,这些标签可以对其他一些表单控件元素(如单行文本框、密码框等)进行说明。<label>
标记可以指定id/style/class
等核心属性,也可以指定onclick
等事件属性。除此之外,<label>
标记还有一个for
属性,该属性指定<label>
标记与哪个表单控件相关联。- 虽然
<label>
标记定义的标签只是输出普通的文本,但<label>
标记生成的标签还有一个另外的作用,那就是当用户单击<label>
生成的标签时,和该标签关联的表单控件元素就会获得焦点
。也就是说,当用户选择元素所生成的标签时,浏览器会自动将焦点转移到和该标签相关联的表单控件元素上。 - 使标签和表单控件相关联主要有两种方式:
- 隐式关联
使用for
属性,指定<label>
标记的for
属性值为所关联的表单控件的id
属性值。 - 显式关联
将普通文本、表单控件一起放在标记内部即可。
- 隐式关联
选择框单选时:
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
演示效果如下:
如果 v-model
表达式的初始值未能匹配任何选项,<select>
元素将被渲染为 未选中
状态。在 iOS
中,这会使用户无法选择第一个选项。因为这样的情况下,iOS
不会触发 change
事件。因此,更推荐像上面这样提供一个 值为空的禁用选项
。
多选时(绑定到一个数组):
<!-- multiple: 表示列表/菜单内容可多选 -->
<select v-model="selected2" multiple style="width: 50px;">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected2 }}</span>
演示效果如下:
用 v-for
渲染的动态选项:
<select v-model="selected3">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected3 }}</span>
演示效果如下:
修饰符:
在默认情况下,v-model
在每次 input
事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy
修饰符,从而转为在 change
事件_之后_进行同步:
<!-- 在"change"时而非"input"时更新 -->
<input v-model.lazy="msg">
如以下例子所示:
演示效果如下:
如果想自动将用户的输入值转为数值类型,可以给 v-model
添加 number
修饰符:
<input v-model.number="age" type="number">
这通常很有用,因为即使在 type="number"
时,HTML
输入元素的值也总会返回字符串。如果这个值无法被 parseFloat()
解析,则会返回原始的值。如果要自动过滤用户输入的首尾空白字符,可以给 v-model
添加 trim
修饰符:
<input v-model.trim="msg">
1.2 自定义指令
为何需要自定义指令?
除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue2.0
中,代码复用和抽象的主要形式是 组件
。然而,有的情况下,你仍然需要对普通 DOM
元素进行底层操作,这时候就会用到自定义指令。举个聚焦输入框的例子,如下:
当页面加载时,该元素将获得焦点 (注意:autofocus
在移动版 Safari
上不工作)。事实上,只要你在打开这个页面后还没点击过任何内容,这个输入框就应当还是处于聚焦状态。现在让我们用指令来实现这个功能:
//注册一个全局指令focus
Vue.directive("focus", {
//当被绑定的元素插入到DOM中时
inserted: function(el) {
//聚焦元素
el.focus();
}
})
自定义指令用法:
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update
:所在组件的VNode
更新时调用,但是可能发生在其子VNode
更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。- componentUpdated:指令所在组件的
VNode
及其子VNode
全部更新后调用。 unbind
:只调用一次,指令与元素解绑时调用。
接下来我们来看一下钩子函数的参数 (即 el、binding、vnode 和 oldVnode)。 指令钩子函数会被传入以下参数:
el
:指令所绑定的元素,可以用来直接操作 DOM。binding
:一个对象,包含以下 property:name
:指令名,不包括v-
前缀。value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为2
。oldValue
:指令绑定的前一个值,仅在update
和componentUpdated
钩子中可用。无论值是否改变都可用。expression
:字符串形式的指令表达式。例如v-my-directive="1 + 1"
中,表达式为"1 + 1"
。arg
:传给指令的参数,可选。例如v-my-directive:foo
中,参数为"foo"
。modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar
中,修饰符对象为{ foo: true, bar: true }
。
vnode
:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode
:上一个虚拟节点,仅在update
和componentUpdated
钩子中可用。
除了 el
之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset
来进行。 下面通过一个例子来说明:
演示效果如下:
如果想注册局部指令,组件中也接受一个 directives
的选项:
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
1.3 计算属性
1.3.1 基本使用
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message
的翻转字符串。当你想要在模板中多包含此处的翻转字符串时,就会更加难以处理。所以,对于任何复杂逻辑,你都应当使用 计算属性
。基础例子如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>计算属性</title>
</head>
<body>
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
</body>
</html>
<script src="js/vue.js"></script>
<script> let vm = new Vue({ el: "#example", data: { message: "Hello" }, computed: { //计算属性的getter reversedMessage: function() { //this指向vm实例 return this.message.split("").reverse().join(""); } } }); </script>
演示效果如下:
这里我们声明了一个计算属性 reversedMessage
。我们提供的函数将用作 property vm.reversedMessage
的 getter 函数:
console.log(vm.reversedMessage) // => 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'
你可以打开浏览器的控制台,自行修改例子中的 vm
。vm.reversedMessage
的值始终取决于 vm.message
的值。如下图所示:
你可以像绑定普通 property 一样在模板中绑定计算属性。Vue
知道 vm.reversedMessage
依赖于 vm.message
,因此当 vm.message
发生改变时,所有依赖 vm.reversedMessage
的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter
函数是没有副作用 (side effect) 的,这使它更易于测试和理解。
1.3.2 计算属性缓存 vs 方法
你可能已经注意到我们可以通过在表达式中调用方法来达到同样的效果:
<p>Reversed message: "{{ reversedMessage() }}"</p>
js
代码如下:
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message
还没有发生改变,多次访问 reversedMessage
计算属性会立即返回之前的计算结果,而不必再次执行函数。
这也同样意味着下面的计算属性将不再更新,因为 Date.now()
不是响应式依赖:
computed: {
now: function () {
return Date.now()
}
}
相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
1.4 侦听属性及侦听器
1.4.1 基本使用
Vue
提供了一种更通用的方式来观察和响应 Vue
实例上的数据变动:侦听属性
。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch
——特别是如果你之前使用过 AngularJS
。然而,通常更好的做法是使用 计算属性
命令式的 watch
回调。细想一下这个例子:
html
核心代码如下:
<body>
<div id="app">
<div>
<span>姓:</span>
<span>
<input type="text" v-model="xing">
</span>
</div>
<div>
<span>名:</span>
<span>
<input type="text" v-model="ming">
</span>
</div>
<div>全名: {{xingming}}</div>
</div>
</body>
js
核心代码如下:
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
xing: "Amo",
ming: "Xiang",
xingming: "Amo Xiang"
},
//在这添加一个watch属性
watch: {
//watch中的属性 一定是data中已经存在的数据
//这里的xing对应着data中的xing 当data中xing的值发生改变时 会自动触发watch
xing: function(val) {
this.xingming = val + " " + this.ming;
},
//这里的ming对应着data中的ming 当data中ming的值发生改变时 会自动触发watch
ming: function(val) {
this.xingming = this.xing + " " + val;
}
}
});
</script>
演示效果如下:
上面代码是命令式且重复的。将它与计算属性的版本进行比较:
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
xing: "Amo",
ming: "Xiang",
},
computed: {
xingming: function() {
return this.xing + " " + this.ming;
}
}
});
</script>
好得多了,不是吗?虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时 执行异步
或 开销较大
的操作时,这个方式是最有用的。html
结构如下:
<body>
<div id="app">
<span>用户名: </span>
<span>
<!-- 使用修饰符将input事件改为change事件 -->
<input type="text" v-model.lazy="uname">
</span>
<span>{{tip}}</span>
</div>
</body>
js
代码如下:
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
uname: "",
tip: ""
},
methods: {
checkName: function(uname) {
// 调用接口,但是可以使用定时任务的方式模拟接口调用
// 因为定时器内部的this是指向window的 所以这里要使用一个变量来存储this指向的vm实例
let that = this;
setTimeout(function() {
if (uname == "admin") {
that.tip = "用户名已经存在,请更改....";
} else {
that.tip = "用户名可以使用";
}
}, 2000);
}
},
watch: {
uname: function(val) {
this.checkName(val); //调用函数校验用户名的合法性
this.tip = "正在检验用户名是否可用...."
}
}
});
</script>
演示效果如下:
当需要监听一个对象的改变时,普通的 watch
方法无法监听到对象内部属性的改变,只有 data
中的数据才能够监听到变化,此时就需要 deep
属性对对象进行深度监听 请看下面这个例子:html
结构如下:
<body>
<div id="app">
<input type="text" v-model="personInfo.name">
<h3>{{personInfo.name}}</h3>
</div>
</body>
js
代码如下:
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
personInfo: {
name: "Amo",
age: 18,
isBoy: true
}
},
watch: {
personInfo: function(value) {
console.log("监听成功");
}
}
});
</script>
演示效果如下:
从上面的结果我们可以看出,是没有监听成功的,我们只需要将上面 js
代码中 watch
部分更改一下即可,如下:
演示效果如下:
1.5 过滤器
所谓的 过滤器
,大家可以这样理解类似于我们家里的 净水器
,净水器
是按对 水
的使用要求对水质
进行深度过滤、净化处理,Vue
中则是按照对数据
的使用要求进行过滤处理,其本质就是对数据的处理,而在 Vue
中数据都是绑定到 Vue
实例的 data
属性中,即过滤器处理 data
属性中的数据然后将其返回。
1.5.1 基本使用
Vue.js
允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值 和 v-bind
表达式 (后者从 2.1.0+ 开始支持)。过滤器
应该被添加在 JavaScript
表达式的尾部,由 管道
符号指示:
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
你可以在一个组件的选项中定义本地的过滤器:
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
//return必须写,charAt(0):获取字符串中第一个字符
//toUpperCase():将小写字母转换为大写字母
//slice(1): 表示字符串从索引1开始截取到最后的子串
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
或者在创建 Vue
实例之前全局定义过滤器:
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
// ...
})
注意:
- 当全局过滤器和局部过滤器重名时,会采用局部过滤器。
- 全局注册时是
filter
,没有s
的。而局部过滤器是filters
,是有s
的
下面这个例子用到了 capitalize
过滤器:
通过上述 gif
演示的效果图,大家可以看出 过滤器
不改变真正的 data
,而只是改变渲染的结果,并返回过滤后的版本。核心代码如下:
过滤器函数总接收表达式的值(之前的操作链的结果)作为第一个参数。在上述例子中,capitalize
过滤器函数将会收到 message
的值作为第一个参数。过滤器可以串联:
{{ message | filterA | filterB }}
在这个例子中,filterA
被定义为接收单个参数的过滤器函数,表达式 message
的值将作为参数传入到函数中。然后继续调用同样被定义为接收单个参数的过滤器函数 filterB
,将 filterA
的结果传递到 filterB
中。过滤器是 JavaScript
函数,因此可以接收参数:
{{ message | filterA('arg1', arg2) }}
这里,filterA
被定义为接收三个参数的过滤器函数。其中 message
的值作为第一个参数,普通字符串 'arg1'
作为第二个参数,表达式 arg2
的值作为第三个参数。格式化日期例子,核心代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<div>{{date | format('yyyy-MM-dd hh:mm:ss')}}</div>
</div>
<script type="text/javascript" src="js/vue.js"></script>
<script type="text/javascript"> Vue.filter('format', function(value, arg) { function dateFormat(date, format) { if (typeof date === "string") { var mts = date.match(/(\/Date\((\d+)\)\/)/); if (mts && mts.length >= 3) { date = parseInt(mts[2]); } } date = new Date(date); if (!date || date.toUTCString() == "Invalid Date") { return ""; } var map = { "M": date.getMonth() + 1, //月份 "d": date.getDate(), //日 "h": date.getHours(), //小时 "m": date.getMinutes(), //分 "s": date.getSeconds(), //秒 "q": Math.floor((date.getMonth() + 3) / 3), //季度 "S": date.getMilliseconds() //毫秒 }; format = format.replace(/([yMdhmsqS])+/g, function(all, t) { var v = map[t]; if (v !== undefined) { if (all.length > 1) { v = '0' + v; v = v.substr(v.length - 2); } return v; } else if (t === 'y') { return (date.getFullYear() + '').substr(4 - all.length); } return all; }); return format; } return dateFormat(value, arg); }) var vm = new Vue({ el: '#app', data: { date: new Date() } }); </script>
</body>
</html>
这里,format
被定义为接收二个参数的过滤器函数。其中 date
的值作为第一个参数,普通字符串 'yyyy-MM-dd hh:mm:ss'
作为第二个参数。程序结果为:
1.6 音乐播放器
1.6.1 功能演示
音乐播放器小案例.mp4
1.6.2 前置知识
在 HTML5
中,新增了两个元素——video
元素与 audio
元素。video
元素专门用来播放网络上的视频或电影,而 audio
元素专门用来播放网络上的音频数据。使用这两个元素,就不再需要使用其他任何插件了,只要使用支持 HTML5
的浏览器就可以了。这两个元素的使用方法都很简单,本文使用到的是audio
,所以这里 audio
元素为例,只要把播放音频的 URL
给指定元素的 src
属性就可以了,audio
元素使用方法如下所示。
<audio src="./Music/麦小兜-下山.flac">您的浏览器不支持audio元素!</audio>
通过这种方法,可以把指定的音频数据直接嵌入在网页上,其中 您的浏览器不支持audio元素!
为在不支持 audio
元素的浏览器中所显示的替代文字。本案例用到的属性及事件介绍如下:
src
属性用于指定媒体数据的URL
地址。autoplay
属性用于指定媒体是否在页面加载后自动播放。使用方法如下:<audio src="./Music/汪苏泷-小星星.flac" autoplay></audio>
controls
属性指定是否为视频或音频添加浏览器自带的播放用的控制条。控制条中具有播放、暂停等按钮。使用方法如下:<audio src="./Music/汪苏泷-小星星.flac" controls></audio>
ended
事件:播放由于媒介结束而停止
1.6.3 示例代码
html
结构如下:
<body>
<div id="app">
<audio :src="currentSrc" controls autoplay @ended="handleEnded"></audio>
<ul>
<li :class="{active:index===currentIndex}" v-for="(item,index) in musicData" :key="item.id" @click="handle(item,index)">
<h2>{{item.id}}--歌名:{{item.name}}</h2>
<p>{{item.author}}</p>
</li>
</ul>
<button @click="handlePre">上一首</button>
<button @click="handleNext">下一首</button>
</div>
</body>
js
代码如下:
<script>
const musicData = [{
id: 1,
name: '下山',
author: '麦小兜',
songSrc: './Music/麦小兜-下山.flac'
}, {
id: 2,
name: 'Please Dont Go',
author: 'Joel Adams',
songSrc: './Music/Joel Adams - Please Dont Go.mp3'
}, {
id: 3,
name: '小星星',
author: '汪苏泷',
songSrc: './Music/汪苏泷-小星星.flac'
}, {
id: 4,
name: '芒种',
author: '赵方婧',
songSrc: './Music/音阙诗听,赵方婧-芒种.flac'
}];
let vm = new Vue({
el: "#app",
data: {
musicData,
currentSrc: "./Music/麦小兜-下山.flac",
currentIndex: 0
},
methods: {
handle(item, index) {
this.currentSrc = item.songSrc;
this.currentIndex = index;
},
handleEnded() {
this.handleNext();
},
handlePre() {
this.currentIndex--;
if (this.currentIndex < 0) {
this.currentIndex = this.musicData.length - 1;
}
this.currentSrc = this.musicData[this.currentIndex].songSrc;
},
handleNext() {
this.currentIndex++;
if (this.currentIndex === this.musicData.length) {
this.currentIndex = 0;
}
this.currentSrc = this.musicData[this.currentIndex].songSrc;
}
}
});
</script>
2. 综合案例
2.1 前置知识-数组
数组
是 JavaScript
中的一种复合数据类型。变量中保存单个数据,而数组中则保存的是多个数据的集合。数组
与 变量
的比较效果如下图所示:
2.1.1 概念
数组 (Array)
就是一组数据的集合。数组是 JavaScript
中用来存储和操作有序数据集的数据结构。可以把数组看作一个单行表格,该表格的每一个单元格中都可以存储一个数据,即一个数组中可以包含多个元素,如下图所示。
由于 JavaScript
是一种弱类型的语言,所以在数组中的每个元素的类型可以是不同的。数组中的元素类型可以是 数值型/字符串型/布尔型
等,甚至也可以是一个 数组
。
2.1.2 元素
数组是数组元素的集合,在上图中,每个单元格里所存放的就是数组元素。例如,一个班级的所有学生就可以看作是一个数组,每一位学生都是数组中的一个元素。再比如,一个酒店的所有房间就相当于一个数组,每一个房间都是这个数组中的一个元素。
每个数组元素都有一个 索引号
(数组的下标),通过 索引号
可以方便地引用数组元素。数组的下标从 0
开始编号,例如,第一个数组元素的下标是 0
,第二个数组元素的下标是 1
,以此类推。
2.1.3 定义数组
在 JavaScript
中数组也是一种对象,这种对象被称为数组对象。因此在定义数组时,也可以使用 构造函数
。JavaScript
中定义数组的方法主要有4种。如下所示:
<script>
// 第一种定义数组的方式:
let arr = new Array(); //定义一个空数组
arr[0] = "Amo"; //向数组中添加第一个数组元素
arr[1] = "Paul"; //向数组中添加第二个数组元素
arr[2] = "Jerry"; //向数组中添加第三个数组元素
console.log(arr);
// 在上述代码中定义了一个空数组,此时数组中元素的个数为0。在为数组的元素赋值后,数组中才有了数组元素。
// 第二种定义数组的方式:在定义数组的同时可以指定数组元素的个数。此时并没有为数组元素赋值,所有数组元素的值都是undefined。
let arr2 = new Array(3);
arr2[0] = 1; //为第一个数组元素赋值
arr2[1] = 2; //为第二个数组元素赋值
arr2[2] = 3; //为第三个数组元素赋值
console.log(arr2);
// 第三种定义数组的方式: 在定义数组的同时可以直接给出数组元素的值。此时数组的长度就是在括号中给出的数组元素的个数。
let arr3 = new Array("电商172", "电商173", "市营171"); //定义一个包含3个元素的数组
console.log(arr3);
// 第四种定义数组的方式: 直接将数组元素放在一个中括号中,元素与元素之间用逗号分隔。
let arr4 = ["Python高级", "Vue框架技术", "JavaSE基础"]; //直接定义一个包含3个元素的数组
console.log(arr4);
</script>
2.1.4 数组元素的输入和输出
数组是一系列元素的集合,在对数组进行操作时,实际上是对数组元素进行输入和输出的操作。数组元素的 输入
即为数组中的元素 进行赋值
,数组元素的 输出
即获取 数组中元素的值并输出
,示例代码如下:
<script>
console.log("-------------数组对象的输入如下:-------------");
//1.在定义数组对象时直接输入数组元素(前提:确定数组元素的情况下)
let arr1 = new Array("a", "b", "c", "d", "e");
//2.使用下标赋值或者是修改数组中的元素
let arr2 = new Array(3);
arr1[0] = "f"; //为下标为1的数组元素赋值
arr1[0] = "g"; //修改下标为1的数组元素的值为g
//3.利用for语句向数组对象中输入数组元素(批量)
let num = 7;
let arr3 = new Array();
for (let i = 0; i < num; i++) {
arr3[i] = i;
}
console.log("-------------数组对象的输出如下:-------------");
//1.用下标获取指定元素值 获取arr1数组中的'd'
console.log(arr1[3]); //d
let str = "";
//2.用for语句获取数组中的元素值
for (let i = 0; i < 5; i++) {
//将各个数组连接在一起
str += arr1[i];
}
console.log(str); //gbcde
//3.用数组对象名输出所有元素值
console.log(arr1);
</script>
2.1.5 数组元素的添加和删除
在定义数组时虽然已经设置了数组元素的个数,但是该数组的元素个数并不是固定的。可以通过添加数组元素的方法来增加数组元素的个数。添加数组元素的方法非常简单,只要对新的数组元素进行赋值就可以了。
例如,定义一个包含两个元素的数组,然后为数组添加3个元素,最后输出数组中的所有元素值,代码如下:
<script>
let arr1 = new Array("Amo", "Jerry");
console.log(arr1);
arr1[2] = "Paul"; //添加新的数组元素
arr1[3] = "Ben"; //添加新的数组元素
arr1[4] = "Jason"; //添加新的数组元素
console.log(arr1);
</script>
运行结果为:
另外,还可以对已经存在的数组元素进行重新赋值。例如,定义一个包含两个元素的数组,将第二个数组元素进行重新赋值并输出数组中的所有元素值,代码如下:
<script>
let arr = new Array("Vue框架技术", "Python基础"); //定义数组
console.log(arr); //输出数组
arr[1] = "JavaSE基础"; //为下标为1的数组元素重新赋值
console.log(arr); //输出重新赋值后的新数组
</script>
运行结果为:
使用 delete
运算符可以删除数组元素的值,但是只能将该元素恢复为未赋值的状态,即 undefined
,而不能真正地删除一个数组元素,数组中的元素个数也不会减少。例如,定义一个包含 3个
元素的数组,然后应用 delete
运算符删除 下标为1
的数组元素,最后输出数组中的所有元素值。代码如下:
<script>
let arr = new Array("Vue框架技术", "Python高级", "JavaSE基础"); //定义数组
console.log(arr);
delete arr[1]; //删除下标为1的数组元素
console.log(arr); //输出删除元素后的数组
console.log(arr[1]);
</script>
运行结果为:
注意:应用 delete
运算符删除数组元素之前和删除数组元素之后,元素个数并没有改变,改变的只是被删除的数组元素的值,该值变为 undefined
。
2.1.6 length属性
该属性用于返回 数组的长度
。例如,获取已创建的数组对象的长度。代码如下:
<script>
let arr = new Array(1, 2, 3, 4, 5, 6, 7, 8); //定义数组
console.log(arr.length); //输出数组的长度 8
</script>
例如,增加已有数组的长度。代码如下:
<script>
let arr = new Array(1, 2, 3, 4, 5, 6, 7, 8); //定义数组
arr[arr.length] = arr.length + 1; //为新的数组元素赋值
console.log(arr.length); //输出数组的新长度 9
</script>
将 福建/江西/四川
三省的省份名称、省会城市名称以及 3个
城市的旅游景点分别定义在数组中,应用 for循环语句
和 数组的length
属性,将省份、省会以及旅游景点循环输出在表格中。代码如下:
<table cellspacing="1" bgcolor="#CC00FF">
<tr height="30" bgcolor="#FFFFFF">
<td align="center" width="50">序号</td>
<td align="center" width="100">省份</td>
<td align="center" width="100">省会</td>
<td align="center" width="260">旅游景点</td>
</tr>
<script type="text/javascript">
let province = new Array("福建省", "江西省", "四川省"); //定义省份数组
let city = new Array("福州市", "南昌市", "成都市"); //定义省会数组
let tourist = new Array("三坊七巷 福州国家森林公园 金山寺", "滕王阁 鄱阳湖 凤凰沟风景区",
"天府广场 峨眉金顶 乐山大佛"); //定义旅游景点数组
for (let i = 0; i < province.length; i++) { //定义for循环语句
document.write("<tr height=26 bgcolor='#FFFFFF'>"); //输出<tr>开始标记
document.write("<td align='center'>" + (i + 1) + "</td>"); //输出序号
document.write("<td align='center'>" + province[i] + "</td>"); //输出省份名称
document.write("<td align='center'>" + city[i] + "</td>"); //输出省会名称
document.write("<td align='center'>" + tourist[i] + "</td>"); //输出旅游景点
document.write("</tr>"); //输出</tr>结束标记
}
</script>
</table>
运行结果如下图所示。
2.1.7 prototype属性
该属性可以为数组对象添加自定义的属性或方法。
Array.prototype.name=value
例如,利用 prototype
属性自定义一个方法,用于显示数组中的最后一个元素。代码如下:
<script>
Array.prototype.outLast = function() { //自定义outLast()方法
console.log(this[this.length - 1]); //输出数组中最后一个元素
}
let arr = new Array(1, 2, 3, 4, 5, 6, 7, 8); //定义数组
arr.outLast(); //调用自定义方法 8
let arr2 = new Array(1, 2, 3, 4, 5, 6, 7, 8, 9); //定义数组
arr2.outLast(); //调用自定义方法 9
</script>
2.1.8 数组的添加和删除
数组的添加和删除可以使用 concat()、push()、unshift()、pop()、shift()和splice()
方法实现。如下:
<script>
//1.concat()方法: 该方法用于将其他数组连接到当前数组的末尾
let arr1 = [1, 2];
let arr2 = [3, 4];
let newArr = arr1.concat(arr2, 5, 6);
console.log(newArr); //[1, 2, 3, 4, 5, 6]
//2.push()方法: 该方法向数组的末尾添加一个或多个元素,并返回添加后的数组长度。
let arr3 = [1, 2];
console.log(arr3); // [1, 2]
console.log(arr3.push(3, 4)); //4
console.log(arr3); //[1, 2, 3, 4]
//3.unshift()方法: 该方法向数组的开头添加一个或多个元素。
let arr4 = [1, 2];
console.log(arr4); // [1, 2]
console.log(arr4.unshift(3, 4)); //4
console.log(arr4); //[3, 4, 1, 2]
//4.pop()方法: 该方法用于把数组中的最后一个元素从数组中删除,并返回删除元素的值。
let arr5 = [1, 2, 3, 4, 5, 6];
console.log(arr5); // [1, 2, 3, 4, 5, 6]
console.log(arr5.pop()); //6
console.log(arr5); //[1, 2, 3, 4, 5]
//5.shift()方法: 该方法用于把数组中的第一个元素从数组中删除,并返回删除元素的值。
let arr6 = [1, 2, 3, 4, 5, 6];
console.log(arr6); // [1, 2, 3, 4, 5, 6]
console.log(arr6.shift()); //1
console.log(arr6); //[2, 3, 4, 5, 6]
//6.splice()方法: 可以删除数组中指定位置的元素,还可以向数组中的指定位置添加新元素。
// arrayObject.splice(start,length,element1,element2,…)
// 1.arrayObject:必选项,数组名称。
// 2.start:必选项,指定要删除数组元素的开始位置,即数组的下标。
// 3.length:可选项,指定删除数组元素的个数。如果未设置该参数,则删除从start开始到原数组末尾的所有元素。
// 4.element:可选项,要添加到数组的新元素。
let arr7 = new Array("a", "b", "c", "d"); //定义数组
arr7.splice(1); //删除第2个元素和之后的所有元素
document.write(arr7 + "<br>"); //输出删除后的数组
let arr8 = new Array("a", "b", "c", "d"); //定义数组
arr8.splice(1, 2); //删除数组中的第2个和第3个元素
document.write(arr8 + "<br>"); //输出删除后的数组
let arr9 = new Array("a", "b", "c", "d"); //定义数组
arr9.splice(1, 2, "e", "f"); //删除数组中的第2个和第3个元素,并添加新元素
document.write(arr9 + "<br>"); //输出删除后的数组
let arr10 = new Array("a", "b", "c", "d"); //定义数组
arr10.splice(1, 0, "e", "f"); //在第2个元素前添加新元素
document.write(arr10 + "<br>"); //输出删除后的数组
</script>
2.1.9 设置数组的排列顺序
将数组中的元素按照指定的顺序进行排列可以通过 reverse()
和 sort()
方法实现。如下:
<script>
//1.reverse()方法: 该方法用于颠倒数组中元素的顺序
let arr1 = new Array("Amo", "Jerry", "Paul");
console.log(arr1); //["Amo", "Jerry", "Paul"]
arr1.reverse();
console.log(arr1); // ["Paul", "Jerry", "Amo"]
//2.sort()方法: 该方法用于对数组的元素进行排序
let arr2 = new Array("HTML", "CSS", "JavaScript");
console.log(arr2); //["HTML", "CSS", "JavaScript"]
arr2.sort();
console.log(arr2); //["CSS", "HTML", "JavaScript"]
//定义一个包含4个元素的数组,将数组中的元素按从小到大的顺序进行输出
let arr3 = new Array(9, 6, 10, 5); //定义数组
console.log(arr3); //输出原数组
function ascOrder(x, y) { //定义比较函数
if (x > y) { //如果第一个参数值大于第二个参数值
return 1; //返回1
} else {
return -1; //返回-1
}
}
arr3.sort(ascOrder); //对数组进行排序
console.log(arr3); //输出排序后的数组
</script>
2.1.10 获取某段数组元素
获取数组中的某段数组元素主要用 slice()
方法实现。slice()方法可从已有的数组中返回选定的元素。
arrayObject.slice(start,end)
参数说明:
start
:必选项。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1
指最后一个元素,-2
指倒数第二个元素,以此类推。end
:可选项。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从start
到数组结束的所有元素。如果这个参数是负数,那么它将从数组尾部开始算起。- 返回值:返回截取后的数组元素,该方法返回的数据中不包括
end
索引所对应的数据。
例如,获取指定数组中某段数组元素。代码如下:
<script>
let arr = new Array("a", "b", "c", "d", "e", "f"); //定义数组
document.write("原数组:" + arr + "<br>"); //输出原数组
//输出截取后的数组
document.write("获取数组中第3个元素后的所有元素:" + arr.slice(2) + "<br>");
document.write("获取数组中第2个到第5个元素:" + arr.slice(1, 5) + "<br>"); //输出截取后的数组
document.write("获取数组中倒数第2个元素后的所有元素:" + arr.slice(-2)); //输出截取后的数组
</script>
运行程序,会将原数组以及截取数组中元素后的数据输出,运行结果如下图所示。
2.1.11 数组转换成字符串
将数组转换成字符串主要通过 toString()
、toLocaleString()
和 join()
方法实现。如下:
<script>
//1.toString()方法: 该方法可把数组转换为字符串,并返回结果。
let arr1 = new Array(1, 2, 3);
console.log(Array.isArray(arr1)); //true
console.log(Array.isArray(arr1.toString())); //false
console.log(arr1.toString());
//2.该方法将数组转换成本地字符串。
console.log(arr1.toLocaleString());
//3.join()方法:
let arr2 = new Array(1, 2, 3);
console.log(arr2.join()); //1,2,3
console.log(arr2.join("*")); //1*2*3
</script>