Vue Day 04——计算属性
概述
- 什么是计算属性?
- 计算属性的复杂操作
- 计算属性的setter和getter
- 计算属性的缓存
- let和var的区别
- 对象自变量-增强写法
4.1. 什么是计算属性?
在模板中可以直接通过插值语法显示一些data中的数据。
但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示
- 比如我们有
firstName
和lastName
两个变量,我们需要显示完整的名称。 - 但是如果多个地方都需要显示完整的名称,我们就需要写多个
{{firstName}}
{{lastName}}
我们可以将上面的代码换成计算属性:
OK,我们发现计算属性是写在实例的computed选项中的。
<div id="app">
<h2>{{firstname+' '+lastname}}</h2>
<h2>{{getfullName()}}</h2>
<h2>{{fullName}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstname: 'Lebanon',
lastname: 'james'
},
computed: { //04计算属性,定义的函数,尽量函数名字像属性
fullName: function () {
return this.firstname + ' ' + this.lastname
}
},
methods: {
getfullName: function () {
return this.firstname + ' ' + this.lastname
}
}
})
// const 基本使用,保持不被修改的性质,定义标志符必须赋值,
// 常量指向的对象不能被修改,但是可以改变对象内部的属性
//
</script>
4.2. 计算属性的复杂操作
计算属性中也可以进行一些更加复杂的操作,比如下面的例子:
<div id="app">
<h2>总价格: {{totalPrice}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
books: [
{
id: 110,name: 'Unix编程艺术', price: 119
},
{
id: 111,name: '代码大全', price: 105
},
{
id: 112,name: '深入理解计算机原理', price: 139
},
{
id: 113,name: '现代操作系统', price: 89
},
]
},
computed: {
totalPrice: function () {
//fiter
let result=0;
for(let i=0;i<this.books.length;i++){
result += this.books[i].price
}
return result
// for(let i in this.books){
// this.books[i]
// }
//
// for(let book of this.books){
//
// }
}
}
})
</script>
4.3. 计算属性的setter和getter
每个计算属性都包含一个getter和一个setter
- 在上面的例子中,我们只是使用getter来读取。
- 在某些情况下,你也可以提供一个setter方法(不常用)。
- 在需要写setter的时候,代码如下:
<div id="app">
<h2>{{fullName}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstname: 'kobe',
lastname: 'Bryant'
},
computed: {
// fullName: function () {
// return this.firstname +' '+ this.lastname
// }计算属性一般没有set方法,只读属性
fullName: {
// set: function (newValue) {//实际上就是构造set
// console.log('----',newValue);
// const names = newValue.split(' ');
// this.firstname = names[0];
// this.lastname = names[1];
// },
get: function () {
return this.firstname + ' ' + this.lastname
}
},
//下面是计算属性get方法的简写
// fullName: function () {
// return this.firstname + ' ' + this.lastname
// }
}
})
</script>
4.4. 计算属性的缓存
我们可能会考虑这样的一个问题:
- methods和computed看起来都可以实现我们的功能,
- 那么为什么还要多一个计算属性这个东西呢?
- 原因:计算属性会进行缓存,如果多次使用时,计算属性只会调用一次。
我们来看下面的代码:
<div id="app">
<!-- 直接拼接-->
<!-- 利用方法,调用多少次,方法就执行多少次-->
<h2>{{getFullname()}}</h2>
<!-- 利用计算属性,然而计算属性中的方法无论调用多少次,都执行一次-->
<h2>{{fullName}}</h2>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
firstname: 'Kode',
lastname: 'Brody'
},
computed: {
fullName: function () {
console.log('---');
return this.firstname +' ' + this.lastname
}
},
methods: {
getFullname: function () {
console.log('---');
return this.firstname +' ' + this.lastname
}
}
})
</script>
4.5. let和var
ES6 新增了let
命令,用来声明局部变量。它的用法类似于var
,但是所声明的变量,只在let
命令所在的代码块内有效,而且有暂时性死区的约束。
先看个var
的常见变量提升的面试题目:
题目1:
var a = 99; // 全局变量a
f(); // f是函数,虽然定义在调用的后面,但是函数声明会提升到作用域的顶部。
console.log(a); // a=>99, 此时是全局变量的a
function f() {
console.log(a); // 当前的a变量是下面变量a声明提升后,默认值undefined
var a = 10;
console.log(a); // a => 10
}
// 输出结果:
undefined
10
99
4.5.1. ES6可以用let定义块级作用域变量
在ES6之前,我们都是用var来声明变量,而且JS只有函数作用域和全局作用域,没有块级作用域,所以{}
限定不了var声明变量的访问范围。
例如:
{
var i = 9;
}
console.log(i); // 9
ES6新增的let
,可以声明块级作用域的变量。
{
let i = 9; // i变量只在 花括号内有效!!!
}
console.log(i); // Uncaught ReferenceError: i is not defined
4.5.2. let 配合for循环的独特应用
let
非常适合用于 for
循环内部的块级作用域。JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,用let声明的变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。看一个常见的面试题目:
for (var i = 0; i <10; i++) {
setTimeout(function() { // 同步注册回调函数到 异步的 宏任务队列。
console.log(i); // 执行此代码时,同步代码for循环已经执行完成
}, 0);
}
// 输出结果
10 共10个
// 这里面的知识点: JS的事件循环机制,setTimeout的机制等
如果把 var
改成 let
声明:
// i虽然在全局作用域声明,但是在for循环体局部作用域中使用的时候,变量会被固定,不受外界干扰。
for (let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i); // i 是循环体内局部作用域,不受外界影响。
}, 0);
}
// 输出结果:
0 1 2 3 4 5 6 7 8 9
4.5.3. let没有变量提升与暂时性死区
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
用let
声明的变量,不存在变量提升。而且要求必须 等let
声明语句执行完之后,变量才能使用,不然会报Uncaught ReferenceError
错误。
例如:
console.log(aicoder); // 错误:Uncaught ReferenceError ...
let aicoder = 'aicoder.com';
// 这里就可以安全使用aicoder
4.5.4. let变量不能重复声明
let不允许在相同作用域内,重复声明同一个变量。否则报错:Uncaught SyntaxError: Identifier 'XXX' has already been declared
例如:
let a = 0;
let a = 'sss';
// Uncaught SyntaxError: Identifier 'a' has already been declared
ES6的let让js真正拥有了块级作用域,也是向这更安全更规范的路走,虽然加了很多约束,但是都是为了让我们更安全的使用和写代码。
4.5.5. 实际自己演练
详情则看代码
<div id="app">
{{message}}
</div>
<button>按钮3</button>
<button>按钮3</button>
<button>按钮3</button>
<button>按钮3</button>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
});
//ES5之前if和for没有块级作用域的概念,所以主要结束function的作用图
//但是在
//1.变量作用域 var 不存在块级作用域的限制(if的块级没有作用域,for的块级也没有作用域
//使用 闭包可以解决for块级作用域的问题,但是实际上闭包相当于5个不同函数
var btns = document.getElementsByTagName('button');
for(var i=0; i<btns.length;i++){
(function (i) {
btns[i].addEventListener('click', function () {
console.log('第'+ i+ '个按钮被点击');
})
})(i)
// btns[i].addEventListener('click', function () {
// console.log('第'+ i+ '个按钮被点击');
// })
}
//在ES6 的let中 不需要使用闭包,使用let,具有自己的作用域,
const btn = document.getElementsByTagName('button');
for(let i=0;i<btn.length;i++){
btn[i].addEventListener('click', function () {
console.log('第'+ i + '个按钮被点击');
})
}
</script>
4.6. 对象自变量-增强写法
代码详述:
<script>
//const obj={} 其中{}就是自变量
// const obj = {
// name: 'whil',
// age: 12,
// run: function () {
// console.log('dddd')
// }
// }
//属性的增强写法
const name = 'whe';
const age = 12;
const height = 1.88;
// ES5写法
// const obj = {
// name: name,
// age: age,
// height: height
// }
// S 6增强写法
// const obj = {
// name,
// age,
// height,
// }
//2.函数的增强写法
//ES 5
// const obj = {
// run: function () {
//
// }
// }
// ES 6增强写法
// const obj = {
// run(){
//
// }
// }
</script>
12;
const height = 1.88;
// ES5写法
// const obj = {
// name: name,
// age: age,
// height: height
// }
// S 6增强写法
// const obj = {
// name,
// age,
// height,
// }
//2.函数的增强写法
//ES 5
// const obj = {
// run: function () {
//
// }
// }
// ES 6增强写法
// const obj = {
// run(){
//
// }
// }
</script>