مقدمه ویژگی‌های Computed

همانطور که یاد گرفتیم، syntaxهای فریم ورک Vue.js بسیار ساده و راحت هستند. اما این عبارتها تنها برای اجرای عملیات‌های ساده مورد استفاده قرار می‌گیرند. بنابراین استفاده از دستورهای پیچیده و ترکیب آنها با یکدیگر و قالب قبلی ممکن است کار شما را سخت تر کند. به کد زیر توجه کنید:

<div id="example">
	{{ message.split('').reverse().join('') }}
</div>

با این روش قالب نوشتاری شما قابل فهم نیست. چرا که فهمیدن آن نیاز به review دوباره دارد تا بدانید که در کدها، متغیر message معکوس می‌شود. این موضوع بسیار غیر قابل فهم و سخت است. برای ساده سازی این عبارت پیچیده باید از ویژگی Computed استفاده کرد. جهت تفهیم این موضوع مثال ساده زیر را بررسی می‌کنیم:

<div id="example">
	<p>متن اصلی پیام: {{ message }}</p>
	<p>متن پیام معکوس شده: {{ reversedMessage }}</p>
</div>

var vm= new Vue({
	el: '#example',
	data: {
		message:  'Hello Roxo.ir'
	},
	computed: {
		// گیرنده Computed
		reversedMessage: function(){
			return this.message.split('').reverse().join('')
		}
	}
})

در مثال بالا یک تابع محاسباتی (Computed) با عنوان reservedMessage به کدهای خود اضافه کردیم. تابع تعریفی در این ویژگی به فرمت vm.reservedMessage قابل دسترس خواهد بود. به مثال‌های فوق توجه کنید:

console.log(vm.reversedMessage) // -> com.levaraltahgaf olleH
vm.message= Goodbye
console.log(vm.reversedMessage) // -> eybdooG

console را باز می کنیم و داده های خود را با متغیر message به گیرنده‌ی computed فرستادیم. در نهایت جواب برای متغیر message برابر Goodbye و برای کل تابع reversedMessage برابر eybdooG می‌باشد. همینطور که در جریانید، با تغییر message داده موجود در بخش reversedMessage تغییر خواهد کرد. بنابراین به صورت کاملا تطابقی هرگونه به اصطلاح Binding‌ای در ویژگی‌های computed آپدیت یا بروزرسانی خواهد شد.

تفاوت بین ویژگی computed و متدها (Computed vs Methods)

ممکن است برای شما این سوال بوجود بیاد که می‌توان ویژگی computed را با استفاده از متدها پیاده‌سازی کرد. پاسخ "بله” است. در ادامه تفاوت‌های بین دو این Computed و Methods را مرور خواهیم کرد. به مثال زیر توجه کنید:

<p> متن پیام معکوس شده: {{ reversedMessage }}</p>

var vm = new Vue{
	data:{
		message: "Hello FaghatLaravel.com"
	}
	methods: {
		reversedMessage: function(){
			return this.message.split('').reverse().join('')
		}
	}
}

همانطور که مشاهده کردید می‌توان بجای استفاده از ویژگی computed، از یک method و function همراه آن استفاده کرد و نتایج یکسانی را داشت. اما آنچه که تفاوت این روش ها را مشخص می‌کند، در بخش cache (حافظه نهان) است. یک ویژگی Computed تنها زمانی شروع به پردازش مجدد می‌کند که مقدار متغیرهای وابسته به آن تغییر می‌کرد. این مورد به این معنی است که اگر message در مثال بالا تغییر نکند، مقدار reversedMessage برابر همان مقدار قبلی است و هیچگونه اجرای مجددی برای ویژگی Computed رخ نمی‌دهد.

به عنوان مثال مقدار computed زیر هیچگاه تغییری نمی‌کند، زیرا مقدار Date.now() همواره ثابت می‌باشد و هیچگونه واکنشی در آن امکان‌پذیر نیست.

computed: {
	now: function(){
		return Date.now()
	}
}

اما در methodها این صورت نیست، بلکه برنامه همواره پس از هربار رندر شدن، اجرا می‌شود.

تفاوت بین ویژگی‌ Computed و Watched

فریم ورک Vue.js یک راه دیگری برای مشاهده و واکنش به تغییرات داده ها را، در اختیار توسعه دهنده ها قرار داده است که به آن ویژگی Watch گفته می‌شود. زمانی که برخی از داده‌ها که به دیگر داده‌ها وابسته هستند، نیاز به تغییرات داشته باشند، به ویژگی Watch نیاز داریم. بخصوص اگر Backend وب سایت شما با Angular انگولار کنترل شود. هر چند استفاده از ویژگی Computed در بسیاری از موارد توصیه می‌شود. به مثال زیر توجه کنید:

<div id="laravelApp"> {{ fullName }} </div>

var vm = new Vue({
	el: '#laravelApp'
	data: {
		firstName: 'Amin',
		lastName: 'Jafari',
		fullName: 'AminJafari'
	},
	watch:{
		firstName: function(val){
			this.fullName = val + ' ' + this.lastName
		}
		lastName: function(val){
			this.fullName = this.firstName + ' ' + val
		}
	}
}})

همانطور که تمرین کردیم، در ویژگی Watch کد بالا یک مقداری تکراری وجود دارد. حال کد بالا را با کد زیر مقایسه کنید که از ویژگی Computed در آن استفاده شده است:

<div id="laravelApp"> {{ fullName }} </div>

var vm = new Vue({
	el: '#laravelApp'
	data: {
		firstName: 'Amin',
		lastName: 'Jafari',
	},
	computed:{
		fullName: function(){
			return this.firstName + ' ' + this.lastName
		}
	}
}})

کدام بهتر است؟ قطعا پاسخ شما استفاده از Computed است که پاسخ درستی‌ست.

Setter ویژگی Computed یا Computed Setter

Computed به صورت پیش‌فرض دریافت‌کننده (getter) است، اما می‌توانیم یک ویژگی محاسباتی جایگزینی (setter) ایجاد کنیم تا در صورت لزوم از آن استفاده کرد. به مثال زیر دقت کنید:

// ...
computed: {
	fullName: {
		// getter
		get: function(){
			return this.fullName + ' ' + this.lastName
		},
		// setter
		set: function(newValue){
			var names= newValue.split(' ')
			this.firstName = names[0]
			this.lastName = names[names.length - 1]
		}
	}
}

بنابراین با دقت به مثال بالا اگر شما دستور vm.fullName = ‘Laravel Tutorials’ را بنویسید، Setter با استخراج vm.firstName و vm.lastName مقادیر جدید را درون firstName و lastName قرار می‌دهد.

ناظر (Watchers)

اگرچه Computed در بسیاری از موارد مفید هستند اما باید در نظر بگیریم بعضی اوقات ممکن است یک ناظر واقعی و ضروری برای برنامه‌ها نیاز باشد. که این ناظر تحت عنوان Watch مطرح است. به همین دلیل یک ویژگی تحت عنوان watch برای فریم ورک Vue.js ایجاد شده است. این ویژگی مانند ویژگی Computed برای حالتی که نیاز به اجرای ناهمزمان برنامه‌ است بسیار مفید می‌باشد. به نمونه‌ کد زیر توجه کنید:

<div id="laravelApp">
	<p>
		پرسیدن یک سوال که جواب بله یا خیر دارد:
		<input v-model = "question">
	</p>
	<p> {{ answer }} </p>
</div>

// تابع _.debouce
// به عنوان یک محدودکننده برای اجرای عملیاتهای محاسباتی سنگین
// مورد استفاده قرار می گیرد که از کتابخانه ی lodash
// فراخوانی می شود. در اینجا ما میخواهیم دسترسی به api
// سایت yesno/wtf/api را 
// محدود کنیم.

<script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://unpkg.com/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
	el: "#laravelApp"
	data: {
		question: '',
		answer: ' تا زمانیکه شما سوالی نپرسیدید، نمیتوانیم به شما پاسخی بدهیم '
	},
	watch: {
		question: function(newQuestion){
			this.answer = 'تا لحظه اتمام تایپ شما، لطفا صبر کنید...'
			this.getAnswer()
		}
	}
	method:{
		getAnswer: _.debounce{
			var vm = this
			if(this.question.indexOf('?') === -1){
				vm.answer = "سوالهای شما باید شامل علامت سوال ؟ باشند"
				return
			}
			vm.answer = 'در حال پاسخگویی'
			axios.get('https://yesno.wtf/api')
				.then(function(response){
					vm.answer = _capitalize(response.data.answer)
				})
				.catch(function(error){
					vm.answer = 'خطا، عدم برقراری ارتباط با Api' + error
				})
		},
		// مدت زمانیکه برای پاسخ باید انتظار کشید
		// تا کاربر تایپ نکند
		500
	}
})
</script>

در این مثال از ویژگی watch برای اجرای یک علمیات ناهمزمان استفاده شد که این عملیات با دسترسی به Api امکان‌پذیر بود. این Api دسترسی ما را به برخی از عملکردها محدود کرد و در نهایت یک وضعیت پایدار را برای پاسخگویی به سیستم ایجاد نمود. هیچ یک از این محدودیت ها و دسترسی ها با استفاده از یک ویژگی Computed امکان‌پذیر نیست. چون با استفاده از ویژگی Computed نظارتی روی سیستم صورت نمی‌گیرد.