برنامه نویسی 382 بازدید

جاوا اسکریپت به عنوان زبان طراحی فرانت‌اند وب، یکی از محبوب‌ترین زبان‌های برنامه‌نویسی دنیا محسوب می‌شود. این محبوبیت در سال‌های اخیر با معرفی واریانت‌های دیگر این زبان از قبیل تایپ اسکریپت و همچنین محیط زمان اجرای Nodejs برای بک‌اند و همچنین انواع مختلف فریمورک‌های فرانت‌اند دوچندان افزایش یافته است. ما در این مطلب از مقالات برنامه‌نویسی بلاگ فرادرس تلاش کرده‌ایم راهنمای جامعی از سؤالات مصاحبه استخدامی برنامه نویس جاوا اسکریپت را گرد هم بیاوریم تا به افرادی که علاقه‌مند به استخدام در چنین مشاغل هستند کمک کرده باشیم، این مصاحبه‌ها را با آمادگی بیشتری سپری کنند.

فهرست مطالب این نوشته پنهان کردن
1. سوالات عمومی
2. پاسخ سوالات

سوالات عمومی

در این بخش سوالات عمومی مرتبط با مصاحبه استخدامی برنامه نویس جاوا اسکریپت را ارائه می‌کنیم.

سوال اول: تفاوت بین undefined و not defined در جاوا اسکریپت چیست؟

سؤال دوم: برای کدام مقدار x نتیجه گزاره‌های زیر یکسان نیست؟

if( x <= 100 ) {...}
if( !(x > 100) ) {...}

سؤال سوم: عیب اعلان مستقیم متدها در اشیای جاوا اسکریپت چیست؟

سؤال چهارم: منظور از کلوژر در جاوا اسکریپت چیست؟ (مثال بزنید)

سؤال پنجم: تابعی به نام mul بنویسید که در زمان فراخوانی با ساختار زیر عملکرد صحیحی داشته باشد.

console.log(mul(2)(3)(4)); // output : 24
console.log(mul(4)(3)(4)); // output : 48

سؤال ششم: چطور یک آرایه جاوا اسکریپت را خالی کنیم؟

برای نمونه چطور می‌توانیم آرایه زیر را خالی کنیم؟

var arrayList = ['a', 'b', 'c', 'd', 'e', 'f'];

سؤال هفتم: آرایه بودن یا نبودن یک شیء را چگونه بررسی کنیم؟

سؤال هشتم: خروجی کد زیر چیست؟

var output = (function(x) {
  delete x;
  return x;
})(0);

console.log(output);

سؤال نهم: خروجی کد زیر چیست؟

var x = 1;
var output = (function() {
  delete x;
  return x;
})();

console.log(output);

سؤال دهم: خروجی کد زیر چیست؟

var x = { foo : 1};
var output = (function() {
  delete x.foo;
  return x.foo;
})();

console.log(output);

سؤال یازدهم: خروجی کد زیر چیست؟

var Employee = {
  company: 'xyz'
}
var emp1 = Object.create(Employee);
delete emp1.company
console.log(emp1.company);

سؤال دوازدهم: منظور از undefined x 1 در جاوا اسکریپت چیست؟

var trees = ["redwood", "bay", "cedar", "oak", "maple"];
delete trees[3];

سؤال سیزدهم: خروجی کد زیر چیست؟

var trees = ["xyz", "xxxx", "test", "ryan", "apple"];
delete trees[3];
console.log(trees.length);

سؤال چهاردهم: خروجی کد زیر چیست؟

var bar = true;
console.log(bar + 0);   
console.log(bar + "xyz");  
console.log(bar + true);  
console.log(bar + false);

سؤال پانزدهم: خروجی کد زیر چیست؟

var z = 1, y = z = typeof y;
console.log(y);

سؤال شانزدهم: خروجی کد زیر چیست؟

// NFE (Named Function Expression)
var foo = function bar() { return 12; };
typeof bar();

سؤال هفدهم (الف): تفاوت بین اعلان کردن یک تابع به روش‌های زیر کدام است؟

var foo = function() {
  // Some code
}
function bar () {
  // Some code
}

سؤال هفدهم (ب): خروجی کد زیر چیست؟

bar();
(function abc(){console.log('something')})();
function bar(){console.log('bar got called')};

سؤال هجدهم: در چه حالتی تعریف تابع در جاوا اسکریپت hoist نمی‌شود؟

سؤال نوزدهم: خروجی کد زیر چه خواهد بود؟

var salary = "1000$";

(function () {
  console.log("Original salary was " + salary);

  var salary = "5000$";

  console.log("My New Salary " + salary);
})();

سؤال بیستم: تفاوت بین typeof و instanceof چیست؟

سؤال بیست و یکم: طول آرایه انجمنی زیر را محاسبه کنید.

var counterArray = {
  A : 3,
  B : 4
};
counterArray["C"] = 1;

سؤال بیست و دوم: تفاوت بین فراخوانی Function, Method و Constructor چیست؟

سؤال بیست و سوم: خروجی کد زیر چه می‌تواند باشد؟

function User(name) {
  this.name = name || "JsGeeks";
}

var person = new User("xyz")["location"] = "USA";
console.log(person);

سؤال بیست و چهارم: سرویس ورکرها چه هستند و چه زمان استفاده می‌شوند؟

سؤال بیست و پنجم: تفاوت بین متد و تابع در جاوا اسکریپت چیست؟

سؤال بیست و ششم: IIFE چیست و چه فایده‌ای دارد؟

سؤال بیست و هفتم: الگوی سینگلتون را در جاوا اسکریپت توضیح دهید.

سؤال بیست و هشتم: روش‌های مختلف ایجاد اشیا در جاوا اسکریپت کدامند؟

سؤال بیست و نهم: تابعی به نام deepClone بنویسید که یک شیء گرفته و کپی آن را بسازد

var newObject = deepClone(obj);

سؤال سی‌ام: بهترین روش برای تشخیص مشخصه شیء undefined در JS کدام است؟

سؤال سی‌ و یکم: تابعی به نام Clone بنویسید که شیئی را گرفته و یک کپی از آن را بدون کپی کردن مشخصه‌های عمیق شیء بسازد.

   var objectLit = {foo : 'Bar'}; 
	var cloneObj = Clone(obj); // Clone is the function which you have to write 
	console.log(cloneObj === Clone(objectLit)); // this should return false
	console.log(cloneObj == Clone(objectLit)); // this should return true

سؤال سی و دوم: promise چیست و چه فایده‌ای دارد؟

سؤال سی و سوم: روش اطمینان از وجود یک کلید در یک شیء جاوا اسکریپت چیست؟

سؤال سی و ‌چهارم: NaN چیست، چرا به آن نیاز داریم و چطور باعث بروز مشکل در صفحه می‌شود؟

سؤال سی و پنجم: باگ کد زیر را تنها با استفاده از ES5 اصلاح کنید

var arr = [10, 32, 65, 2];
for (var i = 0; i < arr.length; i++) {
  setTimeout(function() {
    console.log('The index of this number is: ' + i);
  }, 3000);
}

سؤال سی و ششم: بررسی مقدار یک متغیر در آرایه

سؤال سی و هفتم: بهترین روش برای تشخیص مقدار ارجاعی یک نوع در جاوا اسکریپت کدام است؟

سؤال سی و هشتم: متد Object.create در جاوا اسکریپت چطور عمل می‌کند؟

سؤال سی و نهم: کاربرد توابع سازنده برای ارث‌بری چیست؟

سؤال چهلم: چطور از دستکاری اشیا در جاوا اسکریپت ممانعت کنیم؟

سؤال چهل و یکم: تابع لاگ بنویسید که در لاگ کنسول یک عبارت به ابتدای همه پیام‌ها اضافه کند.

برای نمونه اگر می‌خواهید پیام console.log(“Some message”) را لاگ کنید، خروجی باید به صورت (your message) Some message باشد.

سؤال چهل و دوم: تابعی بنویسید که رشته را به عنوان لفظ یا شیء تست کند.

برای نمونه می‌توانیم با استفاده از لفظ رشته‌ای و یا با استفاده از تابع سازنده رشته یک رشته متنی تولید کنیم.

 // using string literal
 var ltrlStr = "Hi I am string literal";
 // using String constructor function 
 var objStr = new String("Hi I am string object");

سؤال چهل و سوم: کاربرد رایج تابع anonymous در جاوا اسکریپت چیست؟

سؤال چهل و چهارم: چطور یک مقدار پیش‌فرض برای پارامتر تعیین کنیم؟

سؤال چهل و پنجم: کد ادغام دو شیء جاوا اسکریپت به روش دینامیک را بنویسید.

فرض کنید دو شیء مانند زیر دارید:

var person = {
	name : 'John',
	age  : 24
}

var address = {
	addressLine1 : 'Some Location x',
	addressLine2 : 'Some Location y',
	city : 'NewYork'
} 

تابع ادغامی بنویسید که دو شیء را گرفته و مشخصه‌های شیء دوم را به مشخصه‌های شیء اول اضافه کند.

سؤال چهل و ششم: مشخصه غیر شمارشی در جاوا اسکریپت چیست و چطور می‌توان ساخت؟

سؤال چهل و هفتم: منظور از «اتصال تابع» (Function binding) چیست؟

پرسش‌های کدنویسی

  • ارسال مقادیر با ارجاع یا با مقدار؟

درک این که کدام مقادیر باید به شیوه ارجاعی و کدام یک به شیوه مقداری ارسال شوند، برای یک توسعه‌دهنده جاوا اسکریپت حائز اهمیت بالایی است. به یاد داشته باشید که اشیا شامل آرایه‌ها به صورت ارجاعی ارسال می‌شوند، در حالی که رشته‌ها، مقادیر بولی و اعداد به صورت مقداری ارسال می‌شوند.

سؤال چهل‌ و هشتم: خروجی کد زیر چیست؟

var strA = "hi there";
var strB = strA;
strB="bye there!";
console.log (strA)

سؤال چهل ‌و نهم: خروجی کد زیر چیست؟

var objA = {prop1: 42};
var objB = objA; 
objB.prop1 = 90;
console.log(objA) 

سؤال پنجاهم: خروجی کد زیر چیست؟

var objA = {prop1: 42};
var objB = objA;
objB = {};
console.log(objA)

سؤال پنجاه و یکم: خروجی کد زیر چیست؟

var arrA = [0,1,2,3,4,5];
var arrB = arrA;
arrB[0]=42;
console.log(arrA)

سؤال پنجاه و دوم: خروجی کد زیر چیست؟

var arrA = [0,1,2,3,4,5];
var arrB = arrA.slice();
arrB[0]=42;
console.log(arrA)

سؤال پنجاه و سوم: خروجی کد زیر چیست؟

var arrA = [{prop1: "value of array A!!"},  {someProp: "also value of array A!"}, 3,4,5];
var arrB = arrA;
arrB[0].prop1=42;
console.log(arrA);

سؤال پنجاه و چهارم: خروجی کد زیر چیست؟

var arrA = [{prop1: "value of array A!!"}, {someProp: "also value of array A!"},3,4,5];
var arrB = arrA.slice();
arrB[0].prop1=42;
arrB[3] = 20;
console.log(arrA);

پرسش‌های Hoisting

سؤال پنجاه و پنجم: نتیجه دستور console.log(employeeId); چیست؟

  1. Some Value
  2. Undefined
  3. Type Error
  4. ReferenceError: employeeId is not defined

سؤال پنجاه و ششم: خروجی کد زیر چیست؟

console.log(employeeId);
var employeeId = '19000';
  1. Some Value
  2. undefined
  3. Type Error
  4. ReferenceError: employeeId is not defined

سؤال پنجاه و هفتم: خروجی کد زیر چیست؟

var employeeId = '1234abe';
(function(){
	console.log(employeeId);
	var employeeId = '122345';
})();
  1. ‘122345’
  2. undefined
  3. Type Error
  4. ReferenceError: employeeId is not defined

سؤال پنجاه و هشتم: خروجی کد زیر چیست؟

var employeeId = '1234abe';
(function() {
	console.log(employeeId);
	var employeeId = '122345';
	(function() {
		var employeeId = 'abc1234';
	}());
}());
  1. ‘122345’
  2. undefined
  3. ‘1234abe’
  4. ReferenceError: employeeId is not defined

سؤال پنجاه و نهم: خروجی کد زیر چیست؟

(function() {
	console.log(typeof displayFunc);
	var displayFunc = function(){
		console.log("Hi I am inside displayFunc");
	}
}());
  1. undefined
  2. function
  3. ‘Hi I am inside displayFunc’
  4. ReferenceError: displayFunc is not defined

سؤال شصتم: خروجی کد زیر چیست؟

var employeeId = 'abc123';
function foo(){
	employeeId = '123bcd';
	return;
}
foo();
console.log(employeeId);
  1. undefined
  2. ‘123bcd’
  3. ‘abc123’
  4. ReferenceError: employeeId is not defined

سؤال شصت و یکم: خروجی کد زیر چیست؟

var employeeId = 'abc123';

function foo() {
	employeeId = '123bcd';
	return;

	function employeeId() {}
}
foo();
console.log(employeeId);
  1. undefined
  2. ‘123bcd’
  3. ‘abc123’
  4. ReferenceError: employeeId is not defined

سؤال شصت و دوم: خروجی کد زیر چیست؟

var employeeId = 'abc123';

function foo() {
	employeeId();
	return;

	function employeeId() {
		console.log(typeof employeeId);
	}
}
foo();
  1. undefined
  2. function
  3. string
  4. ReferenceError: employeeId is not defined

سؤال شصت و سوم: خروجی کد زیر چیست؟

function foo() {
	employeeId();
	var product = 'Car'; 
	return;

	function employeeId() {
		console.log(product);
	}
}
foo();
  1. undefined
  2. Type Error
  3. ‘Car’
  4. ReferenceError: product is not defined

سؤال شصت و چهارم: خروجی کد زیر چیست؟

(function foo() {
	bar();

	function bar() {
		abc();
		console.log(typeof abc);
	}

	function abc() {
		console.log(typeof bar);
	}
}());
  1. undefined undefined
  2. Type Error
  3. function function
  4. ReferenceError: bar is not defined

سؤال شصت و پنجم: خروجی کد زیر چیست؟

(function() {
	'use strict';

	var person = {
		name: 'John'
	};
	person.salary = '10000$';
	person['country'] = 'USA';

	Object.defineProperty(person, 'phoneNo', {
		value: '8888888888',
		enumerable: true
	})

	console.log(Object.keys(person)); 
})();
  1. Type Error
  2. undefined
  3. [“name”, “salary”, “country”, “phoneNo”]
  4. [“name”, “salary”, “country”]

سؤال شصت و ششم: خروجی کد زیر چیست؟

(function() {
	'use strict';

	var person = {
		name: 'John'
	};
	person.salary = '10000$';
	person['country'] = 'USA';

	Object.defineProperty(person, 'phoneNo', {
		value: '8888888888',
		enumerable: false
	})

	console.log(Object.keys(person)); 
})();
  1. Type Error
  2. undefined
  3. [“name”, “salary”, “country”, “phoneNo”]
  4. [“name”, “salary”, “country”]

سؤال شصت و هفتم: خروجی کد زیر چیست؟

(function() {
	var objA = {
		foo: 'foo',
		bar: 'bar'
	};
	var objB = {
		foo: 'foo',
		bar: 'bar'
	};
	console.log(objA == objB);
	console.log(objA === objB);
}());
  1. false true
  2. false false
  3. true false
  4. true true

سؤال شصت و هشتم: خروجی کد زیر چیست؟

(function() {
	var objA = new Object({foo: "foo"});
	var objB = new Object({foo: "foo"});
	console.log(objA == objB);
	console.log(objA === objB);
}());
  1. false true
  2. false false
  3. true false
  4. true true

سؤال شصت و نهم: خروجی کد زیر چیست؟

(function() {
	var objA = Object.create({
		foo: 'foo'
	});
	var objB = Object.create({
		foo: 'foo'
	});
	console.log(objA == objB);
	console.log(objA === objB);
}());
  1. false true
  2. false false
  3. true false
  4. true true

سؤال هفتادم: خروجی کد زیر چیست؟

(function() {
	var objA = Object.create({
		foo: 'foo'
	});
	var objB = Object.create(objA);
	console.log(objA == objB);
	console.log(objA === objB);
}());
  1. false true
  2. false false
  3. true false
  4. true true

سؤال هفتاد و یکم: خروجی کد زیر چیست؟

(function() {
	var objA = Object.create({
		foo: 'foo'
	});
	var objB = Object.create(objA);
	console.log(objA.toString() == objB.toString());
	console.log(objA.toString() === objB.toString());
}());
  1. false true
  2. false false
  3. true false
  4. true true

سؤال هفتاد و دوم: خروجی کد زیر چیست؟

(function() {
	var objA = Object.create({
		foo: 'foo'
	});
	var objB = objA;
	console.log(objA == objB);
	console.log(objA === objB);
	console.log(objA.toString() == objB.toString());
	console.log(objA.toString() === objB.toString());
}());
  1. true true true false
  2. true false true true
  3. true true true true
  4. true true false false

سؤال هفتاد و سوم: خروجی کد زیر چیست؟

(function() {
	var objA = Object.create({
		foo: 'foo'
	});
	var objB = objA;
	objB.foo = 'bar';
	console.log(objA.foo);
	console.log(objB.foo);
}());
  1. foo bar
  2. bar bar
  3. foo foo
  4. bar foo

سؤال هفتاد و چهارم: خروجی کد زیر چیست؟

(function() {
	var objA = Object.create({
		foo: 'foo'
	});
	var objB = objA;
	objB.foo = 'bar';

	delete objA.foo;
	console.log(objA.foo);
	console.log(objB.foo);
}());
  1. foo bar
  2. bar bar
  3. foo foo
  4. bar foo

سؤال هفتاد و پنجم: خروجی کد زیر چیست؟

(function() {
	var objA = {
		foo: 'foo'
	};
	var objB = objA;
	objB.foo = 'bar';

	delete objA.foo;
	console.log(objA.foo);
	console.log(objB.foo);
}());
  1. foo bar
  2. undefined undefined
  3. foo foo
  4. undefined bar

آرایه‌ها

سؤال هفتاد و ششم: خروجی کد زیر چیست؟

(function() {
	var array = new Array('100');
	console.log(array);
	console.log(array.length);
}());
  1. undefined undefined
  2. [undefined × 100] 100
  3. [“100”] 1
  4. ReferenceError: array is not defined

سؤال هفتاد و هفتم: خروجی کد زیر چیست؟

(function() {
	var array1 = [];
	var array2 = new Array(100);
	var array3 = new Array(['1',2,'3',4,5.6]);
	console.log(array1);
	console.log(array2);
	console.log(array3);
	console.log(array3.length);
}());
  1. [] [] [Array[5]] 1
  2. [] [undefined × 100] Array[5] 1
  3. [] [] [‘1′,2,’3’,4,5.6] 5
  4. [] [] [Array[5]] 5

سؤال هفتاد و هشتم: خروجی کد زیر چیست؟

(function () {
  var array = new Array('a', 'b', 'c', 'd', 'e');
  array[10] = 'f';
  delete array[10];
  console.log(array.length);
}());
  1. 11
  2. 5
  3. 6
  4. undefined

سؤال هفتاد و نهم: خروجی کد زیر چیست؟

(function(){
	var animal = ['cow','horse'];
		animal.push('cat');
		animal.push('dog','rat','goat');
		console.log(animal.length);
})();
  1. 4
  2. 5
  3. 6
  4. undefined

سؤال هشتادم: خروجی کد زیر چیست؟

(function(){
	var animal = ['cow','horse'];
		animal.push('cat');
		animal.unshift('dog','rat','goat');
		console.log(animal);
})();
  1. [‘dog’, ‘rat’, ‘goat’, ‘cow’, ‘horse’, ‘cat’]
  2. [‘cow’, ‘horse’, ‘cat’, ‘dog’, ‘rat’, ‘goat’]
  3. Type Error
  4. undefined

سؤال هشتاد و یکم: خروجی کد زیر چیست؟

(function(){
	var array = [1,2,3,4,5];
	console.log(array.indexOf(2));
	console.log([{name: 'John'},{name : 'John'}].indexOf({name:'John'}));
	console.log([[1],[2],[3],[4]].indexOf([3]));
	console.log("abcdefgh".indexOf('e'));
})();
  1. 1 -1 -1 4
  2. 1 0 -1 4
  3. 1 -1 -1 -1
  4. 1 undefined -1 4

سؤال هشتاد و دوم: خروجی کد زیر چیست؟

(function(){
	var array = [1,2,3,4,5,1,2,3,4,5,6];
	console.log(array.indexOf(2));
	console.log(array.indexOf(2,3));
	console.log(array.indexOf(2,10));
})();
  1. 1 -1 -1
  2. 1 6 -1
  3. 1 1 -1
  4. 1 undefined undefined

سؤال هشتاد و سوم: خروجی کد زیر چیست؟

(function(){
	var numbers = [2,3,4,8,9,11,13,12,16];
	var even = numbers.filter(function(element, index){
		return element % 2 === 0; 
	});
	console.log(even);

	var containsDivisibleby3 = numbers.some(function(element, index){
		return element % 3 === 0;
	});

	console.log(containsDivisibleby3);	
})();
  1. [2, 4, 8, 12, 16] [0, 3, 0, 0, 9, 0, 12]
  2. [2, 4, 8, 12, 16] [3, 9, 12]
  3. [2, 4, 8, 12, 16] true
  4. [2, 4, 8, 12, 16] false

سؤال هشتاد و چهارم: خروجی کد زیر چیست؟

(function(){
	var containers = [2,0,false,"", '12', true];
	var containers = containers.filter(Boolean);
	console.log(containers);
	var containers = containers.filter(Number);
	console.log(containers);
	var containers = containers.filter(String);
	console.log(containers);
	var containers = containers.filter(Object);
	console.log(containers);		
})();
  1. [2, ’12’, true] [2, ’12’, true] [2, ’12’, true] [2, ’12’, true]
  2. [false, true] [2] [’12’] []
  3. [2,0,false,””, ’12’, true] [2,0,false,””, ’12’, true] [2,0,false,””, ’12’, true] [2,0,false,””, ’12’, true]
  4. [2, ’12’, true] [2, ’12’, true, false] [2, ’12’, true,false] [2, ’12’, true,false]

سؤال هشتاد و پنجم: خروجی کد زیر چیست؟

(function(){
	var list = ['foo','bar','john','ritz'];
	    console.log(list.slice(1));	
	    console.log(list.slice(1,3));
	    console.log(list.slice());
	    console.log(list.slice(2,2));
	    console.log(list);				
})();
  1. [‘bar’, ‘john’, ‘ritz’] [‘bar’, ‘john’] [‘foo’, ‘bar’, ‘john’, ‘ritz’] [] [‘foo’, ‘bar’, ‘john’, ‘ritz’]
  2. [‘bar’, ‘john’, ‘ritz’] [‘bar’, ‘john’,’ritz] [‘foo’, ‘bar’, ‘john’, ‘ritz’] [] [‘foo’, ‘bar’, ‘john’, ‘ritz’]
  3. [‘john’, ‘ritz’] [‘bar’, ‘john’] [‘foo’, ‘bar’, ‘john’, ‘ritz’] [] [‘foo’, ‘bar’, ‘john’, ‘ritz’]
  4. [‘foo’] [‘bar’, ‘john’] [‘foo’, ‘bar’, ‘john’, ‘ritz’] [] [‘foo’, ‘bar’, ‘john’, ‘ritz’]

سؤال هشتاد و ششم: خروجی کد زیر چیست؟

(function(){
	var list = ['foo','bar','john'];
	    console.log(list.splice(1));		
	    console.log(list.splice(1,2));
	    console.log(list);			
})();
  1. [‘bar’, ‘john’] [] [‘foo’]
  2. [‘bar’, ‘john’] [] [‘bar’, ‘john’]
  3. [‘bar’, ‘john’] [‘bar’, ‘john’] [‘bar’, ‘john’]
  4. [‘bar’, ‘john’] [] []

سؤال هشتاد و هفتم: خروجی کد زیر چیست؟

(function(){
	var arrayNumb = [2, 8, 15, 16, 23, 42];
	arrayNumb.sort();
	console.log(arrayNumb);
})();
  1. [2, 8, 15, 16, 23, 42]
  2. [42, 23, 26, 15, 8, 2]
  3. [15, 16, 2, 23, 42, 8]
  4. [2, 8, 15, 16, 23, 42]

تابع‌ها

سؤال هشتاد و هشتم: خروجی کد زیر چیست؟

function funcA(){
	console.log("funcA ", this);
	(function innerFuncA1(){
		console.log("innerFunc1", this);
		(function innerFunA11(){
			console.log("innerFunA11", this);
		})();
	})();
}
	
console.log(funcA());
  1. funcA Window {…} innerFunc1 Window {…} innerFunA11 Window {…}
  2. undefined
  3. Type Error
  4. ReferenceError: this is not defined

سؤال هشتاد و نهم: خروجی کد زیر چیست؟

var obj = {
	message: "Hello",
	innerMessage: !(function() {
		console.log(this.message);
	})()
};
	
console.log(obj.innerMessage);
  1. ReferenceError: this.message is not defined
  2. undefined
  3. Type Error
  4. undefined true

سؤال نودم: خروجی کد زیر چیست؟

var obj = {
	message: "Hello",
	innerMessage: function() {
		return this.message;
	}
};
	
console.log(obj.innerMessage());
  1. Hello
  2. undefined
  3. Type Error
  4. ReferenceError: this.message is not defined

سؤال نود و یکم: خروجی کد زیر چیست؟

var obj = {
  message: 'Hello',
  innerMessage: function () {
    (function () {
      console.log(this.message);
    }());
  }
};
console.log(obj.innerMessage());
  1. Type Error
  2. Hello
  3. undefined
  4. ReferenceError: this.message is not defined

سؤال نود و دوم: خروجی کد زیر چیست؟

var obj = {
  message: 'Hello',
  innerMessage: function () {
  	var self = this;
    (function () {
      console.log(self.message);
    }());
  }
};
console.log(obj.innerMessage());
  1. Type Error
  2. ‘Hello’
  3. undefined
  4. ReferenceError: self.message is not defined

سؤال نود و سوم: خروجی کد زیر چیست؟

function myFunc(){
	console.log(this.message);
}
myFunc.message = "Hi John";
	
console.log(myFunc());
  1. Type Error
  2. ‘Hi John’
  3. undefined
  4. ReferenceError: this.message is not defined

سؤال نود و چهارم: خروجی کد زیر چیست؟

function myFunc(){
	console.log(myFunc.message);
}
myFunc.message = "Hi John";
	
console.log(myFunc());
  1. Type Error
  2. ‘Hi John’
  3. undefined
  4. ReferenceError: this.message is not defined

سؤال نود و پنجم: خروجی کد زیر چیست؟

function myFunc() {
  myFunc.message = 'Hi John';
  console.log(myFunc.message);
}
console.log(myFunc());
  1. Type Error
  2. ‘Hi John’
  3. undefined
  4. ReferenceError: this.message is not defined

سؤال نود و ششم: خروجی کد زیر چیست؟

function myFunc(param1,param2) {
  console.log(myFunc.length);
}
console.log(myFunc());
console.log(myFunc("a","b"));
console.log(myFunc("a","b","c","d"));
  1. 2 2 2
  2. 0 2 4
  3. undefined
  4. ReferenceError

سؤال نود و هفتم: خروجی کد زیر چیست؟

function myFunc() {
  console.log(arguments.length);
}
console.log(myFunc());
console.log(myFunc("a","b"));
console.log(myFunc("a","b","c","d"));
  1. 2 2 2
  2. 0 2 4
  3. undefined
  4. ReferenceError

شیءگرایی

سؤال نود و هشتم: خروجی کد زیر چیست؟

function Person(name, age){
	this.name = name || "John";
	this.age = age || 24;
	this.displayName = function(){
		console.log(this.name);
	}
}

Person.name = "John";
Person.displayName = function(){
	console.log(this.name);
}

var person1 = new Person('John');
	person1.displayName();
	Person.displayName();
  • John Person
  • John John
  • John undefined
  • John John

دامنه‌ها

سؤال نود و نهم: خروجی کد زیر چیست؟

function passWordMngr() {
	var password = '12345678';
	this.userName = 'John';
	return {
		pwd: password
	};
}
// Block End
var userInfo = passWordMngr();
console.log(userInfo.pwd);
console.log(userInfo.userName);
  1. 12345678 Window
  2. 12345678 John
  3. 12345678 undefined
  4. undefined undefined

سؤال صدم: خروجی کد زیر چیست؟

var employeeId = 'aq123';
function Employee() {
  this.employeeId = 'bq1uy';
}
console.log(Employee.employeeId);
  1. Reference Error
  2. aq123
  3. bq1uy
  4. undefined

سؤال صد و یکم: خروجی کد زیر چیست؟

var employeeId = 'aq123';

function Employee() {
	this.employeeId = 'bq1uy';
}
console.log(new Employee().employeeId);
Employee.prototype.employeeId = 'kj182';
Employee.prototype.JobId = '1BJKSJ';
console.log(new Employee().JobId);
console.log(new Employee().employeeId);
  1. bq1uy 1BJKSJ bq1uy undefined
  2. bq1uy 1BJKSJ bq1uy
  3. bq1uy 1BJKSJ kj182
  4. undefined 1BJKSJ kj182

سؤال صد و دوم: خروجی کد زیر چیست؟

var employeeId = 'aq123';
(function Employee() {
	try {
		throw 'foo123';
	} catch (employeeId) {
		console.log(employeeId);
	}
	console.log(employeeId);
}());
  1. foo123 aq123
  2. foo123 foo123
  3. aq123 aq123
  4. foo123 undefined

Call, Apply, Bind

سؤال صد و سوم: خروجی کد زیر چیست؟

(function() {
	var greet = 'Hello World';
	var toGreet = [].filter.call(greet, function(element, index) {
		return index > 5;
	});
	console.log(toGreet);
}());
  1. Hello World
  2. undefined
  3. World
  4. [‘W’, ‘o’, ‘r’, ‘l’, ‘d’]

سؤال صد و چهارم: خروجی کد زیر چیست؟

(function() {
	var fooAccount = {
		name: 'John',
		amount: 4000,
		deductAmount: function(amount) {
			this.amount -= amount;
			return 'Total amount left in account: ' + this.amount;
		}
	};
	var barAccount = {
		name: 'John',
		amount: 6000
	};
	var withdrawAmountBy = function(totalAmount) {
		return fooAccount.deductAmount.bind(barAccount, totalAmount);
	};
	console.log(withdrawAmountBy(400)());
	console.log(withdrawAmountBy(300)());
}());
  1. Total amount left in account: 5600 Total amount left in account: 5300
  2. undefined undefined
  3. Total amount left in account: 3600 Total amount left in account: 3300
  4. Total amount left in account: 5600 Total amount left in account: 5600

سؤال صد و پنجم: خروجی کد زیر چیست؟

(function() {
	var fooAccount = {
		name: 'John',
		amount: 4000,
		deductAmount: function(amount) {
			this.amount -= amount;
			return this.amount;
		}
	};
	var barAccount = {
		name: 'John',
		amount: 6000
	};
	var withdrawAmountBy = function(totalAmount) {
		return fooAccount.deductAmount.apply(barAccount, [totalAmount]);
	};
	console.log(withdrawAmountBy(400));
	console.log(withdrawAmountBy(300));
	console.log(withdrawAmountBy(200));
}());
  1. 5600 5300 5100
  2. 3600 3300 3100
  3. 5600 3300 5100
  4. undefined undefined undefined

سؤال صد و ششم: خروجی کد زیر چیست؟

(function() {
	var fooAccount = {
		name: 'John',
		amount: 6000,
		deductAmount: function(amount) {
			this.amount -= amount;
			return this.amount;
		}
	};
	var barAccount = {
		name: 'John',
		amount: 4000
	};
	var withdrawAmountBy = function(totalAmount) {
		return fooAccount.deductAmount.call(barAccount, totalAmount);
	};
	console.log(withdrawAmountBy(400));
	console.log(withdrawAmountBy(300));
	console.log(withdrawAmountBy(200));
}());
  • 5600 5300 5100
  • 3600 3300 3100
  • 5600 3300 5100
  • undefined undefined undefined

سؤال صد و هفتم: خروجی کد زیر چیست؟

(function greetNewCustomer() {
	console.log('Hello ' + this.name);
}.bind({
	name: 'John'
})());
  1. Hello John
  2. Reference Error
  3. Window
  4. undefined

Callback Functions

سؤال صد و هشتم: خروجی کد زیر چیست؟

function getDataFromServer(apiUrl){
    var name = "John";
	return {
		then : function(fn){
			fn(name);
		}
	}
}

getDataFromServer('www.google.com').then(function(name){
	console.log(name);
});

  1. John
  2. undefined
  3. Reference Error
  4. fn is not defined

سؤال صد و نهم: خروجی کد زیر چیست؟

(function(){
	var arrayNumb = [2, 8, 15, 16, 23, 42];
	Array.prototype.sort = function(a,b){
		return a - b;
	};
	arrayNumb.sort();
	console.log(arrayNumb);
})();

(function(){
	var numberArray = [2, 8, 15, 16, 23, 42];
	numberArray.sort(function(a,b){
		if(a == b){
			return 0;
		}else{
			return a < b ? -1 : 1;
		}
	});
	console.log(numberArray);
})();

(function(){
	var numberArray = [2, 8, 15, 16, 23, 42];
	numberArray.sort(function(a,b){
		return a-b;
	});
	console.log(numberArray);
})();
  1. [2, 8, 15, 16, 23, 42] [2, 8, 15, 16, 23, 42] [2, 8, 15, 16, 23, 42]
  2. undefined undefined undefined
  3. [42, 23, 16, 15, 8, 2] [42, 23, 16, 15, 8, 2] [42, 23, 16, 15, 8, 2]
  4. Reference Error

گزاره‌های Return

سؤال صد و دهم: خروجی کد زیر چیست؟

(function(){
	function sayHello(){
		var name = "Hi John";
		return 
		{
			fullName: name
		}
	}
	console.log(sayHello().fullName);
})();
  1. Hi John
  2. undefined
  3. Reference Error
  4. Uncaught TypeError: Cannot read property ‘fullName’ of undefined

سؤال صد و یازدهم: خروجی کد زیر چیست؟

function getNumber(){
	return (2,4,5);
}

var numb = getNumber();
console.log(numb);
  1. 5
  2. undefined
  3. 2
  4. (2,4,5)

سؤال صد و دوازدهم: خروجی کد زیر چیست؟

function getNumber(){
	return;
}

var numb = getNumber();
console.log(numb);
  1. null
  2. undefined
  3. “”
  4. 0

سؤال صد و سیزدهم: خروجی کد زیر چیست؟

function mul(x){
	return function(y){
		return [x*y, function(z){
			return x*y + z;
		}];
	}
}

console.log(mul(2)(3)[0]);
console.log(mul(2)(3)[1](4));
  1. 6, 10
  2. undefined undefined
  3. Reference Error
  4. 10, 6

سؤال صد و چهاردهم: خروجی کد زیر چیست؟

function mul(x) {
	return function(y) {
		return {
			result: x * y,
			sum: function(z) {
				return x * y + z;
			}
		};
	};
}
console.log(mul(2)(3).result);
console.log(mul(2)(3).sum(4));
  1. 6, 10
  2. undefined undefined
  3. Reference Error
  4. 10, 6

سؤال صد و پانزدهم: خروجی کد زیر چیست؟

function mul(x) {
	return function(y) {
		return function(z) {
			return function(w) {
				return function(p) {
					return x * y * z * w * p;
				};
			};
		};
	};
}
console.log(mul(2)(3)(4)(5)(6));
  1. 720
  2. undefined
  3. Reference Error
  4. Type Error

سؤال صد و شانزدهم: خروجی کد زیر چیست؟

function getName1(){
	console.log(this.name);
}

Object.prototype.getName2 = () =>{
	console.log(this.name)
}

let personObj = {
	name:"Tony",
	print:getName1
}

personObj.print();
personObj.getName2();
  1. undefined undefined
  2. Tony undefined
  3. undefined Tony
  4. Tony Tony

پاسخ سوالات

پاسخ سوال اول

در زبان برنامه‌نویسی جاوا اسکریپت اگر بخواهید از متغیرهایی استفاده کنید که وجود ندارند و اعلان هم نشده‌اند، جاوا اسکریپت خطایی به صورت زیر صادر می‌کند:

var name is not defined

و در ادامه اجرای اسکریپت متوقف می‌شود. اما اگر از نوع متغیر undeclared_variable استفاده کرده باشید، مقدار undefined بازگشت می‌یابد.

پیش از ادامه بحث باید تفاوت بین تعریف کردن (Define) و اعلان کردن (Declear) یک متغیر را به خوبی درک کنیم.

عبارت var x یک اعلان است، زیرا تعریف نمی‌کند که متغیر چه مقداری را باید بگیرد، بلکه ما فقط وجود متغیر و نیاز به تخصیص حافظه را اعلان می‌کنیم.

var x; // declaring x
console.log(x); // output: undefined

از سوی دیگر عبارت var x = 1 هم اعلان و هم تعریف کردن یک متغیر است چون اینجا هر دو کار اعلان کردن و انتساب مقدار برای متغیر x در یک خط انجام یافته است. این کار به طور کلی «مقداردهی» (initialisation) نامیده می‌شود. در زبان جاوا اسکریپت هم اعلان متغیر و هم اعلان تابع در ابتدای دامنه‌ای که قرار است اعلان صورت گیرد انجام می‌یابد و سپس انتساب صورت می‌گیرد. این سری وقایع به نام «برافرازی» (hoisting) شناخته می‌شوند.

متغیر می‌تواند اعلان شده باشد، اما تعریف نشده باشد. زمانی که تلاش کنیم به چنین متغیری دسترسی یابیم، نتیجه کار undefined خواهد بود.

var x; // Declaration
typeof x === 'undefined'; // Will return true

متغیر می‌تواند نه اعلان و نه تعریف شده باشد. در چنین حالتی اگر تلاش کنیم به چنین متغیری ارجاع بدهیم، نتیجه not defined خواهد بود.

console.log(y);// Output: ReferenceError: y is not defined

پاسخ سؤال دوم

NaN <= 100 مقدار false دارد و NaN > 100 هم مقدار false دارد، از این رو اگر مقدار x به صورت NaN باشد، گزاره‌ها یکسان نخواهند بود. همین وضعیت برای هر مقدار x که وقتی به نوع «عددی» (Number) تبدیل شده باشد مقدار NaN بازگشت بدهد، نیز صحیح است. برای نمونه می‌توان به undefined, [1,2,5], {a:22} و غیره اشاره کرد.

به همین دلیل است که باید در زمان کار با متغیرهای عددی توجه ویژه‌ای مبذول دارید. NaN نمی‌تواند با هیچ مقدار عددی دیگری برابر باشد یا از آن‌ها کوچک‌تر یا بزرگتر محاسبه شود. از این رو تنها روش مطمئن برای بررسی این که آیا یک مقدار NaN است یا نه، این است که از تابع ()isNaN استفاده کنیم.

پاسخ سؤال سوم

یکی از معایب اعلان متدها به صورت مستقیم درون اشیای جاوا اسکریپت آن است که از نظر حافظه بسیار غیر بهینه است. با انجام این کار یک کپی جدید از متد برای هر وهله از یک شیء ایجاد می‌شود. به مثال زیر توجه کنید:

var Employee = function (name, company, salary) {
  this.name = name || "";       
  this.company = company || "";
  this.salary = salary || 5000;

  // We can create a method like this:
  this.formatSalary = function () {
      return "$ " + this.salary;
  };
};

// Alternatively we can add the method to Employee's prototype:
Employee.prototype.formatSalary2 = function() {
    return "$ " + this.salary;
}

//creating objects
var emp1 = new Employee('Yuri Garagin', 'Company 1', 1000000);
var emp2 = new Employee('Dinesh Gupta', 'Company 2', 1039999);
var emp3 = new Employee('Erich Fromm', 'Company 3', 1299483);

در این حالت، هر وهله از متغیر یعنی emp1, emp2, emp3 کپی خاص خود را از متد theformatSalary دارند. با این حال متد formatSalary2 تنها یک بار به Employee.prototype اضافه خواهد شد.

پاسخ سؤال چهارم

«کلوژر» (closure) تابعی است که درون تابع دیگری (تابع والد نامیده می‌شود) تعریف می‌شود و از این رو به متغیرهای اعلان و تعریف شده درون دامنه تابع والدش دسترسی دارد.

کلوژر به متغیرهای سه دامنه به شرح زیر دسترسی دارد:

  • متغیرهای اعلان شده در دامنه خودش.
  • متغیرهای اعلان شده در دامنه تابع والدش.
  • متغیرهای اعلان شده در فضای نام عمومی.
var globalVar = "abc"; //Global variable

// Parent self-invoking function
(function outerFunction (outerArg) { // start of outerFunction's scope

  var outerFuncVar = 'x'; // Variable declared in outerFunction's function scope   
  
  // Closure self-invoking function
  (function innerFunction (innerArg) { // start of innerFunction's scope

    var innerFuncVar = "y"; // variable declared in innerFunction's function scope
    console.log(         
      "outerArg = " + outerArg + "\n" +
      "outerFuncVar = " + outerFuncVar + "\n" +
      "innerArg = " + innerArg + "\n" +
      "innerFuncVar = " + innerFuncVar + "\n" +
      "globalVar = " + globalVar);
  	
  // end of innerFunction's scope
  
  })(5); // Pass 5 as parameter to our Closure

// end of outerFunction's scope

})(7); // Pass 7 as parameter to the Parent function

در کد فوق innerFunction یک کلوژر است که ‌ درون outerFunction تعریف شده است و از این رو به همه متغیرهایی که درون دامنه outerFunction’s اعلان و تعریف شده‌اند و همچنین به هر متغیری که درون دامنه عمومی برنامه قرار دارد، دسترسی پیدا می‌کند.

خروجی کد فوق چنین خواهد بود:

outerArg = 7
uterFuncVar = x
innerArg = 5
innerFuncVar = y
globalVar = abc

پاسخ سؤال پنجم

function mul (x) {
  return function (y) { // anonymous function
    return function (z) { // anonymous function
      return x * y * z;
    };
  };
}

در کد فوق تابع mul آرگومان نخست را پذیرفته و یک تابع ناشناس بازگشت می‌دهد که پارامتر دوم را می‌گیرد و تابع ناشناس آخر را بازگشت می‌دهد که در نهایت پارامتر سوم و نهایی را می‌گیرد. در ادامه تابع آخر x و y و z را صرب در هم کرده و نتیجه عملیات را بازگشت می‌دهد.

در جاوا اسکریپت، تابعی که درون تابع دیگر تعریف شده باشد، به دامنه تابع بیرونی دسترسی دارد و در نتیجه می‌تواند متغیرهای متعلق به تابع والدش را بازگشت دهد، دستکاری کند و یا آن‌ها را به تابع دیگری ارسال کند.

  • تابع وهله‌ای از نوع Object است.
  • تابع می‌تواند مشخصه داشته باشد و یک پیوند به متد سازنده‌اش دارد.
  • تابع می‌تواند به صورت متغیر ذخیره شود.
  • تابع می‌تواند به شکل پارامتر به تابع دیگر ارسال شود.
  • تابع می‌تواند از سوی تابع دیگری بازگشت یابد.

پاسخ سؤال ششم

چندین روش برای خالی کردن آرایه‌های جاوا اسکریپت وجود دارند. در ادامه این روش‌ها را بررسی می‌کنیم.

روش اول

arrayList = [];

کد فوق متغیر را به صورت یک آرایه جدید خالی تعیین می‌کند. در صورتی ک به آرایه اصلی از هیچ کجا ارجاع نداشته باشد این روش توصیه می‌شود، زیرا در عمل یک آرایه جدید خالی ایجاد می‌کند. توجه کنید که استفاده از این روش نیازمند احتیاط زیادی است، زیرا اگر این ارائه در متغیر دیگری مورد ارجاع قرار گرفته باشد، آرایه مورد ارجاع اصلی بدون تغییر می‌ماند. بنابراین تنها در صورتی باید از این روش استفاده کنید که تنها در متغیر اصلی arrayList آرایه را مورد ارجاع قرار داده باشید.

به مثال زیر توجه کنید:

var arrayList = ['a', 'b', 'c', 'd', 'e', 'f']; // Created array
var anotherArrayList = arrayList;  // Referenced arrayList by another variable
arrayList = []; // Empty the array
console.log(anotherArrayList); // Output ['a', 'b', 'c', 'd', 'e', 'f']

روش دوم

arrayList.length = 0;

کد فوق آرایه موجود را با تعیین مقدار صفر برای طول آن پاک می‌کند. این روش خالی کردن آرایه نیز موجب می‌شود که همه متغیرهای ارجاع داده به آرایه اصلی به‌روزرسانی شوند. به مثال زیر توجه کنید:

var arrayList = ['a', 'b', 'c', 'd', 'e', 'f']; // Created array
var anotherArrayList = arrayList;  // Referenced arrayList by another variable
arrayList.length = 0; // Empty the array by setting length to 0
console.log(anotherArrayList); // Output []

روش سوم

arrayList.splice(0, arrayList.length);

پیاده‌سازی فوق نیز به خوبی کار خواهد کرد. این روش پاک کردن آرایه موجب به‌روز شدن همه ارجاع‌ها به آرایه اصلی می‌شود.

var arrayList = ['a', 'b', 'c', 'd', 'e', 'f']; // Created array
var anotherArrayList = arrayList;  // Referenced arrayList by another variable
arrayList.splice(0, arrayList.length); // Empty the array by setting length to 0
console.log(anotherArrayList); // Output []

روش چهارم

while(arrayList.length) {
  arrayList.pop();
}

پیاده‌سازی فوق نیز می‌تواند آرایه را خالی کند. اما استفاده از آن چندان توصیه نمی‌شود.

پاسخ سؤال هفتم

بهترین روش برای فهمیدن این که یک شیء وهله‌ای از یک کلاس خاص است یا نه، استفاده از متد toString از Object.prototype است.

var arrayList = [1, 2, 3];

یکی از بهترین موارد کاربرد بررسی نوع یک شیء، زمانی است که اقدام به اورلود کردن متد در جاوا اسکریپت کرده‌ایم. برای درک این موضوع فرض کنید متدی به نام greet داریم که می‌تواند یک رشته منفرد و همچنین لیستی از رشته‌ها را دریافت کند. برای این که متد greet قابل استفاده در هر موقعیت باشد باید بدانیم که کدام پارامتر ارسال شده است، یعنی یک پارامتر منفرد است یا لیستی از مقادیر.

function greet(param) {
  if() {
    // here have to check whether param is array or not
  }
  else {
  }
}

با این حال، در پیاده‌سازی فوق ممکن است نیاز به بررسی نوع آرایه داشته باشیم. به این ترتیب می‌توانیم وجود یک مقدار رشته‌ای منفرد را بررسی کرده و کد منطق آرایه را در بلوک else قرار دهیم که در نهایت ما را به قطعه کد زیر می‌رساند:

 function greet(param) {
   if(typeof param === 'string') {
   }
   else {
     // If param is of type array then this block of code would execute
   }
 }

اکنون مشکلی با پیگیری دو پیاده‌سازی قبلی نداریم، اما وقتی موقعیتی داشته باشیم که پارامترها به انواع single value, array و object باشند، با مشکل مواجه خواهیم شد.

اکنون اگر بخواهیم نوع آبجکت را نیز بررسی کنیم، می‌توانیم از Object.prototype.toString استفاده کنیم.

if(Object.prototype.toString.call(arrayList) === '[object Array]') {
  console.log('Array!');
}

اگر از jQuery استفاده می‌کنید، می‌توانید از متد isArray در جی‌کوئری نیز بهره بگیرید:

if($.isArray(arrayList)) {
  console.log('Array');
} else {
  console.log('Not an array');
}

باید بدانید که جی‌کوئری به طور داخلی از Object.prototype.toString.call برای بررسی آبجکت بودن یک آرایه استفاده می‌کند. در یک مرورگر مدرن می‌توان از کد زیر نیز استفاده کرد:

Array.isArray(arrayList);

Array.isArray از سوی کروم 5، فایرفاکس 4، اینترنت اکسپلورر 9، اپرا 10.5 و سافاری 5 پشتیبانی می‌شود.

پاسخ سؤال هشتم

کد فوق مقدار 0 را خروجی می‌دهد. عملگر delete برای حذف یک مشخصه از آبجکت مورد استفاده قرار می‌گیرد. در کد فوق x یک شیء نیست بلکه یک متغیر لوکال است. عملگر delete روی متغیرهای لوکال تأثیری ندارد.

پاسخ سؤال نهم

کد فوق مقدار 1 را در خروجی ارائه می‌کند. عملگر delete برای حذف مشخصه از آبجکت استفاده شده است. به این ترتیب x نه یک شیء بلکه یک متغیر سراسری از نوع number است.

پاسخ سؤال دهم

کد فوق مقدار undefined را در خروجی ارائه می‌کند. عملگر delete برای حذف یک مشخصه از آبجکت استفاده می‌شود. در این کد x یک شیء است که مشخصه‌ای به نام foo دارد و یک تابع خود-احضار را شکل داده. ما پس از حذف مشخصه foo از شیء x تلاش می‌کنیم تا به مشخصه foo ارجاع بدهیم که نتیجه آن undefined است.

پاسخ سؤال یازدهم

کد فوق مقدار xyz را در خروجی ارائه می‌کند. در این کد شیء emp1 مشخصه company را به عنوان مشخصه پروتوتایپ دریافت می‌کند. عملگر delete مشخصه پروتوتایپ را حذف نمی‌کند.

شیء emp1 مقدار company را به عنوان مشخصه خودش ندارد. اگر می‌خواهید این موضوع را تست کنید، کد زیر را اجرا نمایید:

console.log(emp1.hasOwnProperty('company')); //output: false

با این حال می‌توانیم مشخصه company را به طور مستقیم با استفاده از delete Employee.company از شیء Employee حذف کنیم یا این که می‌توانیم با بهره‌گیری از مشخصه __proto__ و دستور delete emp1.__proto__.company از شیء emp1 حذف کنیم.

پاسخ سؤال دوازدهم

هنگامی که کد فوق را اجرا کرده و در کنسول توسعه‌دهندگان مرورگر کروم دستور console.log(trees); را اجرا کنید، مقدار زیر را به دست می‌آورید:

["redwood", "bay", "cedar", undefined × 1, "maple"]

در نسخه‌های جدیدتر کروم یکی از کلمه‌های empty یا undefined x 1 را ملاحظه می‌کنید. زمانی که همین کد را در مرورگر فایرفاکس اجرا کنید مقدار زیر را به دست می‌آورید:

["redwood", "bay", "cedar", undefined, "maple"]

بدیهی است که کروم روش خاص خود را برای نمایش اندیس مقداردهی نشده در آرایه‌ها دارد. با این حال هنگامی که trees[3] === undefined را در هر مرورگری بررسی کنید، خروجی مشابه true را دریافت خواهید کرد.

نکته: به خاطر داشته باشید که لزومی به بررسی اندیس مقداردهی نشده در آرایه در trees[3] === ‘undefined × 1’ وجود ندارد، زیرا خطایی نمایش نمی‌یابد و ‘undefined × 1’ تنها روشی برای نمایش اندیس مقداردهی نشده در کروم محسوب می‌شود.

پاسخ سؤال سیزدهم

کد فوق مقدار 5 را به عنوان خروجی ارائه می‌کند. زمانی که از عملگر delete برای حذف کردن عناصر یک آرایه بهره بگیریم، طول آرایه تحت تأثیر قرار نمی‌گیرد. حتی در صورتی که همه عناصر یک آرایه را با استفاده از عملگر delete حذف کنید، طول آن هیچ تأثیری نمی‌گیرد.

بنابراین زمانی که عملگر delete یک عنصر آرایه را حذف می‌کند، آن عنصر حذف شده دیگر در آرایه وجود نخواهد داشت. به جای اندیس حذف شده، مقدار undefined x 1 در مرورگر chrome و undefined در اندیس جای می‌گیرد. در این زمان اگر دستور undefined x 1 in chrome and undefined is را اجرا کنید، خروجی کروم چنین خواهد بود:

["xyz", "xxxx", "test", undefined × 1, "apple"]

خروجی فایرفاکس نیز چنین خواهد بود:

["xyz", "xxxx", "test", undefined, "apple"]

پاسخ سوال چهاردهم

کد فوق مقدار 1, “truexyz”, 2, 1 را در خروجی ارائه می‌کند. راهنمای کلی عملگر بعلاوه چنین است:

  • عدد + عدد = جمع
  • مقدار بولی + عدد = جمع
  • مقدار بولی + مقدار بولی = جمع
  • عدد + رشته = الحاق
  • رشته + مقدار بولی = الحاق
  • رشته + رشته = الحاق

پاسخ سؤال پانزدهم

کد فوق رشته undefined را در خروجی چاپ می‌کند. بر اساس قاعده شرکت‌پذیری، عملگرهای دارای تقدم یکسان بر اساس خصوصیت شرکت‌پذیری عملگر پردازش می‌شوند. در این مثال شرکت‌پذیری عملگر انتساب از راست به چپ است و از این رو typeof y ابتدا ارزیابی می‌شود که رشته undefined است و به z انتساب می‌یابد و سپس y به مقدار z انتساب می‌یابد. دنباله کلی به صورت زیر است:

var z;
z = 1;
var y;
z = typeof y;
y = z;

پاسخ سؤال شانزدهم

خروجی این کد به صورت Reference Error است. برای حل این باگ باید کد را به روش اندکی متفاوت بازنویسی کنیم:

مثال اول

var bar = function() { return 12; };
typeof bar();

یا به روش زیر عمل می‌کنیم:

مثال دوم

function bar() { return 12; };
typeof bar();

تعریف تابع می‌تواند تنها یک متغیر ارجاعی به صورت نام تابع داشته باشد. در مثال اول bar یک متغیر ارجاعی است که به anonymous function اشاره دارد و در مثال دوم یک انتساب تابع داریم و bar نام تابع است.

var foo = function bar() {
  // foo is visible here
  // bar is visible here
  console.log(typeof bar()); // Works here :)
};
// foo is visible here
// bar is undefined here

پاسخ سؤال هفدهم (الف)

تفاوت اصلی در این است که تابع foo در زمان اجرا (runtime) تعریف شده و یک «عبارت تابعی» (function expression) نامیده می‌شود، در حالی که تابع bar در زمان parse تعریف شده و «گزاره تابعی» (function statement) نامیده می‌شود. برای درک بهتر آن نگاهی به کد زیر بیندازید:

// Run-Time function declaration
  foo(); // Call foo function here, It will give an error
  var foo = function() {
    console.log("Hi I am inside Foo");
  };
// Parse-Time function declaration
bar(); // Call bar function here, It will not give an Error
function bar() {
  console.log("Hi I am inside Foo");
}

پاسخ سؤال هفدهم (ب)

خروجی کد فوق چنین است:

bar got called
something

از آنجا که تابع ابتدا فراخوانی می‌شود و در زمان parse تعریف می‌شود، موتور جاوا اسکریپت تلاش می‌کند تا تعاریف زمان parse را یافته و حلقه اجرا را آغاز کند. معنای این حرف آن است که تابع اصلی ابتدا فراخوانی می‌شود، هر چند تعریف در تابع دیگری ارسال شده باشد.

پاسخ سؤال هجدهم

عبارت تابعی را در نظر بگیرید:

 var foo = function foo() {
     return 12;
 }

در جاوا اسکریپت متغیرهای اعلان شده با var و تابع‌ها به صورت hoist-شده هستند. ابتدا تابع hoisting را بررسی می‌کنیم. اساساً مفسر جاوا اسکریپت به دنبال همه اعلان‌های متغیرها می‌گردد و آن‌ها را به ابتدای تابع یعنی جایی که اعلان شده hoist می‌کند. مثال زیر را در نظر بگیرید.

foo(); // Here foo is still undefined
var foo = function foo() {
  return 12;
};

کد فوق در پس‌زمینه چیزی شبیه زیر است:

var foo = undefined;
foo(); // Here foo is undefined
foo = function foo() {
  // Some code stuff
}
var foo = undefined;
foo = function foo() {
  // Some code stuff
}
foo(); // Now foo is defined here

پاسخ سؤال نوزدهم

خروجی کد فوق به صورت undefined, 5000$ است، زیرا hoisting رخ داده است. در کد ارائه شده فوق ممکن است ببینید که salary مقدار خارج از دامنه خود را تا زمانی که salary در دامنه درونی دوباره اعلان می‌شود، نگه‌داری می‌کند. اما می‌بینیم که مقدار حقوق hoisting به صورت undefined است. برای درک بهتر این مسئله باید کد زیر را بررسی کنید. در کد زیر متغیر salary به صورت hosit است و در ابتدای دامنه تابع اعلان شده است. هنگامی که مقدار آن را با استفاده از console.log چاپ می‌کنیم، نتیجه undefined است. در ادامه متغیر دوباره اعلان می‌شود و مقدار جدید 5000$ به آن انتساب می‌یابد.

var salary = "1000$";

(function () {
  var salary = undefined;
  console.log("Original salary was " + salary);

  salary = "5000$";

  console.log("My New Salary " + salary);
})();

پاسخ سؤال بیستم

Typeof یک عملگر است که رشته‌ای با هر نوع که ارسال شده باشد، بازگشت می‌دهد. عملگر typeof بررسی می‌کند آیا یک مقدار به یکی از هفت نوع ابتدایی یعنی number, string, boolean, object, function, undefined یا Symbol تعلق دارد یا نه. typeof(null) مقداری به صورت object بازگشت می‌دهد.

Instanceof هوشمندانه‌تر عمل می‌کند و در سطح پروتوتایپ وارد عمل می‌شود. به طور خاص بررسی می‌کند آیا عملوند مناسبی در هر جایی در زنجیره پروتوتایپ سمت چپ استفاده شده است یا نه. Instanceof روی انواع مقدماتی کاربرد ندارد. عملگر instanceof شیء کنونی را بررسی کرده و در صورتی که آن شیء از نوع خاصی باشد مقدار true بازگشت می‌دهد. به مثال زیر توجه کنید.

var dog = new Animal();
dog instanceof Animal; // Output : true

در کد فوق، dog instanceof Animal مقدار true دارد، زیرا dog از Animal.prototype ارث می‌برد.

var name = new String("xyz");
name instanceof String; // Output : true

پاسخ سؤال بیست و یکم

قبل از هر چیز باید اشاره کنیم که آرایه انجمنی در جاوا اسکریپت همان شیء است. دوما با این که هیچ تابع یا مشخصه داخلی برای محاسبه طول/اندازه یک شیء وجود ندارد، اما می‌توانیم خودمان چنین تابعی بنویسیم.

روش اول

Object دارای متد keys است که می‌تواند برای محاسبه طول شیء مورد استفاده قرار گیرد.

Object.keys(counterArray).length; // Output 3

روش دوم

همچنین می‌توانیم طول شیء را با تعریف حلقه روی شیء و شمارش مشخصه‌های شیء محاسبه کنیم. در این روش مشخصه‌هایی که از زنجیره پروتوتایپ شیء هستند نادیده گرفته می‌شوند.

function getLength(object) {
  var count = 0;
  for(key in object) {
    // hasOwnProperty method check own property of object
    if(object.hasOwnProperty(key)) count++;
  }
  return count;
}

روش سوم

همه مرورگرهای مدرن از متد etOwnPropertyNames پشتیبانی می‌کنند و از ای رو می‌توانیم با استفاده از کد زیر طول شیء را حساب کنیم:

Object.getOwnPropertyNames(counterArray).length; // Output 3

روش چهارم

کتابخانه‌های Underscore و lodash دارای متد size هستند که اختصاص به محاسبه طول شیء دارد. توجه کنید که گنجاندن این کتابخانه‌ها صرفاً برای محاسبه طول یک آرایه کار معقولی نیست، اما اگر از قبل در پروژه خود دارید می‌توانید با استفاده از کد زیر طول شیء را حساب کنید:

_.size({one: 1, two: 2, three: 3});
=> 3

پاسخ سوال بیست و دوم

اگر با برنامه‌نویسی شیء‌گرا آشنا باشید، به احتمال زیاد با مفاهیم تابع‌، متد و سازنده‌های کلاس نیز آشنا هستید. اما در جاوا اسکریپت این موارد صرفاً سه الگوی کاربرد متفاوت از یک سازه واحد هستند.

تابع‌ها: ساده‌ترین کاربرد یک فراخوانی تابع چنین است.

function helloWorld(name) {
  return "hello world, " + name;
}

helloWorld("JS Geeks"); // "hello world JS Geeks"

متدها در جاوا اسکریپت چیزی بیش از مشخصه‌ شیء از جنس تابع نیستند.

var obj = {
  helloWorld : function() {
    return "hello world, " + this.name;
  },
  name: 'John Carter'
}
obj.helloWorld(); // // "hello world John Carter"

توجه کنید که helloWorld به مشخصه this در obj اشاره می‌کند. احتمالاً متوجه شده‌اید که this با obj پیوند دارد. اما نکته جالب این است که می‌توانیم یک ارجاع به همان تابع helloWorld را در شیء دیگر کپی کرده و پاسخ متفاوتی دریافت کنیم. به مثال زیر توجه کنید.

var obj2 = {
  helloWorld : obj.helloWorld,
  name: 'John Doe'
}
obj2.helloWorld(); // "hello world John Doe"

ممکن است تعجب کنید که در فراخوان متد دقیقاً چه اتفاقی می‌افتد. ر این متد خود عبارت را فرا می‌خوانیم تا اتصال آن با this را تعیین کنیم. عبارت ()obj2.helloWorld به بررسی مشخصه helloWorld از شیء obj می‌پردازد و با استفاده از شیء دریافت‌کننده obj2 آن را فرا می‌خواند.

سومین کاربرد تابع به عنوان «سازنده» (constructor) است. سازنده‌ها نیز همانند تابع‌ها و متدها با استفاده از یک تابع تعریف می‌شوند.

function Employee(name, age) {
  this.name = name;
  this.age = age;
}

var emp1 = new Employee('John Doe', 28);
emp1.name; // "John Doe"
emp1.age; // 28

برخلاف فراخوانی تابع و فراخوانی متد، فراخوانی سازنده مانند new Employee(‘John Doe’, 28) موجب ایجاد یک شیء کاملاً جدید می‌شود و آن را به عنوان مقدار this ارسال می‌کند و به طور ضمنی شیء جدید را به عنوان نتیجه‌اش بازگشت می‌دهد.

نقض اصلی تابع سازنده، مقداردهی شیء است.

پاسخ سؤال بیست و سوم

خروجی کد فوق می‌تواند USA باشد. در این کد new User(“xyz”) یک شیء کاملاً جدید ایجاد می‌کند و مشخصه ایجاد شده location روی آن و USA به مشخصه مکان شیء انتساب می‌یابد و از سوی فرد مورد ارجاع قرار می‌گیرد.

فرض کنید یک شیء به نام foo ایجاد می‌کند. مقدار USA به foo[“location”] انتساب می‌یابد، اما بر اساس مشخصه‌های ECMAScript خود انتساب مقدار سمت راست را بازگشت می‌دهد که در این مورد USA است که در ادامه به Person انتساب خواهد یافت.

برای درک بهتر اتفاقاتی که در کد فوق می‌افتد باید این کد را در کنسول به طور خط به خط اجرا کنیم:

function User(name) {
 this.name = name || "JsGeeks";
}

var person;
var foo = new User("xyz");
foo["location"] = "USA";
// the console will show you that the result of this is "USA"

پاسخ سؤال بیست و چهارم

سرویس ورکر یک فناوری است که به وب اپلیکیشن‌ها امکان می‌دهد تا ابتدا از منابع کش ‌شده بهره بگیرند و تجربه پیش‌فرض آفلاین را در اختیار کاربر قرار دهند و تنها پس از بارگذاری کامل صفحه است که اقدام به واکشی داده‌ها از شبکه می‌کند. این مفهوم عموماً به نام «ابتدا-آفلاین» (Offline First) خوانده می‌شود.

سرویس ورکرها به طور فعالانه از پرامیس‌ها بهره می‌گیرند. یک سرویس ورکر باید نصب و فعال شود تا بتواند به رویدادهای واکشی، ارسال و همگام‌‌سازی واکنش نشان دهد.

پاسخ سؤال بیست و پنجم

تفاوت بین تابع و متد در زبان برنامه‌نویسی جاوا اسکریپت بسیار ظریف است. تابع قطعه کدی است که بر اساس نامش فراخوانی می‌شود و خود تابع هیچ ارتباط با شیء ندارد و درون شیء نیز تعریف نمی‌شود. تابع می‌تواند داده‌هایش را به جای دیگری ارسال کند یا از جای دیگری دریافت کند تا عملیاتی رویشان انجام یابد و می‌تواند به طور اختیاری داده‌ها را به صورت خروجی ارائه کند.

// Function statement
function myFunc() {
  // Do some stuff;
}

// Calling the function
myFunc();

در کد فوق تابع ()myFunc با شیء ارتباطی ندارد و از این رو از طریق هیچ شیئی احضار نمی‌شود. تابع می‌تواند به صورت یک «عبارت تابعی با احضار بی‌درنگ» (IIFE) مانند مثال زیر باشد.

// Anonymous Self-invoking Function
(function() {
  // Do some stuff;
})();

در نهایت تابع‌های arrow نیز به شکل زیر هستند:

const myFunc = arg => {
    console.log("hello", arg)
} 

در سوی دیگر، متد قطعه کدی است که به وسیله نامش فراخوانده می‌شود و با یک شیء ارتباط دارد. زمانی که یک متد را به صورت ()obj1.myMethod فرا می‌خوانید، ارجاع به obj1 با متغیر this پیوند می‌یابد. به بیان دیگر، مقدار this همان obj1 درون myMethod خواهد بود. در ادامه برخی مثال‌های دیگر از متدها را ملاحظه می‌کنید.

مثال یکم

var obj1 = {
  attribute: "xyz",
  myMethod: function () {  // Method
    console.log(this.attribute);
  }
};

// Call the method
obj1.myMethod();

در کد فوق obj1 یک شیء است و myMethod متدی است که با obj1 ارتباط دارد.

مثال دوم

در ES6 با مفهوم کلاس سروکار داریم. از این رو برخی متدها مانند زیر وجود دارند.

class MyAwesomeClass {
  myMethod() {
    console.log("hi there");
  }
}

const obj1 = new MyAwesomeClass();
obj1.myMethod();

توجه کنید که متد نوع خاصی از تابع نیست و تفاوت آن با تابع به شیو اعلان کردنش بستگی ندارد. در واقع شیوه فراخوانی است که تفاوت این دو را مشخص می‌کند. به مثال زیر توجه کنید.

var obj1 = {
  prop1: "buddy"
}; 
var myFunc = function () {
  console.log("Hi there", this);
};
// let's call myFunc as a function: 
myFunc(); // will output "Hi there undefined" or "Hi there Window"
 
obj1.myMethod = myFunc;
//now we're calling myFunc as a method of obj1, so this will point to obj1
obj1.myMethod(); // will print "Hi there" following with obj1. 

پاسخ سؤال بیست و ششم

IIFE تابعی است که به محض تعریف شدن اجرا می‌شود. این تابع به طور معمول ناشناس (بی‌نام) است، اما می‌تواند دارای نام نیز باشد. در ادامه نمونه‌ای از یک IIFE را می‌بینید.

(function() {
  console.log("Hi, I'm IIFE!");
})();
// outputs "Hi, I'm IIFE!"

اگر تفاوت بین گزاره‌های تابعی (function a () {}) و عبارت تابعی (var a = function() {}) را به خاطر داشته باشید، متوجه خواهید شد که IIFE یک عبارت تابعی است. برای این که آن را به یک عبارت تبدیل کنیم، اعلان تابع را درون پرانتز قرار می‌دهیم. در واقع با انجام این کار به پارسر اعلام می‌کنیم این یک عبارت و نه یک گزاره است.

پس از تابع دو پرانتز مشاهده می‌شود که نشانگر شیوه اجرای تابع اعلان شده است.

تابع درون IIFE لزومی به ناشناس بودن ندارد. در واقع تخصیص نام به این توابع به درستی کار می‌کند و به تشخیص مشکلات در زمان دیباگ کردن مشکلات کمک زیادی خواهد کرد.

(function myIIFEFunc() {
  console.log("Hi, I'm IIFE!");
})();
// outputs "Hi, I'm IIFE!"

توابع IIFE می‌توانند پارامتر بگیرند.

(function myIIFEFunc(param1) {
  console.log("Hi, I'm IIFE, " + param1);
})("Yuri");
// outputs "Hi, I'm IIFE, Yuri!"

در کد فوق Yuri به پارامتر param1 تابع ارسال شده است.

توابع IIFE می‌توانند مقداری بازگشت دهند.

var result = (function myIIFEFunc(param1) {
  console.log("Hi, I'm IIFE, " + param1);
  return 1;
})("Yuri");
// outputs "Hi, I'm IIFE, Yuri!"
// result variable will contain 1

نیازی به قرار دادن اعلان تابع درون پرانتز وجود ندارد، گرچه این رایج‌ترین شیوه تعریف IIFE است. در عوض می‌توانید از هر یک از شکل‌های زیر بهره بگیرید.

  • ~function(){console.log(“hi I’m IIFE”)}()
  • !function(){console.log(“hi I’m IIFE”)}()
  • +function(){console.log(“hi I’m IIFE”)}()
  • -function(){console.log(“hi I’m IIFE”)}()
  • (function(){console.log(“hi I’m IIFE”)}());
  • var i = function(){console.log(“hi I’m IIFE”)}();
  • true && function(){ console.log(“hi I’m IIFE”) }();
  • 0, function(){ console.log(“hi I’m IIFE”) }();
  • new function(){ console.log(“hi I’m IIFE”) }
  • new function(){ console.log(“hi I’m IIFE”) }()

توجه کنید که نباید از همه این اشکال تعریف تابع همزمان استفاده کنید، این موارد صرفاً به این خاطر ارائه شده‌اند که هر گاه آن‌ها را در قطعه کدی دید شگفت‌زده نشوید.

کاربردها و فواید ‌IIFE

متغیرها و توابعی که درون IIFE اعلان می‌شوند از دید دنیای خارج پنهان هستند. این مسئله موجب ایجاد خصوصیات و فواید زیر می‌شود.

  • از IIFE برای جدا کردن بخشی از کد و پنهان کردن جزئیات پیاده‌سازی استفاده کنید.
  • اینترفیس ورودی کد را با ارسال اشیای سراسری پر استفاده (از قبیل window, document, jQuery و غیره)، پارامترهای IIFE و سپس ارجاع به این اشیای سراسری درون IIFE از طریق یک دامنه لوکال مشخص‌تر کنید.
  • زمانی که کلوژر داخل حلقه قرار دارد می‌توانید از توابع IIFE درون کلوژر استفاده کنید.
  • IIFE مبنای الگوی ماژول در کد ES5 است و به جلوگیری از آلودگی دامنه سراسری کمک کرده و اینترفیس ماژول را در اختیار دنیای بیرون قرار می‌دهد.

پاسخ سؤال بیست و هفتم

«الگوی سینگلتون» (singleton pattern) یک الگوی طراحی پراستفاده در جاوا اسکریپت محسوب می‌شود. این الگو روشی برای بسته‌بندی کد درون یک واحد منطقی ارائه می‌کند که می‌تواند از طریق یک متغیر منفرد مورد دسترسی قرار گیرد. الگوی طراحی سینگلتون زمانی استفاده می‌شود مکه تنها یک وهله از شیء در سراسر عمر اپلیکیشن مورد نیاز باشد. در جاوا اسکریپت الگوی سینگلتون کاربردهای زیادی دارد و می‌تواند برای ایجاد فضای نام (NameSpacing) استفاده شود که موجب کاهش تعداد متغیرهای سراسری در صفحه شود. همچنین برای سازمان‌دهی کد به یک شیوه منسجم نیز کاربرد دارد که موجب افزایش خوانایی و قابلیت نگهداری صفحه‌های خواهد شد.

دو نکته مهم در مورد تعریف سنتی از الگوی سینگلتون وجود دارند:

  1. تنها یک وهله مجاز برای هر کلاس باید وجود داشته باشد
  2. و باید امکان نقطه دسترسی سراسری به آن وهله سینگلتون عرضه شده باشد.

تعریف الگوی سینگلتون در چارچوب جاوا اسکریپت به صورت زیر است:

سینگلتون شیئی است که برای ایجاد فضای نام و گروه‌بندی مجموعه مرتبطی از متدها و خصوصیات (کپسوله‌سازی) مورد استفاده قرار می‌گیرد و اگر امکان مقداردهی داشته باشد، تنها یک بار می‌تواند مقداردهی شود.

در جاوا اسکریپت می‌توان از طریق «لفظ شیئی» (object literal) یک سینگلتون ساخت. با این حال روش‌های دیگری نیز به این منظور وجود دارند.

یک شیء سینگلتون از دو بخش تشکیل یافته است که بخش اول خود شیء است که شامل اعضا (چه متد و جه خصوصیت) می‌شود و دیگری متغیر سراسری است که برای دسترسی به شیء مورد استفاده قرار می‌گیرد. متغیر به این جهت سراسری تعریف می‌شود که بتوان از هر جایی در صفحه به شیء سینگلتون دسترسی افت چون این یک خصوصیت کلیدی الگوی سینگلتون محسوب می‌شود.

سینگلتون به مثابه فضای نام در جاوا اسکریپت

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

function findUserName(id) {

}

/* Later in the page another programmer
added code */
var findUserName = $('#user_list');

/* You are trying to call :( */
console.log(findUserName())

یکی از بهترین روش‌ها برای جلوگیری از بازنویسی تصادفی متغیر این است که کد خود را درون یک شیء سینگلتون به صورت فضای نام دربیاورید.

/*  Using Namespace */

var MyNameSpace = {
  findUserName : function(id) {},
  // Other methods and attribute go here as well
}

/* Later in the page another programmer
added code */
var findUserName = $('#user_list');

/* You are trying to call and you make this time workable */
console.log(MyNameSpace.findUserName());

پیاده‌سازی الگوی طراحی سینگلتون

/* Lazy Instantiation skeleton for a singleton pattern */

var MyNameSpace = {};
MyNameSpace.Singleton = (function() {

  // Private attribute that holds the single instance
  var singletonInstance;  

  // All of the normal code goes here
  function constructor() {
    // Private members
    var privateVar1 = "Nishant";
    var privateVar2 = [1,2,3,4,5];

    function privateMethod1() {
      // code stuff
    }

    function privateMethod1() {
      // code stuff
    }

    return {
      attribute1 : "Nishant",
      publicMethod: function() {
        alert("Nishant");// some code logic
      }
    }
  }

  return {
    // public method (Global access point to Singleton object)
    getInstance: function() {
      //instance already exist then return  
      if(!singletonInstance) {
        singletonInstance = constructor();
      }
      return singletonInstance;           
    }           
  }

})();   

// getting access of publicMethod
console.log(MyNamespace.Singleton.getInstance().publicMethod());

سینگلتون پیاده‌سازی شده فوق به سادگی درک می‌شود. کلاس سینگلتون یک ارجاع استاتیک به وهله منفرد سینگلتون نگه می‌دارد و این ارجاع را از طریق متد استاتیک ()getInstance بازگشت می‌دهد.

پاسخ سؤال بیست و هشتم

روش‌های مختلفی برای ایجاد شیء در جاوا اسکریپت وجود دارند که در ادامه برخی از آن‌ها را بر می‌شماریم.

روش یکم: بر اساس تابع

این روش زمانی مفید است که بخواهیم چند شیء مشابه را ایجاد کنیم. در نمونه کد زیر تابع Employee را نوشته‌ایم و از طریق فراخوانی‌اش با عملگر new از آن به عنوان یک سازنده بهره گرفته‌ایم.

  function Employee(fName, lName, age, salary){
  	this.firstName = fName;
  	this.lastName = lName;
  	this.age = age;
  	this.salary = salary;
  }

  // Creating multiple object which have similar property but diff value assigned to object property.
  var employee1 = new Employee('John', 'Moto', 24, '5000$');
  var employee2 = new Employee('Ryan', 'Jor', 26, '3000$');
  var employee3 = new Employee('Andre', 'Salt', 26, '4000$');

روش دوم: لفظ شیئی

لفظ شیئی بهترین روش برای ایجاد یک شیء است و کاربرد زیادی دارد. در ادامه نمونه کدی برای ایجاد شیء کارمند (employee) می‌بینید که شامل مشخصه‌ها و همچنین متد است.

var employee = {
	name : 'Nishant',
	salary : 245678,
	getName : function(){
		return this.name;
	}
}

نمونه کد زیر یک لفظ شیئی تودرتو است که در آن آدرس یک شیء درون شیء کارمند است.

var employee = {
	name : 'Nishant',
	salary : 245678,
	address : {
		addressLine1 : 'BITS Pilani',
		addressLine2 : 'Vidya Vihar'.
		phoneNumber: {
		  workPhone: 7098889765,
		  homePhone: 1234567898
		}
	}
}

روش سوم: ساخت از Object با استفاده از کلیدواژه new

در کد زیر یک شیء ساده با استفاده از تابع سازنده Object ساخته می‌شود.

var employee = new Object(); // Created employee object using new keywords and Object()
employee.name = 'Nishant';
employee.getName = function(){
	return this.name;
}

روش چهارم: ** با استفاده از Object.create

تابع Object.create(obj) یک شیء جدید ایجاد کرده و obj را برابر با پروتوتایپ آن قرار می‌دهد. این یک روش مدرن برای ایجاد اشیا است که در آن مشخصه‌ها از اشیای دیگر ارث‌بری می‌کنند. تابع Object.create سازنده را اجرا نمی‌کند. امکان استفاده از Object.create(null) در مواردی که قصد ارث‌بری مشخصه‌ها از Object را نداشته باشیم نیز فراهم آمده است.

پاسخ سؤال بیست و نهم

function deepClone(object){
	var newObject = {};
	for(var key in object){
		if(typeof object[key] === 'object'  && object[key] !== null ){
		 newObject[key] = deepClone(object[key]);
		}else{
		 newObject[key] = object[key];
		}
	}
	return newObject;
}

در این سؤال از ما خواسته شده است که یک کپی عمیق از شیء بسازیم و از این رو باید ابتدا معنی کپی عمیق را بدانیم. فرض کنید یک شیء به نام personalDetail به شما داده شده و این شیء شامل برخی مشخصه‌ها است که خود نوعی شیء هستند. برای نمونه چنان که می‌بینیم address یک شیء است و نیز یک address و یک شیء است به بیان ساده یک شیء تودرتو است. به این ترتیب کپی عمیق به این معنا است که باید یک کپی از همه مشخصه‌های شیء personalDetail داشته باشیم که حتی شامل شیء تودرتو نیز باشد.

var personalDetail = {
	name : 'Nishant',
	address : {
	  location: 'xyz',
	  zip : '123456',
	  phoneNumber : {
	    homePhone: 8797912345,
	    workPhone : 1234509876
	  }
	}
}

بنابراین زمانی که یک کلون عمیق ایجاد می‌کنیم باید همه مشخصه‌ها از جمله اشیای تودرتو را نیز کپی کنیم.

پاسخ سؤال سی‌ام

فرض کنید شیئی به نام person داریم.

var person = {
	name: 'Nishant',
	age : 24
}

در این کد شیء person دارای مشخصه‌های name و age است. اکنون تلاش می‌کنیم تا به مشخصه salary دسترسی پیدا کنیم که روی شیء person اعلان شده، اما در زمان دسترسی یک مقدار تعریف نشده بازگشت می‌یابد. اینک سؤال این است که پیش از اجرای هر نوع عملیات روی یک شیء از کجا می‌توانیم مطمئن باشیم که کدام مشخصه تعریف نشده است؟

امکان استفاده از عملگر typeof برای بررسی undefined به شکل زیر وجود دارد.

if(typeof someProperty === 'undefined'){
	console.log('something is undefined here');
}

اکنون تلاش می‌کنیم به مشخصه حقوق شیء person دسترسی داشته باشیم.

if(typeof person.salary === 'undefined'){
	console.log("salary is undefined here because we haven't declared");
}

پاسخ سؤال سی و یکم

function Clone(object){
  var newObject = {};
  for(var key in object){
  	newObject[key] = object[key];
  }
  return newObject;
}

پاسخ سؤال سی و دوم

از promise برای مدیریت تعامل‌های ناهمگام به شیوه ترتیبی استفاده می‌کنیم. این موارد به طور خاص زمانی مفید هستند که یک عملیات ناهمگام (async) انجام داده باشیم و «سپس» بخواهیم بر مبنای نتایج عملیات نخست، عملیات ناهمگام دیگری انجام دهیم. برای نمونه اگر بخواهیم فهرست همه پروازها را به دست آوریم و سپس در مورد برخی پروازها که علاقه‌مند هستیم، جزییات بیشتری ببینیم، می‌توانیم از پرامیس بهره بگیریم. پرامیس نماینده یک مقدار آتی است. پرامیس یک وضعیت درونی به شکل‌های pending, fulfilled و rejected دارد و به عنان یک ماشین حالت عمل می‌کند.

شیء promise دارای متد then است که در آن کاری که پس از برآورده یا رد شدن پرامیس باید انجام یابد را مشخص می‌کنیم.

می‌توان بلوک‌های ()‌then را به هم زنجیر کرد و از این رو از بروز زنجیره تودرتوی callback اجتناب ورزید. امکان مدیریت خطاها در بلوک ()catch وجود دارد. پس از آن که یک پرامیس وارد حالت موفقیت یا شکست شد، «تغییرناپذیر» (immutable) می‌شود.

همچنین لازم به ذکر است که باید در مورد مفاهیم پیچیده‌تر مانند زیر نیز اطلاعات داشته باشید.

  • async/await موجب می‌شود که ظاهر کد هر چه بیشتر سرراست شود.
  • observable-های RxJS را می‌توان به عنوان پرامیس‌های قابل بازیافت در نظر گرفت.

در هر صورت باید مطمئن شوید که امکان پیاده‌سازی پرامیس را دارید.

پاسخ سؤال سی و سوم

فرض کنید یک شیء person با مشخصه name و age مانند زیر داریم:

var person = {
	name: 'Nishant',
	age: 24
}

اکنون می‌خواهیم بررسی کنیم مشخصه name در شیء person وجود دارد یا نه. در شیء جاوا اسکریپت می‌توان یک مشخصه تعریف کرد. در مثال فوق، نام و سن مشخصه‌های خود شیء فرد (person) هستند. همچنین شیء برخی مشخصه‌های ارث‌بری‌شده از شیء مبنا از قبیل toString دارد.

بنابراین سؤال این است که چطور باید بررسی کنیم مشخصه‌ها متعلق به خود شیء هستند یا ارث‌بری شده‌اند؟

روش اول: ما می‌توانیم از عملگر in روی شیء استفاده کنیم تا ببینیم آیا مشخصه متعلق به خودش است یا ارث‌بری شده است.

console.log('name' in person); // checking own property print true
console.log('salary' in person); // checking undefined property print false

عملگر in همچنین به دنبال مشخصه ارث‌بری‌شده می‌گردد تا ببیند آیا مشخصه تعریف شده را به عنوان مشخصه خودشی پیدا می‌کند یا نه. برای نمونه اگر وجود مشخصه toString را بررسی کنیم، از آنجا که می‌دانیم این مشخصه را روی شیء person اعلان نکرده‌ایم، از این رو عملگر in روی مشخصه‌های مبنا به دنبال آن می‌گردد.

به مثال زیر توجه کنید.

console.log('toString' in person); // Will print true

اگر بخواهیم مشخصه یک وهله از شیء را بررسی کنیم که مشخصه ارث‌بری شده است یا نه، از متد hasOwnProperty وهله شیء استفاده می‌کنیم.

console.log(person.hasOwnProperty('toString')); // print false
console.log(person.hasOwnProperty('name')); // print true
console.log(person.hasOwnProperty('salary')); // print false

پاسخ سؤال سی و چهارم

NaN اختصاری برای عبارت «غیر عددی» (not a number) است و در صورتی که بخواهید یک عملیات حسابی روی چنین مقادیری اجرا کنید، ممکن است موجب از کار افتادن عملیات شود. در ادامه برخی از مواردی که می‌توانید مقدار NaN دریافت نمایید را ملاحظه می‌کنید.

Math.sqrt(-5);
Math.log(-1);
parseFloat("foo"); /* this is common: you get JSON from the server, convert some strings from JSON to a number and end up with NaN in your UI. */

NaN با هیچ عددی برابر نخواهد بود، کمتر یا بیشتر از هیچ عددی نمی‌شود و هرگز حتی با خودش هم برابر نیست:

NaN !== NaN
NaN < 2 // false
NaN > 2 // false
NaN === 2 // false

برای این که بررسی کنیم آیا متغیر کنونی NaN است یا خیر، می‌توانیم از تابع isNaN بهره بگیریم. به همین جهت است که غالباً NaN را در صفحه‌ها می‌بینیم، چون به بررسی خاصی نیاز دارد که بسیاری از توسعه‌دهندگان اجرای آن را فراموش می‌کنند.

پاسخ سؤال سی و پنجم

در صورت استفاده از ES6 می‌توانستیم var i را با let i عوض کنیم. اما در ES5 باید یک دامنه تابع مانند زیر بسازیم:

var arr = [10, 32, 65, 2];
for (var i = 0; i < arr.length; i++) {
  setTimeout(function(j) {
    return function () {
      console.log('The index of this number is: ' + j)
    };
  }(i), 3000);
}

این نتیجه با استفاده از forEach نیز حاصل می‌شود.

var arr = [10, 32, 65, 2];
arr.forEach(function(ele, i) {
  setTimeout(function() {
    console.log('The index of this number is: ' + i);
  }, 3000);
})

پاسخ سؤال سی و ششم

در اغلب مواقع متوجه می‌شویم که لازم است بررسی کنیم نوع متغیری آرایه است یا نه. برای نمونه در کد زیر نوعی عملیات را بر اساس نوع مقدار اجرا می‌کنیم.

function(value){
	if("value is an array"){
		// Then perform some operation
	}else{
		// otherwise
	}
}

در ادامه با روش‌های تشخیص آرایه در جاوا اسکریپت آشنا می‌شویم.

روش اول: یک روش عالی به این منظور به صورت زیر است.

	function isArray(value){
		return Object.prototype.toString.call(value) === '[object Array]';
	}

این رویکرد محبوب‌ترین روش برای تشخیص یک مقدار از نوع آرایه در جاوا اسکریپت است و استفاده از
آن توصیه می‌شود. این رویکرد بر این واقعیت استوار است که متد نیتیو ()toString روی یک مقدار مفروض یک رشته استاندارد در همه مرورگرها ایجاد می‌کند.

روش دوم

تست نوع‌بندی اردکی برای تشخیص نوع آرایه

 // Duck typing arrays
 function isArray(value){
 	return typeof value.sort === 'function';
 }

چنان که می‌بینیم متد isArray زمانی مقدار درست بازگشت می‌دهد که شیء مورد بررسی دارای متد sort از نوع function باشد. اکنون فرض کنید شیئی با متد سورت ایجاد کردده باشیم:

	var bar = {
		sort: function(){
			// Some code 
		}
	}

اکنون زمانی که isArray(bar) را بررسی کنیم، مقدار true بازگشت می‌دهد، زیرا شیء‌ bar دارای متد sort است، اما واقعیت این است که bar آرایه نیست.

بنابراین این روش بهترین روش برای تشخیص یک آرایه نیست، زیرا حالتی که شیء دارای متد sort باشد را مدیریت نمی‌کند.

روش سوم

ECMAScript 5 یک متد به نام ()Array.isArray معرفی کرده است که مقدار نوع آرایه را تشخیص می‌دهد. تنها هدف این متد آن است که به درستی تشخیص دهد آیا مقدار مفروض یک آرایه است یا نه. در بسیاری از کتابخانه‌های جاوا اسکریپت ممکن است کد زیر را برای تشخیص آرایه بودن ببینید.

function(value){
   // ECMAScript 5 feature
	if(typeof Array.isArray === 'function'){
		return Array.isArray(value);
	}else{
	   return Object.prototype.toString.call(value) === '[object Array]';
	}
}

روش چهارم

امکان کوئری زدن به نام سازنده نیز وجود دارد:

function isArray(value) {
	return value.constructor.name === "Array";
}

روش پنجم

همچنین می‌توان با استفاده از instanceof Array آرایه بودن یک مقدار را بررسی کرد:

function isArray(value) {
	return value instanceof Array;
}

پاسخ سؤال سی و هفتم

اشیای جاوا اسکریپت به صورت ارجاعی فراخوانی می‌شوند. هر مقدار به جز مقادیر ابتدایی قطعاً یک نوع ارجاعی است. چند نوع ارجاعی داخلی مانند Object, Array, Function, Date, null و Error در جاوا اسکریپت وجود دارند.

تشخیص یک شیء با استفاده از عملگر typeof ممکن است.

console.log(typeof {});           // object
console.log(typeof []);           // object
console.log(typeof new Array());  // object
console.log(typeof null);         // object 
console.log(typeof new RegExp()); // object
console.log(typeof new Date());   // object

اما عیب استفاده از عملگر typeof برای تشخیص نوع شیء این است که برای null نیز مقدار object بازگشت می‌دهد.

بهترین روش برای تشخیص یک شیء با نوع ارجاعی خاص استفاده از عملگر instanceof است.

//Detecting an array
if(value instanceof Array){
	console.log("value is type of array");
}
// Employee constructor function
function Employee(name){
	this.name = name; // Public property
}

var emp1 = new Employee('John');

console.log(emp1 instanceof Employee); // true

عملگر instanceof نه تنها سازنده‌ای که برای ایجاد یک شیء استفاده شده را تشخیص می‌دهد، بلکه زنجیره پروتوتایپ آن را نیز مورد بررسی قرار می‌دهد.

console.log(emp1 instanceof Object); // true

پاسخ سؤال سی و هشتم

متد ()Object.create در ECMAScript 5 آسان‌ترین روش برای ارث‌بری یک شیء از شیء دیگر بدون احضار تابع سازنده است. به مثال زیر توجه کنید.

var employee = {
  name: 'Nishant',
  displayName: function () {
    console.log(this.name);
  }
};

var emp1 = Object.create(employee);
console.log(emp1.displayName());  // output "Nishant"

در مثال فوق یک شیء جدید به نام emp1 ایجاد می‌کنیم که از employee ارث‌بری می‌کند. به بیان دیگر پروتوتایپ emp1 روی employee تنظیم شده است. پس از آن، این emp1 توانایی دسترسی به همان مشخصه‌ها و متد را روی employee پیدا می‌کند تا این که مشخصه‌ها یا متد جدید با همان نام تعریف شود.

برای نمونه تعریف کردن متد ()displayName روی emp1 موجب باطل شدن خودکار displayName در employee نمی‌‌شود.

emp1.displayName = function() {
	console.log('xyz-Anonymous');
};

employee.displayName(); //Nishant
emp1.displayName();//xyz-Anonymous

علاوه بر این متد ()Object.create امکان تعیین آرگومان دوم را نیز می‌دهد که یک شیء شامل مشخصه‌ها و متد‌های اضافی برای افزودن به شیء جدید است. به مثال زیر توجه کنید.

var emp1 = Object.create(employee, {
	name: {
		value: "John"
	}
});

emp1.displayName(); // "John"
employee.displayName(); // "Nishant"

در مثال فوق، emp1 با نام خودش ایجاد شده است، از این رو با فراخوانی متد ()displayName به جای Nishant با مقدار John مواجه می‌شویم. شیئی که به این روش ایجاد شود کنترل کاملی روی شیء جدیداً ایجاد شده می‌دهد. به این ترتیب آزاد هستید که هر مشخصه و متدی که می‌خواهید را حذف/اضافه کنید.

پاسخ سؤال سی و نهم

فرض کنید کلاس Person را داریم که دارای مشخصه‌های نام، سن، حقوق و متد ()incrementSalary است.

function Person(name, age, salary) {
  this.name = name;
  this.age = age;
  this.salary = salary;
  this.incrementSalary = function (byValue) {
    this.salary = this.salary + byValue;
  };
}

اکنون می‌خواهیم کلاس Employee را ایجاد کنیم که شامل همه مشخصه‌های کلاس Person است و همچنین می‌خواهیم مشخصه‌های دیگری را وارد کلاس Employee بکنیم.

function Employee(company){
	this.company = company;
}

//Prototypal Inheritance 
Employee.prototype = new Person("Nishant", 24,5000);

در مثال فوق نوع Employee از نوع Person ارث‌بری می‌کند. این کار از طریق ساخت وهله جدیدی از Person از روی پروتوتایپ Employee انجام می‌یابد. در ادامه هر وهله از Employee از مشخصه‌ها و متدهای Employee ارث خواهد برد.

//Prototypal Inheritance 
Employee.prototype = new Person("Nishant", 24,5000);

var emp1 = new Employee("Google");

console.log(emp1 instanceof Person); // true
console.log(emp1 instanceof Employee); // true

اینک وراثت سازنده را بررسی می‌کنیم.

//Defined Person class
function Person(name){
	this.name = name || "Nishant";
}

var obj = {};

// obj inherit Person class properties and method 
Person.call(obj); // constructor inheritance

console.log(obj); // Object {name: "Nishant"}

در کد فوق می‌بینیم که با فراخوانی Person.call(obj) مشخصه‌های نام از Person به obj تعریف می‌شوند.

console.log(name in obj); // true

وراثت مبتنی بر نوع بهتر است با تابع سازنده تعریف شده توسعه‌دهنده استفاده شود تا توابع نیتیو جاوا اسکریپت. همچنین امکان ایجاد انعطاف در شیوه ساخت نوع‌های مشابه از شیء در اختیار ما قرار می‌دهد.

پاسخ سؤال چهلم

ECMAScript 5 چندین روش برای جلوگیری از دستکاری شیء ارائه کرده است شیء را قفل می‌کند تا مطمئن شود که هیچ کس به طور تصادفی یا به هر طریق دیگر کارکرد شیء را تغییر نمی‌دهد. سه سطح از ممانعت دستکاری اشیا به شرح زیر وجود دارد.

اکستنشن‌های ممانعت

در این روش هیچ مشخصه یا متد جدید نمی‌تواند به شیء اضافه شود، اما فرد می‌تواند مشخصه‌ها یا متدهای موجود را تغییر دهد. به مثال زیر توجه کنید:

var employee = {
	name: "Nishant"
};

// lock the object 
Object.preventExtensions(employee);

// Now try to change the employee object property name
employee.name = "John"; // work fine 

//Now try to add some new property to the object
employee.age = 24; // fails silently unless it's inside the strict mode

مهروموم

این روش مشابه روش قبلی است به جز این که از حذف شدن مشخصه‌ها و متدهای موجود نیز ممانعت می‌کند.

برای مهروموم کردن یک شیء باید از متد ()Object.seal استفاده کنید. امکان بررسی کردن مهروموم بودن یکشی نیز با استفاده از ()Object.isSealed وجود دارد.

var employee = {
	name: "Nishant"
};

// Seal the object 
Object.seal(employee);

console.log(Object.isExtensible(employee)); // false
console.log(Object.isSealed(employee)); // true

delete employee.name // fails silently unless it's in strict mode

// Trying to add new property will give an error
employee.age = 30; // fails silently unless in strict mode

هنگامی که یک شیء مهروموم می‌شود، مشخصه‌ها و متدهای موجود نمی‌توانند حذف شوند. شیء مهروموم شده غیر قابل بسط نیز هست.

فریز کردن

در این روش نیز مشابه مهروموم کردن، امکان دستکاری مشخصه‌ها و متدهای موجود وجود ندارد و همه این موارد فقط-خواندنی هستند. برای فریز کردن یک شیء باید از متد استفاده کنیم. همچنین می‌توانیم وضعیت فریز بودن را با استفاده از ()Object.isFrozen بررسی کنیم.

var employee = {
	name: "Nishant"
};

//Freeze the object
Object.freeze(employee); 

// Seal the object 
Object.seal(employee);

console.log(Object.isExtensible(employee)); // false
console.log(Object.isSealed(employee));     // true
console.log(Object.isFrozen(employee));     // true


employee.name = "xyz"; // fails silently unless in strict mode
employee.age = 30;     // fails silently unless in strict mode
delete employee.name   // fails silently unless it's in strict mode

اشیای فرز شده هم مهر و موم و هم غیر قابل بسط هستند.

توصیه‌های مهم

اگر تصمیم دارید جلوی دستکاری یک شیء را بگیرید، آن را مهروموم یا فریز بکنید و سپس در حالت strict مورد استفاده قرار دهید تا بتوانید خطاها را به دام بیندازید. به مثال زیر توجه کنید.

"use strict";

var employee = {
	name: "Nishant"
};

//Freeze the object
Object.freeze(employee); 

// Seal the object 
Object.seal(employee);

console.log(Object.isExtensible(employee)); // false
console.log(Object.isSealed(employee));     // true
console.log(Object.isFrozen(employee));     // true


employee.name = "xyz"; // fails silently unless in strict mode
employee.age = 30;     // fails silently unless in strict mode
delete employee.name;  // fails silently unless it's in strict mode

پاسخ سؤال چهل و یکم

لاگ کردن پیام‌های خطا یا برخی پیام‌های آگاهی‌بخش در زمان کار با سمت کلاینت جاوا اسکریپت با استفاده از متد console.log امری ضروری محسوب می‌شود. گاهی اوقات لازم است که نوعی پیشوند به پیام‌های لاگ اضافه کنیم تا مشخص شود کهان پیام از سمت یک اپلیکیشن خاص تولید شده است. یک روش کلی برای انجام این کار این است که به همه پیامک‌های لاگ در کنسول یک نام مانند زیر اضافه کنیم:

console.log('your app name' + 'some error message');

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

function appLog() {
  var args = Array.prototype.slice.call(arguments);
  args.unshift('your app name');
  console.log.apply(console, args);
}

appLog("Some error message"); 
//output of above console: 'your app name Some error message'

پاسخ سؤال چهل و دوم

امکان استفاده از عملگر typeof برای تست این که رشته‌ای لفظی است وجود دارد و عملگر instanceof نیز شیء بودن رشته را بررسی می‌کند.

 function isString(str) {
 	return typeof(str) == 'string' || str instanceof String;
 }
 
 var ltrlStr = "Hi I am string literal";
 var objStr = new String("Hi I am string object");
 console.log(isString(ltrlStr)); // true
 console.log(isString(objStr)); // true

پاسخ سؤال چهل و سوم

تابع‌های بی‌نام (anonymous) به طور معمول در موارد زیر به کار گرفته می‌شوند.

استفاده بی‌درنگ

در صورتی که تابع بلافاصله پس از ایجاد مورد استفاده قرار گیرد، نیاز به نام نخواهد داشت. به عنوان مثال تابع setTimeout را در نظر بگیرید:

setTimeout(function(){
	alert("Hello");
},1000);

در حالت فوق نیازی به استفاده از تابع نام‌دار وجود ندارد، چون مطمئن هستیم که این تابع که عبارت hello را نمایش می‌دهد تنها یک بار در اپلیکیشن استفاده می‌شود.

اعلان درون‌خطی تابع

اعلان تابع‌ها به روش درون‌خطی (inline) مزیت‌های زیادی دارد، از جمله امکان دسترسی به متغیر در دامنه کنونی را فراهم می‌سازد. برای نمونه یک مثال از «دستگیره رویداد» (event handler) را در نظر بگیرید. این دستگیره وجود یک نوع خاصی از رویداد را برای یک شیء خاص هشدار می‌دهد. فرض کنید یک عنصر HTML مانند یک Button داریم که می‌خواهیم روی آن یک دستگیره رویداد برای کلیک کردن اضافه کنیم تا وقتی کاربر روی دکمه کلیک کرد برخی کدها اجرا شوند.

<button id="myBtn"></button>

شنونده رویداد را نیز اضافه می‌کنیم.

var btn = document.getElementById('myBtn');
btn.addEventListener('click', function () {
  alert('button clicked');
});

مثال فوق کاربرد تابع بی‌نام را به عنوان یک تابع callback در دستگیره رویداد نشان می‌دهد.

ارسال تابع بی‌نام به صورت پارامتر در زمان فراخوانی تابع

به مثال زیر توجه کنید.

// Function which will execute callback function
function processCallback(callback){
	if(typeof callback === 'function'){
		callback();
	}
}

// Call function and pass anonymous function as callback 
processCallback(function(){
	alert("Hi I am anonymous callback function");
});

بهترین روش برای تصمیم‌گیری در مرد استفاده از تابع بی‌نام این است که سؤالات زیر را از خود بپرسیم:

  • آیا تابعی که تعریف می‌کنیم، جای دیگری استفاده خواهد شد؟

اگر پاسخ مثبت باشد، در این صورت باید از تابع نام‌دار استفاده شود و در غیر این صورت می‌توان از تابع بی‌نام کمک گرفت.

مزیت استفاده از تابع بی‌نام

  1. کدهای که باید نوشته شود کاهش می‌یابند و این موضوع در موارد تابع بازگشتی و همچنین تابع callback مصداق بیشتری دارد.
  2. از آلودگی غیرضروری فضای نام سراسری جلوگیری می‌شود.

پاسخ سؤال چهل و چهارم

اگر قبلاً با زبان‌های برنامه‌نویسی پایتون یا سی شارپ آشنا باشید، ممکن است با روش استفاده از مقدار پیش‌فرض برای پارامترهای تابع آشنایی داشته باشید. به مثال زیر توجه کنید:

// Define sentEmail function 
// configuration : Configuration object
// provider : Email Service provider, Default would be gmail
def sentEmail(configuration, provider = 'Gmail'):
	# Your code logic

قبل از معرفی ES6/ES2015

تا قبل از معرفی ES6/ES2015 روش‌های زیادی برای انجام این کار وجود داشت. در ادامه کدی ارائه شده است که مقدار پارامتر پیش‌فرض را به یکی از این روش‌ها تعیین می‌کند.

روش اول تعیین مقدار پارامتر پیش‌فرض

function sentEmail(configuration, provider) {
  // Set default value if user has not passed value for provider
  provider = typeof provider !== 'undefined' ? provider : 'Gmail'  
  // Your code logic
;
}
// In this call we are not passing provider parameter value
sentEmail({
  from: 'xyz@gmail.com',
  subject: 'Test Email'
});
// Here we are passing Yahoo Mail as a provider value
sentEmail({
  from: 'xyz@gmail.com',
  subject: 'Test Email'
}, 'Yahoo Mail');

روش دوم تعیین مقدار پارامتر پیش‌فرض

function sentEmail(configuration, provider) {
  // Set default value if user has not passed value for provider
  provider = provider || 'Gmail'  
  // Your code logic
;
}
// In this call we are not passing provider parameter value
sentEmail({
  from: 'xyz@gmail.com',
  subject: 'Test Email'
});
// Here we are passing Yahoo Mail as a provider value
sentEmail({
  from: 'xyz@gmail.com',
  subject: 'Test Email'
}, 'Yahoo Mail');

روش سوم تعیین مقدار پارامتر پیش‌فرض

function sendEmail(configuration, provider = "Gmail") {
  // Set default value if user has not passed value for provider
  
  // Value of provider can be accessed directly
  console.log(`Provider: ${provider}`);
}

// In this call we are not passing provider parameter value
sentEmail({
  from: 'xyz@gmail.com',
  subject: 'Test Email'
});
// Here we are passing Yahoo Mail as a provider value
sentEmail({
  from: 'xyz@gmail.com',
  subject: 'Test Email'
}, 'Yahoo Mail');

پاسخ سؤال چهل و پنجم

merge(person , address); 
 
/* Now person should have 5 properties 
name , age , addressLine1 , addressLine2 , city */

روش اول: استفاده از ES6 و متد Object.assign

const merge = (toObj, fromObj) => Object.assign(toObj, fromObj);

روش دوم: بدون استفاده از تابع داخلی

function merge(toObj, fromObj) {
  // Make sure both of the parameter is an object
  if (typeof toObj === 'object' && typeof fromObj === 'object') {
    for (var pro in fromObj) {
      // Assign only own properties not inherited properties
      if (fromObj.hasOwnProperty(pro)) {
        // Assign property and value
        toObj[pro] = fromObj[pro];
      }
    }
  }else{
  	throw "Merge function can apply only on object";
  }
}

پاسخ سؤال چهل و ششم

اشیای جاوا اسکریپت می‌توانند مشخصه‌هایی داشته باشند که وقتی با استفاده از حلقه for روی شیء می‌چرخید یا از ()Object.keys برای دریافت نام‌های مشخصه‌ها استفاده می‌کنید ظاهر نشوند. این مشخصه‌ها به نام «مشخصه‌های غیر شمارشی» (non-enumerable properties) نامیده می‌شوند.

فرض کنید شیء زیر را داریم:

var person = {
	name: 'John'
};
person.salary = '10000$';
person['country'] = 'USA';

console.log(Object.keys(person)); // ['name', 'salary', 'country']

از آنجا که می‌دانیم شیء person دارای مشخصه‌های شمارشی name, salary و country است، هنگامی که Object.keys(person) را فرا بخوانیم ظاهر خواهند شد. برای ایجاد مشخصه غیر شمارشی باید از ()Object.defineProperty استفاده کنیم. این یک متد خاص برای ایجاد مشخصه غیر شمارشی در جاوا اسکریپت است.

var person = {
	name: 'John'
};
person.salary = '10000$';
person['country'] = 'USA';

// Create non-enumerable property
Object.defineProperty(person, 'phoneNo',{
	value : '8888888888',
	enumerable: false
})

Object.keys(person); // ['name', 'salary', 'country']

در مثال فوق مشخصه phoneNo نشان داده نمی‌شود زیرا با تنظیم enumerable:false آن را غیر شمارشی کرده‌ایم.

نکته مهم

اکنون فرض کنید می‌خواهیم مقدار phoneNo را تغییر دهیم.

person.phoneNo = '7777777777';

متد ()Object.defineProperty امکان ایجاد مشخصه‌های «فقط-خواندنی» چنان که در بالا دیدیم را دارد و از این رو امکان دستکاری تغییر را در یک شیء person نداریم. دلیل این امر آن است که descriptor دارای مشخصه writable است که به طور پیش‌فرض FALSE است. تغییر دادن مقدار مشخصه غیر نوشتنی در حالت strict خطا بازگشت می‌دهد. در حالت غیر strict هیچ خطایی اتفاق نمی‌افتد، اما مقدار phoneNo تغییر نخواهد یافت.

پاسخ سؤال چهل و هفتم

اتصال تابع در حیطه موارد پیشرفته جاوا اسکریپت قرار می‌گیرد و یک تکنیک بسیار محبوب برای استفاده همراه با دستگیره رویداد و تابع کالبک جهت حفظ چارچوب کد اجرایی در زمان ارسال تابع به صورت پارامتر به حساب می‌آید.

مثال زیر را در نظر بگیرید.

var clickHandler = {
	message: 'click event handler',
	handleClick: function(event) {
		console.log(this.message);
	}
};

var btn = document.getElementById('myBtn');
// Add click event to btn
btn.addEventListener('click', clickHandler.handleClick);

در کد فوق شیء clickHandler ایجاد شده است که شامل مشخصه‌های پیام و متد handleClick است.

ما متد handleClick را به یک دکمه DOM انتساب داده‌ایم که در پاسخ به فرایند کلیک اجرا می‌شود. هنگامی که دکمه کلیک شود، متد handleClick فراخوانی می‌شود و پیام کنسول فراخوانده می‌شود. در اینجا console.log باید پیام click event handler را لاگ کند، اما در عمل undefined را لاگ می‌کند.

مشکل نمایش undefined به این دلیل است که چارچوب اجرایی متد clickHandler.handleClick ذخیره نمی‌شود و از این رو this بله شیء دکمه btn اشاره می‌کند. با استفاده از متد bind می‌توانیم این مشکل را رفع کنیم.

var clickHandler = {
	message: 'click event handler',
	handleClick: function(event) {
		console.log(this.message);
	}
};

var btn = document.getElementById('myBtn');
// Add click event to btn and bind the clickHandler object
btn.addEventListener('click', clickHandler.handleClick.bind(clickHandler));

متد bind مشابه متدهای call و apply برای همه تابع‌ها عرضه شده و مقدار آرگومان this را می‌گیرد.

پاسخ سؤال چهل و هشتم

خروجی کد فوق hi there است، زیرا در این جا به رشته‌ها سروکار داریم. رشته‌ها به صورت مقداری ارسال می‌شوند یعنی کپی خواهند شد.

پاسخ سؤال چهل و نهم

خروجی کد فوق به صورت {prop1: 90} است زیرا در اینجا با اشیا سروکار داریم. اشیا به صورت ارجاعی ارسال می‌شوند، یعنی objA و objB در حافظه شیء یکسانی هستند.

پاسخ سؤال پنجاهم

خروجی این کد به صورت {prop1: 42} است. زمانی که objA به objB انتساب می‌یابد، متغیر objB به همان شیء که متغیر objb اشاره دارد، اشاره خواهد کرد.

اما زمانی که objB را برابر با یک شیء خالی قرار دهیم، در واقع ارجاع متغیر objB را به آن تغییر داده‌ایم. این کار تأثیری روی ارجاع متغیر objA نمی‌گذارد.

پاسخ سؤال پنجاه و یکم

خروجی این کد به صورت [42,1,2,3,4,5] است. آرایه‌ها در جاوا اسکریپت شیء محسوب می‌شوند. به صورت ارجاعی ارسال شده و انتساب می‌یابند. به همین دلیل است که هم arrA و هم arrB به همان آرایه اشاره دارند. از این رو تغییر دادن عنصر نخست آرایه arrB موجب ایجاد تغییر در arrA نیز می‌شود، چون در حافظه همان آرایه است.

پاسخ سؤال پنجاه و دوم

خروجی این کد به صورت است. تابع slice همه عناصر آرایه را کپی کرده و یک آرایه جدید بازگشت می‌دهد. به همین دلیل است که arrA و arrB به دو آرایه کاملاً متفاوت اشاره می‌کنند.

پاسخ سؤال پنجاه و سوم

خروجی این کد به صورت زیر است:

[{prop1: 42}, {someProp: "also value of array A!"}, 3,4,5]

آرایه‌ها اشیای جاوا اسکریپت هستند و از این رو هر دو متغیر arrA و arrB به آرایه یکسانی اشاره دارند. تغییر دادن arrB[0] همان تغییر دادن آرایه arrA[0] است.

پاسخ سؤال پنجاه و چهارم

خروجی این کد به صورت زیر است:

[{prop1: 42}, {someProp: "also value of array A!"}, 3,4,5]

تابع slice همه عناصر آرایه را کپی کرده و یک آرایه جدید بازگشت می‌دهد. با این حال این کپی یک کپی عمیق نیست؛ بلکه کپی سطحی انجام می‌یابد. این Slice که اجرا شده را می‌توان به صورت زیر تصور کرد:

function slice(arr) {
   var result = [];
   for (i = 0; i< arr.length; i++) {
       result.push(arr[i]);
   }
   return result; 
}

به خط result.push(arr[i]) نگاه کنید. اگر arr[i] بر حسب تصادف عدد یا رشته باشد به صورت مقداری ارسال می‌شود، یعنی کپی می‌شود. اگر arr[i] آرایه باشد، به صورت ارجاعی ارسال می‌شود.

در صورتی که آرایه arr[i] یک شیء باشد، {prop1: “value of array A!!”} تنها ارجاع به این شیء کپی خواهد شد. این حرف به آن معنی است که آرایه‌های arrA و arrB دارای دو عنصر ابتدایی مشترک هستند.

به همین دلیل است گه تغییر دادن مشخصه arrB[0] در arrB موجب ایجاد تغییر در arrA[0] نیز می‌شود.

پاسخ سؤال پنجاه و پنجم

ReferenceError: employeeId is not defined

پاسخ سؤال پنجاه و ششم

Undefined

پاسخ سؤال پنجاه و هفتم

Undefined

پاسخ سؤال پنجاه و هشتم

Undefined

پاسخ سؤال پنجاه و نهم

undefined

پاسخ سؤال شصتم

‘123bcd’

پاسخ سؤال شصت و یکم

‘abc123’

پاسخ سؤال شصت و دوم

Function

پاسخ سؤال شصت و سوم

undefined

پاسخ سؤال شصت و چهارم

function function

پاسخ سؤال شصت و پنجم

[“name”, “salary”, “country”, “phoneNo”]

پاسخ سؤال شصت و ششم

[“name”, “salary”, “country”]

پاسخ سؤال شصت و هفتم

false false

پاسخ سؤال شصت و هشتم

false false

پاسخ سؤال شصت و نهم

false false

پاسخ سؤال هفتادم

false false

پاسخ سؤال هفتاد و یکم

true true

پاسخ سؤال هفتاد و دوم

true true true true

پاسخ سؤال هفتاد و سوم

bar bar

پاسخ سؤال هفتاد و چهارم

foo foo

پاسخ سؤال هفتاد و پنجم

undefined undefined

پاسخ سؤال هفتاد و ششم

[“100”] 1

پاسخ سؤال هفتاد و هفتم

[] [] [Array[5]] 1

پاسخ سؤال هفتاد و هشتم

11

پاسخ سؤال هفتاد و نهم

6

پاسخ سؤال هشتادم

[‘dog’, ‘rat’, ‘goat’, ‘cow’, ‘horse’, ‘cat’]

پاسخ سؤال هشتاد و یکم

1 -1 -1 4

پاسخ سؤال هشتاد و دوم

1 6 -1

پاسخ سؤال هشتاد و سوم

[2, 4, 8, 12, 16] true

پاسخ سؤال هشتاد و چهارم

[2, ’12’, true] [2, ’12’, true] [2, ’12’, true] [2, ’12’, true]

پاسخ سؤال هشتاد و پنجم

[‘bar’, ‘john’, ‘ritz’] [‘bar’, ‘john’] [‘foo’, ‘bar’, ‘john’, ‘ritz’] [] [‘foo’, ‘bar’, ‘john’, ‘ritz’]

پاسخ سؤال هشتاد و ششم

[‘bar’, ‘john’] [] [‘foo’]

پاسخ سؤال هشتاد و هفتم

[15, 16, 2, 23, 42, 8]

پاسخ سؤال هشتاد و هشتم

1

پاسخ سؤال هشتاد و نهم

undefined true

پاسخ سؤال نودم

Hello

پاسخ سؤال نود و یکم

undefined

پاسخ سؤال نود و دوم

‘Hello’

پاسخ سؤال نود و سوم

undefined

پاسخ سؤال نود و چهارم

‘Hi John’

پاسخ سؤال نود و پنجم

‘Hi John’

پاسخ سؤال نود و ششم

a) 2 2 2

پاسخ سؤال نود و هفتم

0 2 4

پاسخ سؤال نود و هشتم

John Person

پاسخ سؤال نود و نهم

12345678 undefined

پاسخ سؤال صدم

undefined

پاسخ سؤال صد و یکم

bq1uy 1BJKSJ bq1uy

پاسخ سؤال صد و دوم

foo123 aq123

پاسخ سؤال صد و سوم

[‘W’, ‘o’, ‘r’, ‘l’, ‘d’]

پاسخ سؤال صد و چهارم

Total amount left in account: 5600 Total amount left in account: 5300

پاسخ سؤال صد و پنجم

5600 5300 5100

پاسخ سؤال صد و ششم

3600 3300 3100

پاسخ سؤال صد و هفتم

Hello John

6. Suggest your question!

پاسخ سؤال صد و هشتم

John

پاسخ سؤال صد و نهم

[2, 8, 15, 16, 23, 42] [2, 8, 15, 16, 23, 42] [2, 8, 15, 16, 23, 42]

پاسخ سؤال صد و دهم

Uncaught TypeError: Cannot read property ‘fullName’ of undefined

پاسخ سؤال صد و یازدهم

5

پاسخ سؤال صد و دوازدهم

undefined

پاسخ سؤال صد و سیزدهم

6, 10

پاسخ سؤال صد و چهاردهم

6, 10

پاسخ سؤال صد و پانزدهم

720

پاسخ سؤال صد و شانزدهم

Tony undefined

توجه کنید که تابع ()getName1 به درستی کار می‌کند، زیرا از personObj فراخوانی شده و از این رو به مشخصه this.name دسترسی دارد. اما هنگامی که بخواهیم getnName2 را فرا بخوانیم که تحت Object.prototype تعریف شده، هیچ مشخصه‌ای به نام this.name ندارد. باید یک مشخصه به نام name تحت پروتوتایپ وجود داشته باشد. کد آن چنین است:

function getName1(){
	console.log(this.name);
}

Object.prototype.getName2 = () =>{
  console.log(Object.getPrototypeOf(this).name);
}

let personObj = {
	name:"Tony",
	print:getName1
}

personObj.print();
Object.prototype.name="Steve";
personObj.getName2();

سخن پایانی

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

اگر این مطلب برای شما مفید بوده است، آموزش‌ها و مطالب زیر نیز به شما پیشنهاد می‌شوند:

بر اساس رای 2 نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.

«میثم لطفی» در رشته‌های ریاضیات کاربردی و مهندسی کامپیوتر به تحصیل پرداخته و شیفته فناوری است. وی در حال حاضر علاوه بر پیگیری علاقه‌مندی‌هایش در رشته‌های برنامه‌نویسی، کپی‌رایتینگ و محتوای چندرسانه‌ای، در زمینه نگارش مقالاتی با محوریت نرم‌افزار با مجله فرادرس همکاری دارد.

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *