Примитивные типы и ссылочные типы
В JavaScript типы данных можно разделить на примитивные типы и ссылочные типы.
Существует шесть основных типов:Null, Undefined, String, Boolean, Number, Symbol;
И эталонный тип легендарныйObject.
Базовый тип передается по значению, а значение ссылочного типа доступно по ссылке, поэтому, когда вы манипулируете объектом, вы фактически манипулируете ссылкой на объект вместо фактического объекта (ps: при добавлении свойств к объекту , операция является фактическим объектом).
О разнице между примитивными типами и ссылочными типами, наверное, есть следующие моменты:
1. Ссылочные типы являются динамическими свойствами, а примитивные типы — нет.
Для ссылочных типов мы можем добавлять и удалять свойства и методы, но мы не можем добавлять свойства к значениям примитивных типов:
// 基本类型
var name = 'Fly_001';
name.age = 22;
alert(name.age); // undefined;
// 引用类型
var person = new Object();
person.name = 'Fly_001';
alert(person.name); // 'Fly_001';
2. Способ копирования разный.
При копировании из одной переменной в другуюбазовый тип, скопирует значение в место, назначенное новой переменной:
var num1 = 5;
var num2 = num1;
Когда NUM2 инициализируется со значением NUM1, значение 5 также сохраняется в NUM2, но это значение является просто копией 5 в NUM1, а две переменные не влияют на друг друга.
При копировании из одной переменной в другуютип ссылки, передавая указатель на объект, хранящийся в куче, после завершения копирования две переменные фактически будут ссылаться на один и тот же объект, и изменение одной повлияет на другую:
var obj1 = new Object();
var obj2 = obj1;
obj1.name = 'Fly_001';
alert(obj2.name); // 'Fly_001';
3. Характеристики передаваемых параметров.
Это сбивающий с толку момент 😖.
Параметры всех функций в ECMAScript:передать по значениюиз. То есть копирование значения вне функции в параметр внутри функции аналогично копированию значения из одной переменной в другую. Передача значений базового типа аналогична копированию переменных базового типа, а передача ссылочных типов аналогична копированию переменных ссылочного типа.Это действительно вызовет разногласия среди многих мелких партнеров.Добро пожаловать к обсуждению~
-
При передаче значения примитивного типа в аргумент переданное значение копируется в локальную переменную (то есть в элемент объекта arguments).
-
При передаче значения ссылочного типа в параметр адрес значения в памяти копируется в локальную переменную, поэтому изменения локальной переменной будут отражены вне функции:
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); // 20,木有变化;
alert(result); // 30
function setNmae(obj) {
obj.name = 'Fly_001';
}
var person = new Object();
setName(person);
alert(person.name); // 'Fly_001';
В приведенном выше коде мы создали объект и сохранили его в переменной person. Затем этот объект передается функции setName() и копируется в obj, а внутри этой функции obj и person ссылаются на один и тот же объект.
Многие друзья подумают, что параметр передается по ссылке.Чтобы доказать, что объект передается по значению, посмотрите на этот измененный код:
function setName(obj) {
obj.name = 'Fly_001';
obj = new Object();
obj.name = 'juejin';
}
var person = new Object();
setName(person);
alert(person.name); // 'Fly_001';
Если человек передается по ссылке, то человек автоматически модифицируется так, чтобы он указывал на новый объект, свойство имени которого равно 'juejin'. Но при следующем посещении person.name по-прежнему отображается «Fly_001», что означает, что даже если значение параметра будет изменено внутри функции, исходная ссылка останется прежней. (На самом деле, когда obj переопределяется внутри функции, переменная ссылается на локальный объект, который будет уничтожен сразу после завершения выполнения функции.)
4. Операторы типов обнаружения разные.
- Обнаружение примитивных типов целесообразно с помощью оператора typeof
alert(typeof 'Fly_001'); // 'string';
alert(typeof []); // 'object';
Поскольку возвращаемое значение оператора typeof является одним из следующих: «неопределенное», «строка», «логическое», «число», «символ», «объект», «функция».
Может быть очень удобно указывать конкретный базовый тип и возвращать 'object' в целом для ссылочных типов (typeof возвращает 'object' для массива, обычного и нулевого).
- При проверке ссылочных типов лучше использовать оператор instanceof:
result = varible instanceof constructor;
Если переменная является экземпляром данного ссылочного типа (Распознавание по цепочке прототипов) Оператор InstanceOF вернет True.
Среда выполнения и область применения
Давайте поговорим об очень важной концепции в JavaScript —среда исполнения.
Каждая среда выполнения в JS имеет связанный с ней переменный объект.Глобальный контекст выполнения — это объект окна., поэтому все глобальные переменные и функции создаются как свойства и методы объекта окна.
После того, как весь код в среде выполнения будет выполнен, среда будет уничтожена, и все сохраненные в ней определения переменных и функций также будут уничтожены, а глобальная среда выполнения не будет уничтожена до тех пор, пока не будет закрыта веб-страница или браузер (если есть закрытая Сумка, ситуация другая, будет упомянуто в следующих статьях 😅, спасибо Ву хр за исправление).
Каждая функция имеет свою среду выполнения. Когда поток выполнения входит в функцию, среда функции помещается в стек среды. После выполнения функции стек извлекает свою среду, возвращая управление предыдущей среде выполнения.
var color = 'blue';
function changeColor() {
var anotherColor = 'red';
function swapColors() {
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问 color、anotherColor 和 tempColor;
}
swapColors();
// 这里可以访问 color 和 anotherColor,但不能访问 tempColor;
}
changeColor();
// 这里只能访问 color;
Приведенный выше код включает всего 3 среды выполнения: глобальную среду, локальную среду changeColor() и локальную среду swapColor(). в,Внутренняя среда может получить доступ ко всем внешним средам через цепочку областей видимости, но внешняя среда не может получить доступ ни к каким переменным и функциям во внутренней среде.Связи между этими средами являются линейными и последовательными. Каждая среда может выполнять поиск имен переменных и функций вверх по цепочке областей видимости 🔍, но ни одна среда не может выполнять поиск вниз по цепочке областей видимости для входа в другую среду выполнения.
- Расширьте цепочку областей.
Хотя существуют только два типа среды выполнения - глобальные и локальные (функции), все еще есть два способа продлить цепочку объема ~ черезБлок catch и оператор with оператора try-catch.
Оба этих оператора добавляют переменный объект в начало цепочки областей видимости. Для оператора with указанный объект добавляется в цепочку областей видимости, для оператора catch создается новый объект-переменная, который содержит объявление сгенерированного объекта ошибки.
- Блока нет.
Отсутствие области видимости блока в JavaScript часто приводит к путанице 😲. В других C-подобных языках блоки кода, заключенные в фигурные скобки, имеют свою область видимости, среду выполнения, но в JavaScript это не так:
if (true) {
var color = 'blue';
}
alert(color); // 'blue';
for (var i = 0; i < 10; i ++) {
// dosomething
}
alert(i); // 10;
Переменные, объявленные с помощью var, автоматически добавляются в ближайшее окружение. Внутри функции ближайшей средой является локальная среда функции.Если переменная инициализируется без объявления var, переменная автоматически добавляется в глобальную среду. (Создавать локальные переменные с блочной областью более удобно, используя ключевое слово let.):
function add(num1, num2) {
var sum = num1 + num2;
return sum;
}
var result = add(10, 20); // 30;
alert(sum); // 'sum is not defined';
В приведенном выше коде, несмотря на то, что функция возвращает сумму, она недоступна вне функции. Если ключевое слово var опущено, то сумма доступна (хотя в строгом режиме инициализация необъявленной переменной будет сообщать об ошибке «xxx is notdefined»).
- Имитирует область видимости на уровне блоков.
Хотя js не имеет области действия на уровне блоков, мы можем использовать анонимные функции для имитации области действия на уровне блоков~ Синтаксис следующий:
(function() {
// 这里是块级作用域;
}) ();
Заключение объявления функции в паре круглых скобок указывает на то, что это на самом деле функциональное выражение, а следующие за ним круглые скобки немедленно вызывают функцию. на самом деле эквивалентно:
var someFunction() {
// 这里是块级作用域;
};
someFunction();
В то же время, поскольку JavaScript рассматривает ключевое слово function как начало объявления функции, за ним не могут следовать круглые скобки, а за выражением функции могут следовать круглые скобки, поэтому объявление функции плюс круглые скобки преобразуются в функциональное выражение.
Везде, где вам временно нужна какая-то переменная, вы можете использовать приватную область видимости:
function outputNumbers(count) {
(function () {
for (var i = 0; i < count; i ++) {
alert(i);
}
}) ();
alert(i); // 会导致错误,读取不到 i;
}
Поскольку любая переменная, определенная в анонимной функции, уничтожается сразу в конце выполнения, переменная i может использоваться только в цикле.
- Идентификатор запроса.
Когда на переменную или имя функции (идентификатор) ссылаются в среде для чтения или записи, ее необходимо искать, чтобы определить, что она на самом деле представляет.
Процесс поиска начинается с переднего конца области и ищет вверх уровень за уровнем.Если есть определение локальной переменной, поиск останавливается, то есть локальная переменная с тем же именем перезапишет глобальную переменную с таким же именем:
var color = 'blue';
function getColor() {
var color = 'red'; // 局部变量;
return color;
}
alert(getColor()); // 'red';
alert(window.color); // 'blue';
Вывоз мусора.
В JavaScript есть механизм автоматической сборки мусора, так что разработчикам не нужно беспокоиться об использовании памяти, разве это не безумие 🤗, но лучше знать 😕.
Во-первых, давайте проанализируем нормальный жизненный цикл локальных переменных в функциях: локальные переменные существуют только во время выполнения функции, и их память будет освобождена для дальнейшего использования после завершения выполнения функции. такСборщик мусора должен отслеживать, какие переменные полезны, а какие нет.Существуют две стратегии, специфичные для реализации браузера: удаление меток и подсчет ссылок.
- пометить как очищенный
Это наиболее часто используемый механизм сборки мусора в JavaScript.
Когда сборщик мусора работает, он помечает все переменные, хранящиеся в памяти, а затем удаляет теги переменных в среде и переменных, на которые ссылаются переменные в среде.
Переменные, помеченные после этого, будут рассматриваться как переменные, готовые к удалению, поскольку переменные в среде больше не доступны. Наконец, сборщик мусора завершает очистку памяти, уничтожая отмеченные значения и освобождая место в памяти, которое они занимают.
- подсчет ссылок
Другой не очень популярной стратегией сборки мусора является подсчет ссылок.
В основном он отслеживает количество ссылок на каждое значение.Когда количество ссылок на значение равно 0, это означает, что нет способа получить доступ к значению, поэтому пространство памяти, занимаемое им, может быть освобождено.
Но будет счетчик ссылокциклическая ссылкаЭта проблема:
function problem() {
var objA = new Object();
var objB = new Object();
objA.someOtherObject = objB;
objB.anotherObject = objA;
}
То есть после выполнения функции objA и objB будут продолжать существовать, поэтому их опорные времена никогда не будут равны 0. Если эта функция вызывается повторно, большой объем памяти не будет восстановлен 😱.
Чтобы избежать подобных проблем с циклическими ссылками, лучше отключить их вручную, когда вы их не используете:
objA.someOtherObject = null;
objB.anotherObject = null;
При следующем запуске сборщика мусора эти значения удаляются, а занимаемая ими память освобождается.
Tips:一旦数据不再有用,最好将其设为 null。
(Это относится к глобальным переменным и свойствам глобальных объектов, поскольку локальные переменные автоматически разряжены, когда они оставляют контекст выполнения).
Хорошо, давайте сначала поговорим об основных переменных, области видимости и сборке мусора JavaScript, а в следующей статье мы поговорим об объектно-ориентированном программировании JavaScript и функциональных выражениях.
Если вам это нравится, давайте обновим его снова, большое спасибо~ 🤗