Контент

  1. Введение
  2. Контент/данные в объекте
  3. Вычисляемые ключи
  4. Массивы
  5. Глубокое копирование
  6. Дескрипторы свойств
  7. Неизменный
  8. Геттер и сеттер
  9. Существование

1. ВВЕДЕНИЕ

Возможно, вы слышали, что все в JS является объектом (хотя и не совсем так). Но почему? В этой статье, я надеюсь, вы поймете причину.

Давайте начнем.

Итак, как сказано, все в Js не является объектом (например, строкой, числом, логическим значением, нулевым значением или неопределенным). Это все примитивные типы, а не объекты. Тип null — это объект, но в основном это ошибка.

Не говоря, что все в JS является объектом, мы можем противоречиво сказать, что существует существуетнесколько специальных подтипов объектов, которые мы можем назвать «сложными примитивами». ,'как функции (мы поговорим об этом позже).

Итак, на протяжении всего вашего пути вы столкнетесь с двумя типами форм объявления объектов.

(1. а)декларативная форма

const obj = {
  name: "Karan"
}

(1. б) сконструированная форма

const obj = new Object();
obj.name = "Karan"

Одно из различий, с которым вы столкнетесь между ними, заключается в том, что вы можете добавить только одно значение ключа к объекту за раз с помощью формы конструктора. И строка не равна строке, созданной объектом. То, что я имею в виду, здесь.

// reference from YOU DON'T KNOW JS 
var strPrimitive = "I am a string"; typeof strPrimitive; // "string" strPrimitive instanceof String; // false
var strObject = new String( "I am a string" ); typeof strObject; // "object"
strObject instanceof String; // true
// inspect the object sub-type
Object.prototype.toString.call( strObject );

Итак, если строка не является объектом и является примитивным типом, то как мы можем получить доступ к методам строки (например, к длине)? Ну, ну, благодаря принуждению JS. Итак, что происходит, когда вы вызываете любой метод для примитивного типа данных, такого как строка, язык внутренне преобразует строковый литерал в строковый объект (например, в приведенном выше фрагменте кода), а затем мы получаем доступ ко всем методам. .

[Примечание: следует помнить, что значения null и undefined не применяются принудительно и являются только примитивными.]

2. СОДЕРЖИМОЕ / ДАННЫЕ в объекте

Когда мы ссылаемся на содержимое или данные объекта, мы в основном указываем на значение и ключ, который содержит это значение. Честно говоря, это всего лишь внешний вид. Что происходит, так это то, что движок сохраняет ключ в этом объекте, и этот ключ содержит указатель, указывающий на данные.

(2.a) Разница между «.» и "[]"

Существует два способа доступа к данным внутри объекта.

const obj = {
  name: "Karan"
}

console.log(obj.name) // Karan
console.log(obj["name"]) // Karan 

Использование '.' обозначает доступ к свойству, а '[]' обозначает доступ по ключу. Помимо этого, вы не можете использовать такой ключ, как «Super-like» с нотацией «.», поэтому вы должны использовать его как objName[«Super-like»]. Это '.' нотация требует использования имени свойства, совместимого с идентификатором, тогда как нотация '[]' этого не требует.

Обратите внимание, что ключ всегда имеет строковый тип. Если вы используете число или логическое значение, то 2 считается «2», а «истина» считается «истиной» ]

// reference from YOU DON'T KNOW JS
var myObject = { };
myObject[true] = "foo"; 
myObject[3] = "bar"; 
myObject[myObject] = "baz";
myObject["true"]; // "foo" 
myObject["3"]; // "bar" myObject["[object Object]"];

3. Вычисляемые ключи

Короче говоря, если вы хотите, чтобы ключ вычислялся, скажем, из двух разных переменных, в ES6 есть новая функция, которая позволяет нам создавать ключ во время выполнения на основе содержащихся в нем значений. Похоже на это.

var prefix = "foo";
var myObject = {
[prefix + "bar"]: "hello", [prefix + "baz"]: "world"
};
myObject["foobar"]; // hello
myObject["foobaz"]; // world

4. Массивы

Какого черта мы перебираем массивы в статье объекта? Причина в том, что массивы также являются объектами (сложными объектами). Давайте сначала определим, что они собой представляют и как они являются объектами.

Массивы хранят данные так же, как и объекты. Разница в том, что индекс — это ключ, то есть число, а значение — это ссылка на местоположение этого индекса.

// reference from YOU DON'T KNOW JS
var myArray = [ "foo", 42, "bar" ]; 
myArray.length; // 3
myArray[0]; // "foo"
myArray[2]; // "bar"

Как уже было сказано, массивы — это не что иное, как объекты, а это значит, что мы также можем добавлять к ним свойства. И да, вы абсолютно правы. Мы можем добавлять свойства к таким объектам.

var myArray = [ "foo", 42, "bar" ]; 
myArray.baz = "baz"; 
myArray.length; // 3
myArray.baz; // "baz"

myArray.length; // 3

Почему, даже после того, как мы добавили свойства в массив, он по-прежнему имеет три длины? Во-первых, у массивов есть поведение и оптимизация, специфичные для их предполагаемого использования, и мы должны подчиняться им. Но да, если мы введем число вместо «баз», то это изменит значение этого массива.

"И именно поэтому было важно включить массивы в эту статью".

5. Глубокое копирование

Зачем нам нужно понимать, что такое глубокое копирование? И это тоже в Object. Причина этого в опциях и переменных, которые идут с ними.

ПРОБЛЕМА

Давайте посмотрим, почему даже копия является проблемой.

const obj1 = {
  a : 2,
  b: {
      name: "Karan"
  }
}

const obj2 = obj1;
const obj3 = {...obj1}

obj2.b.name = "Bairagi"
obj3.b.name = "Bairagii"

console.log(obj1) // expected (Karan) // got() Bairagii  
console.log(obj2) // expected (Bairagi) // got() Bairagii
console.log(obj3) // expectd (Bairagii) // got() Bairagii

Если вы внимательно посмотрите, то увидите, что значение имени obj1 также было изменено. Почему так? Причина - передача по ссылке. Когда мы приравниваем объект к другому объекту, примитивные типы данных копируются (новая копия) в новый объект. Это действительно только для самого внешнего уровня (то есть, если мы изменим значение obj3.a на 3, тогда obj1 и obj2 по-прежнему будут равны 2). Поэтому это называется 'поверхностной копией, которая просто создает новую копию примитивных типов данных на самом внешнем уровне и дает ссылки на непримитивные типы (объект и массив).

РЕШЕНИЕ

Итак, совершенно очевидно, что решение этой проблемы заключается в создании глубокой копии всего исходного объекта и размещении этой копии в целевом объекте.

Один из способов сделать это — сделать рекурсивный вызов (DFS) и скопировать каждый элемент один за другим. Но это не будет работать везде. Давайте посмотрим на приведенный ниже пример.

1.  function anotherFunction() { /*..*/ }
2.
3.  var anotherObject = { c: true
4.  };
5. 
6.  var anotherArray = [];
7. 
8.  var myObject = { 
9.     a: 2,
10. b: another object, a reference, not a copy! 
11.    c: anotherArray, // another reference!
12.    d: anotherFunction
13. };
14.
15. anotherArray.push( anotherObject, myObject );

В этой ситуации, если вы заметили, другой массив в строке номер 15 копирует мой объект, массив, другое уведомление, ситуацию, а внутри моего объектау нас есть другой массив со значением c в нем.

Это означает, что если мы выберем глубокое копирование с рекурсивным вызовом, это войдет в бесконечный цикл. Итак, это подводит нас к решению, которое предпочитают многие разработчики.

То есть ……… с использованием объекта JSON.

const obj1 = JSON.parse(JSON.string(obj2))

[Примечание: чтобы этот объект JSON работал, позаботьтесь о том, чтобы объект был безопасным для JSON]

Это будет работать для вас большую часть времени, но у него также есть некоторые дыры (я вернусь к этому позже). Таким образом, самым надежным решением является метод Object.assign, предоставляемый ES6.

const obj1 = Object.assign(//target object, // to copy from object)

6. Дескрипторы свойств

Как ясно из названия, дескрипторы свойств — это не что иное, как нечто, что помогает нам указать описание свойства объекта или может быть вызвано ключом объекта.

Даже несмотря на то, что как разработчик вы, возможно, не сталкивались с такими дескрипторами, потому что JS по умолчанию присваивает некоторые дескрипторы свойству этого конкретного объекта.

Так выглядит под капотом.

var myObject = { a:2
};

Object.getOwnPropertyDescriptor( myObject, "a" ); // {
// value: 2,
//    writable: true,
//    enumerable: true,
//    configurable: true
// }

Итак, что это такое и для чего они используются? Прежде чем понять это, давайте посмотрим, как мы можем указать дескрипторы для свойства.

var myObject = {};

Object.defineProperty( myObject, "a", {
        value: 2,
        writable: true, 
        configurable: true, 
        enumerable: true
});

Теперь давайте разберем их один за другим.

ДОСТУПНО ДЛЯ ЗАПИСИ

Если вы установите для параметра writable значение FALSE, то вы не сможете изменить значение свойства.

var myObject = {};

Object.defineProperty( myObject, "a", {
        value: 2,
        writable: false, 
        configurable: true, 
        enumerable: true
});

myObject.a = 3;
console.log(myObject.a) // 2

Примечание. Если вы используете «строгий режим», будет выдана ошибка типа; в противном случае он не выдаст никаких ошибок. Даже если значение не изменится ни в каком режиме]

НАСТРОЙКА

Если вы установите для параметра configurable значение false, то после определения конфигурации вы не сможете установить ее снова.

var myObject = {};

Object.defineProperty( myObject, "a", {
        value: 2,
        writable: true, 
        configurable: false, 
        enumerable: true
});

Object.defineProperty( myObject, "a", {
        value: 3,
        writable: false, 
        configurable: false, 
        enumerable: true
}); // throws ERROR

ВЫБОР

Установка для перечисления значения false гарантирует, что данные не будут итерируемыми. То есть, когда вы просматриваете объект, он не будет отображаться в цикле. Как и другие, по умолчанию для него установлено значение true, поэтому вам не нужно ничего делать для повторения.

const obj = {}

Object.defineProperty(obj,"a",
  {enumerable: true, value: 2}
)

Object.defineProperty(obj,"b",
  {enumerable: false, value: 3}
)

Object.keys(obj).forEach((value) => {
    console.log(value) // a
})

// you can check if the property is enumerable or not by this method
myObject.propertyIsEnumerable( "a" ); // true
myObject.propertyIsEnumerable( "b" ); // false


// but let's say you want all the values whether it is enumerable or not
// then you can use this
Object.getOwnPropertyNames(obj).forEach((value) => {
    console.log(value) // a, b
})

Поскольку мы постоянно говорим об итерациях и перечислениях, давайте также рассмотрим здесь массивы. Ниже приведены некоторые из них

forEach: цикл повторяется до конца списка и всех данных, доступных для итерации.

const arr = [1,2,3,4]

arr.forEach((value) => console.log(value)) // 1,2,3,4

каждое: цикл повторяется до конца, пока обратный вызов не вернет false. (В основном работает как инструкция break)

const arr = [1,2,3,4]

arr.forEach((value) => {
  console.log(value)
  if (value === 2) {
    return false;
  }
}) // 1, 2

some:Это повторяется до конца, пока обратный вызов не вернет true.

const arr = [1,2,3,4]

arr.forEach((value) => {
  console.log(value)
  if (value === 3) {
    return true;
  }
}) // 1, 2, 3

Здесь есть еще один, который выполняет ту же работу, но о нем можно подробно рассказать. Итак, что, если вы хотите перебирать значения напрямую, а не индексы массива (или свойства объекта)?

Это можно сделать с помощью цикла for…of. Этот цикл перебирает значения, а не индексы. Сначала давайте посмотрим, как это выглядит на самом деле, а затем попробуем разобраться в этом.

const arr = [1,2,3]

for ( var i in arr ) {
  console.log(i) // 1, 2, 3
} 

Как мы видим здесь, цикл for…of перебирает значения, и важно понимать, как эта штука работает под капотом.

Когда создается экземпляр цикла for…of, цикл запрашивает объект итератора объекта для повторения. Это достигается с помощью внутренней функции, прикрепленной к массиву с именем @@iterator. Затем цикл использует свойство value объекта итератора и возвращает его для этой конкретной итерации. А затем использует функцию «следующий» для перехода к объекту итератора следующего элемента. Посмотрим, что в работе

 1. const arr = [1,2,3]
 2. const it = arr[Symbol.iterator]()
 3. 
 4. // if you are having a hard time understanding the above code
 5. // then please try to remember the way we retrive the data from array
 6. // and if you do remember then we can also add method to a
 7. // this arr.push = 3 will get us arr = [1, 2, 3, push: 3] and this is what 
 8. // the above code says. If you console Symbole.iterator will give Symbol(Symbol.iterator)
 9. // and the arr goes like arr = [1, 2, 3, Symbol(Symbol.iterator): function()...]
10. // and hence we are calling it in line number 2 with ().
11. 
12. // Let's manually implement them.
13. var arr = [1, 2, 3]
14. const it = arr[Symbol.iterator]();
15. it.next() {value: 1, done: false}
16. it.next() {value: 2, done: false}
17. it.next() {value: 3, done: false}
18. it.next() {done: true}

на каждой итерации у него есть свойство 2 в этом объекте, из которого значение дает значение, а выполнено представляет собой завершенную итерацию, и, следовательно, следующая функция выполняется 4 раза, чтобы убедиться, что итерация закончилась.

Тот же @@iterator недоступен для объектов, но если мы хотим, то можем создать свою функцию-итератор.

const obj = {
  a: "Karan",
  b: "Bairagi"
}

Object.defineProperty(obj, Symbol.iterator, {
  enumerable: false,
  writable: false,
  configurable: true,
  value: function () {
     const objectt = this; // points to the object
     let vidx = -1 // holds the virtual index for iteration
     const keysOfObject = Object.keys(objectt);
      console.log(objectt[keysOfObject[vidx++]])
     return { 
        next: function () {
          return {
            value: objectt[keysOfObject[vidx++]],
            done: (vidx > keysOfObject.length)
          };
        }
     }
  }
})

var it = obj[Symbol.iterator](); 
it.next(); // { value:Karan, done:false } 
it.next(); // { value:Bairagi, done:false } 
it.next(); // { value:undefined, done:true }

7. Неизменный

Есть способы сделать ваш объект неизменным. То есть всякий раз, когда вы не хотите, чтобы значение вашего объекта менялось, добавляя новую пару ключей или удаляя существующую.

Есть несколько способов добиться одного и того же. Давайте пройдемся по всем из них один за другим.

путем изменения дескрипторов свойств

var myObject = {};
Object.defineProperty( myObject, "FAVORITE_NUMBER", {
    value: 42,
    writable: false,
    configurable: false 
});

Запрещая расширение

Используя это, вы можете остановить добавление новых свойств к этому объекту.

var myObject = { a:2};
Object.preventExtensions( myObject );
myObject.b = 3; 
myObject.b; // undefined

С помощью Object.seal(..)

Это не только делает конфигурацию вашего свойства недоступной для записи, но также отключает Extension.

С помощью Object.freeze(..)

Это наивысший уровень неизменности, которого разработчик может достичь с объектом. Это использует Object.seal, но устанавливает для всех доступных для записи свойств значение false.

Примечание. Замораживается только внешний уровень свойства. Если вы хотите заморозить все внутренние свойства, сделайте рекурсивный вызов и заморозьте внутренние объекты.]

8. Геттер и сеттер

Как следует из названия, речь идет о способе установки и получения значения в объект и из него соответственно. Но ждать!!!!! Разве мы уже не знаем и не располагаем способами устанавливать и получать значение для объекта и из него?

const obj = {
  a: "Karan"
}

obj.a = "Bairagi"
console.log(obj.a) // Bairagi

Это выглядит примерно так, верно? Но здесь мы говорим о способе добавления промежуточного программного обеспечения или способе, с помощью которого мы можем обрабатывать часть способа JS для установки и получения значения из объекта.

Итак, мы говорим о специальной функции, которая существует и помогает нам определить способ, которым мы можем устанавливать и получать значения от объектов. Похоже на это.

const obj = {
// All this does is generate a key with the key "a" and the value 2.
  get a() {
    return 2
  }
}

console.log(Object.a) //2

Есть еще один способ создания функции-получателя.

// reference: YOU DON'T KNOW JS
const obj = {
  a: 2
}
Object.defineProperty(
  obj,
  b,
  {
    get: function(){return this.a * 2}
  }
)

console.log(obj.a) // 2
console.log(obj.b) // 4

Я надеюсь, вы поймали его. Оба этих способа делают одно и то же. Но здесь у нас есть проблема. Проблема в том, что если мы укажем функцию получения, а не сеттера, то сеттер не будет работать.

// reference: YOU DON'T KNOW JS
var myObject = {
// define a getter for `a` 
    get a() {
        return 2; }
    };
myObject.a = 3;
myObject.a; // 2

Это заставляет нас понять, что мы также должны указать сеттер. Что приводит нас к функции setter, которая выглядит так:

var myObject = {
// define a getter for `a` 
    get a() {
        return this._a_; 
    }
  
    set a(value) {
      this._a_ = value
    }
};
myObject.a = 3;
myObject.a; // 2

9. Существование

Под существованием я подразумеваю проверку того, доступно ли свойство в объекте или нет. Так что есть способы добиться этого.

const obj = {
  a: "Exists",
  b: undefined
}

obj.a // Exists
obj.b // undefined
obj.c // undefined

Вот как это делается, да? Но если вы правильно это заметите, то здесь, когда мы пытаемся получить доступ к «b», мы получаем undefined (поскольку ему присвоено значение undefined), и когда мы пытаемся получить доступ к «c», мы также получаем неопределенное (поскольку его нет в объекте ). Поэтому нам нужно что-то, чтобы сказать нам, является ли это свойством объекта или нет. JS предоставляет нам два способа сделать это.

const obj = {
  a: "Exists",
  b: undefined
}

("a" in obj) // true
("b" in obj) // true
("c" in obj) // false

obj.hasOwnProperty(a) // true
obj.hasOwnProperty(b) // true
obj.hasOwnProperty(c) // false

Это подводит нас к концу объектов. Я надеюсь, что эта статья помогла вам понять, что такое объекты и их детали. С учетом сказанного, если вы дошли до этого момента, пожалуйста, дайте отзыв о том, как это было и что я могу улучшить.

Ссылка: ВЫ НЕ ЗНАЕТЕ JS

Спасибо!!