JavaScript: в чем разница между функцией и классом

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

5 ответов

Технически нет класса, они оба просто функции. Любая функция может быть вызвана как конструктор с ключевым словом new и свойство prototype этой функции используется для объекта для наследования методов.

"Класс" используется только концептуально для описания вышеупомянутой практики.

Поэтому, когда кто-то говорит вам "сделайте цветовой класс" или что-то еще, вы сделаете:

function Color(r, g, b) {
    this.r = r;
    this.g = g;
    this.b = b;
}

Color.prototype.method1 = function() {

};

Color.prototype.method2 = function() {

};

Когда вы разбиваете его, есть просто функция и некоторые присвоения свойству prototype этой функции, весь общий синтаксис JavaScript, ничего особенного не происходит.

Все становится немного волшебным, когда вы говорите var black = new Color(0,0,0), Затем вы получите объект со свойствами .r, .g а также .b, Этот объект также будет иметь скрытую [[prototype]] ссылку на Color.prototype, Что означает, что вы можете сказать black.method1() даже если .method1() не существует в black объект.

JavaScript является наиболее популярной реализацией стандарта ECMAScript. Основные функции Javascript основаны на стандарте ECMAScript, но Javascript также имеет другие дополнительные функции, которых нет в спецификации / стандарте ECMA. У каждого браузера есть интерпретатор JavaScript.


Overview

" ECMAScript изначально разрабатывался как язык веб-сценариев, предоставляя механизм для оживления веб-страниц в браузерах и для выполнения вычислений на сервере как часть веб-архитектуры клиент-сервер. Язык сценариев - это язык программирования, который используется для управления, настройки и автоматизации возможностей существующей системы.

ECMAScript - это объектно-ориентированный язык программирования для выполнения вычислений и манипулирования вычислительными объектами в среде хоста. Веб-браузер предоставляет хост-среду ECMAScript для вычислений на стороне клиента, включая, например, объекты, которые представляют окна, меню, всплывающие окна, диалоговые окна, текстовые области, якоря, рамки, историю, файлы cookie и ввод / вывод.

ECMAScript основан на объектах: базовый язык и средства хоста предоставляются объектами, а программа ECMAScript представляет собой кластер взаимодействующих объектов.

Объекты "

  • Каждый конструктор является функцией, которая имеет свойство с именем “prototype” это используется для реализации наследования на основе прототипа и общих свойств.

  • Каждый объект, созданный конструктором, имеет неявную ссылку (называемую прототипом объекта) на значение его constructor’s “prototype” имущество. Кроме того, прототип может иметь ненулевую неявную ссылку на свой прототип и т. Д.; это называется prototype chain ,


функция

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

Подъем - это действие интерпретатора JavaScript по перемещению всех объявлений переменных и функций в начало текущей области видимости. Function Hoisting, declarations & expressions

FunctionDeclaration: функция BindingIdentifier ( FormalParameters) { FunctionBody } FunctionExpression: функция BindingIdentifier (FormalParameters) {FunctionBody}

ES5 Функция:

function Shape(id) { // Function Declaration
    this.id = id;
};
// prototype was created automatically when we declared the function
Shape.hasOwnProperty('prototype'); // true

// Adding a prototyped method to a function.
Shape.prototype.getID = function () {
    return this.id;
};

var expFn = Shape; // Function Expression
console.dir( expFn () ); // Function Executes and return default return type - 'undefined'

Для функции, если возвращаемое значение не указано, то undefined возвращается Если функция вызывается с new и возвращаемое значение не является объектом, то это (новый объект) возвращается.

ПРИМЕЧАНИЕ. Свойство прототипа автоматически создается для каждой функции, чтобы обеспечить возможность использования функции в качестве конструктора.

  • constructor "Функциональный объект, который создает и инициализирует объекты.
  • prototype "Объект, который предоставляет общие свойства для других объектов.
  • __proto__ "Свойство proto, указывающее на прототип суперобъекта. Если вы откроете его, то увидите, что прото указывает на его переменные и функции суперобъекта.

Чтобы получить доступ к методам-прототипам вышеупомянутой функции, мы должны создать объект, используя new ключевое слово вместе с constructor function, если вы создаете Shape - Object с помощью new Ключевое слово тогда имеет internal (or) private link функционировать по прототипу Shape,

Классы функций конструктора ES5: объекты функций, созданные с использованием Function.prototype.bind

Shape.prototype.setID = function ( id ) {
    this.id = id;
};

var funObj = new Shape( );
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 )
console.dir( funObj );

console.log( funObj.getID() );
/*
expFun                            funObj
    name: "Shape"                   id: 10
    prototype:Object
        constructor: function Shape(id)
        getID: function()
        setID: function( id )
    __proto__: function ()          __proto__: Object
                                        constructor: function Shape(id)
                                        getID: function()
                                        setID: function( id )
    <function scope>
*/

В ES6 появилась функция Arrow: выражение функции стрелки имеет более короткий синтаксис, чем выражение функции, и не связывает свой собственный this, arguments, super или new.target. Эти функциональные выражения лучше всего подходят для не-методических функций и не могут использоваться в качестве конструкторов. Производство грамматики ArrowFunction не имеет свойства прототипа.

ArrowFunction: ArrowParameters => ConciseBody

  a => (a < 10) ? 'valid' : 'invalid'

  const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
    console.log( fn(2) ); // Even
    console.log( fn(3) ); // Odd

Учебный класс

В объектно-ориентированном языке на основе классов в общем случае состояние передается экземплярами, методы - классами, а наследование - только по структуре и поведению. В ECMAScript состояние и методы переносятся объектами, а структура, поведение и состояние наследуются.

Babel - это компилятор JavaScript. Используйте его для трансформации ES6 в ES5 формат BABEL JS (или же) ES6Console,

ES6 Классы: ES2015 classes простой сахар по шаблону ОО на основе прототипа. Наличие единой удобной декларативной формы облегчает использование шаблонов классов и способствует взаимодействию. Классы поддерживают наследование на основе прототипов, супер вызовы, экземпляры и статические методы и конструкторы.

class Shape {
  constructor(id) {
    this.id = id
  }

  get uniqueID() {
    return this.id;
  }
  set uniqueID(changeVal) {
    this.id = changeVal;
  }
}
Shape.parent_S_V = 777;

// Class Inheritance
class Rectangle extends Shape {

  constructor(id, width, height) {
    super(id)
    this.width = width
    this.height = height
  }
  // Duplicate constructor in the same class are not allowed.
  /*constructor (width, height) { this._width  = width; this._height = height; }*/

  get area() {
    console.log('Area : ', this.width * this.height);
    return this.width * this.height
  }
  get globalValue() {
    console.log('GET ID : ', Rectangle._staticVar);
    return Rectangle._staticVar;
  }
  set globalValue(value) {
    Rectangle._staticVar = value;
    console.log('SET ID : ', Rectangle._staticVar);
  }

  static println() {
    console.log('Static Method');
  }

  // this.constructor.parent_S_V - Static property can be accessed by it's instances
  setStaticVar(staticVal) { // https://sckoverflow.com/a/42853205/5081877
    Rectangle.parent_S_V = staticVal;
    console.log('SET Instance Method Parent Class Static Value : ', Rectangle.parent_S_V);
  }

  getStaticVar() {
    console.log('GET Instance Method Parent Class Static Value : ', Rectangle.parent_S_V);
    return Rectangle.parent_S_V;
  }
}
Rectangle._staticVar = 77777;

var objTest = new Rectangle('Yash_777', 8, 7);
console.dir( objTest );

Функциональные классы ES5: использует Object.defineProperty ( O, P, Attributes )

Object.defineProperty() Метод определяет новое свойство непосредственно для объекта или изменяет существующее свойство объекта и возвращает объект.

Экземпляры функций, которые можно использовать в качестве конструктора, имеют свойство prototype.

Это свойство имеет атрибуты { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }.

    'use strict';
var Shape = function ( superClass ) {
    var currentClass = Shape;
    _inherits(currentClass, superClass); // Prototype Chain - Extends

    function Shape(id) { superClass.call(this); // Linking with SuperClass Constructor.
        // Instance Variables list.
        this.id = id;   return this;
    }
    var staticVariablesJOSN = { "parent_S_V" : 777 };
    staticVariable( currentClass, staticVariablesJOSN );

    // Setters, Getters, instanceMethods. [{}, {}];
    var instanceFunctions = [
        {
            key: 'uniqueID',
            get: function get() { return this.id; },
            set: function set(changeVal) { this.id = changeVal; }
        }
    ];
    instanceMethods( currentClass, instanceFunctions );

    return currentClass;
}(Object);

var Rectangle = function ( superClass ) {
    var currentClass = Rectangle;

    _inherits(currentClass, superClass); // Prototype Chain - Extends

    function Rectangle(id, width, height) { superClass.call(this, id); // Linking with SuperClass Constructor.

        this.width = width;
        this.height = height;   return this;
    }

    var staticVariablesJOSN = { "_staticVar" : 77777 };
    staticVariable( currentClass, staticVariablesJOSN );

    var staticFunctions = [
        {
            key: 'println',
            value: function println() { console.log('Static Method'); }
        }
    ];
    staticMethods(currentClass, staticFunctions);

    var instanceFunctions = [
        {
            key: 'setStaticVar',
            value: function setStaticVar(staticVal) {
                currentClass.parent_S_V = staticVal;
                console.log('SET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
            }
        }, {
            key: 'getStaticVar',
            value: function getStaticVar() {
                console.log('GET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
                return currentClass.parent_S_V;
            }
        }, {
            key: 'area',
            get: function get() {
                console.log('Area : ', this.width * this.height);
                return this.width * this.height;
                }
        }, {
            key: 'globalValue',
            get: function get() {
                console.log('GET ID : ', currentClass._staticVar);
                return currentClass._staticVar;
            },
            set: function set(value) {
                currentClass._staticVar = value;
                console.log('SET ID : ', currentClass._staticVar);
            }
        }
    ];
    instanceMethods( currentClass, instanceFunctions );

    return currentClass;
}(Shape);

// ===== ES5 Class Conversion Supported Functions =====
function defineProperties(target, props) {
    console.log(target, ' : ', props);
    for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}
function staticMethods( currentClass, staticProps ) {
    defineProperties(currentClass, staticProps);
};
function instanceMethods( currentClass, protoProps ) {
    defineProperties(currentClass.prototype, protoProps);
};
function staticVariable( currentClass, staticVariales ) {
    // Get Key Set and get its corresponding value.
    // currentClass.key = value;
    for( var prop in staticVariales ) {
        console.log('Keys : Values');
        if( staticVariales.hasOwnProperty( prop ) ) {
            console.log(prop, ' : ', staticVariales[ prop ] );
            currentClass[ prop ] = staticVariales[ prop ];
        }
    }
};
function _inherits(subClass, superClass) {
    console.log( subClass, ' : extends : ', superClass );
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, 
            { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });
    if (superClass)
        Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

var objTest = new Rectangle('Yash_777', 8, 7);
console.dir(objTest);

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

var obj1 = new Rectangle('R_1', 50, 20);
Rectangle.println(); // Static Method
console.log( obj1 );    // Rectangle {id: "R_1", width: 50, height: 20}
obj1.area;              // Area :  1000
obj1.globalValue;       // GET ID :  77777
obj1.globalValue = 88;  // SET ID :  88
obj1.globalValue;       // GET ID :  88  

var obj2 = new Rectangle('R_2', 5, 70);
console.log( obj2 );    // Rectangle {id: "R_2", width: 5, height: 70}
obj2.area;              // Area :  350    
obj2.globalValue;       // GET ID :  88
obj2.globalValue = 999; // SET ID :  999
obj2.globalValue;       // GET ID :  999

console.log('Static Variable Actions.');
obj1.globalValue;        // GET ID :  999

console.log('Parent Class Static variables');
obj1.getStaticVar();    // GET Instance Method Parent Class Static Value :  777
obj1.setStaticVar(7);   // SET Instance Method Parent Class Static Value :  7
obj1.getStaticVar();    // GET Instance Method Parent Class Static Value :  7


Основные различия между функциями и классами:

  • Объявления функций получают Hoisted К началу контекста, где в качестве деклараций классов и выражений функций не используется Hoisted.
  • Объявления функций, выражение может быть Overriddenкак они похожи на переменную - var если доступно несколько объявлений, то оно переопределяет родительскую область видимости. Где, поскольку Классы не Переопределены, они похожи let | const let не допускает многократное объявление с одним и тем же именем в своей области видимости.
  • Функции / классы допускают только один конструктор для своей области видимости.
  • Computed method names разрешены классы ES6, имеющие ключевое слово class, но ключевое слово function не позволяет

    function myFoo() {
     this.['my'+'Method'] = function () { console.log('Computed Function Method'); };
    }
    class Foo {
        ['my'+'Method']() { console.log('Computed Method'); }
    }
    

В javascript нет классов. javascript использует наследование прототипов, а не наследование на основе классов. Многие люди ссылаются на классы в javascript, потому что это легче понять, но это просто аналогия.

В наследовании на основе классов вы создаете класс ("план", если хотите), а затем создаете экземпляры объектов из этого класса.

При наследовании прототипа объект создается непосредственно из другого родительского объекта, без каких-либо "чертежей".

См. Страницу википедии для получения дополнительной информации о наследовании класса против прототипа.

Разница между конструктором function а также class

В class Ключевое слово в javascript очень похоже на функцию-конструктор следующим образом:

  • Оба они используют прототипную систему наследования javascript.
  • Оба они используются для создания объектов со следующим синтаксисом: new myObj(arg1, arg2)

Функции и классы-конструкторы очень похожи, часто могут использоваться взаимозаменяемо в зависимости от предпочтений. Однако частные поля javascript для классов - это функциональность, которая не может быть реализована функциями конструктора (без взлома области видимости)

Пример:

class PersonClass {
  constructor(name) {
    this.name = name;
  }
  
  speak () { console.log('hi'); }
}

console.log(typeof PersonClass); 
// logs function, a class is a constructor function under the hood.

console.log(PersonClass.prototype.speak);
// The class's methods are placed on the prototype of the PersonClass constructor function

const me = new PersonClass('Willem');

console.log(me.name); 
// logs Willem, properties assinged in the constructor are placed on the newly created object


// The constructor function equivalent would be the following:
function PersonFunction (name) {
  this.name = name;
}

PersonFunction.prototype.speak = function () { console.log('hi'); }

Учебный класс

Объявление класса ограничено его содержащим блоком. Дважды объявлять имя класса в одном блоке является ошибкой. Определение класса не поднимается.

Функции

Объявление функции - это блок в строгом режиме.

В таблице ниже приведены различия между классом и функцией.

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

Термин класс обычно используется в контексте объектно-ориентированного языка программирования. Класс - это шаблон объекта, который будет создан при создании экземпляра. JavaScript - это язык программирования, основанный на прототипах, поэтому немного странно использовать термин "класс" для описания прототипа JavaScript. В JavaScript прототипы создаются как функции

HackerRank является отличным примером в этом отношении. В принципе,

Важное различие между объявлениями функций и объявлениями классов заключается в том, что объявления функций поднимаются (т. Е. На них можно ссылаться до их объявления), а объявления классов - нет. Это означает, что мы должны сначала объявить наш класс, прежде чем пытаться получить к нему доступ (или ссылку); если мы этого не сделаем, наш код выдает ошибку ReferenceError.

Итак, если у нас есть

try {
    let p = new Polygon(1, 2);
    console.log('Polygon p:', p);
}
catch (exception) {
    console.log(exception.name + ': ' + exception.message);
}
class Polygon {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
}

p = new Polygon(1, 2);
console.log('Polygon p:', p);

Мы получим на выходе

ReferenceError: Polygon is not defined
Polygon p: Polygon { height: 1, width: 2 }
Другие вопросы по тегам