Repository: black-shadows/Cheat-Sheets Branch: master Commit: 811c97f72101 Files: 47 Total size: 1.6 MB Directory structure: gitextract_5wy5wbdt/ ├── Angular/ │ └── README.md ├── C++/ │ ├── C++ Syntax.md │ ├── Data Structures and Algorithms.md │ └── README.md ├── Command Line/ │ └── README.md ├── Django/ │ └── README.md ├── Elixir/ │ └── README.md ├── Git/ │ └── README.md ├── Golang/ │ ├── README.md │ └── golang_refcard.odt ├── Java/ │ ├── README.md │ └── todo.md ├── JavaScript/ │ ├── README.md │ ├── _config.yml │ └── translations/ │ ├── fr-FR.md │ ├── ja-JP.md │ ├── pl_PL.md │ ├── pt-BR.md │ ├── ru-RU.md │ ├── th-TH.md │ ├── zh-CN.md │ └── zh-TW.md ├── Kotlin/ │ └── README.md ├── MATLAB/ │ └── README.md ├── Markdown/ │ └── README.md ├── MongoDB/ │ ├── README.md │ └── sql_mongo_comparison.md ├── Oracle SQL/ │ ├── README.md │ └── SQL_commands.md ├── PHP/ │ └── README.md ├── Perl/ │ └── README.md ├── Python/ │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── README.md │ ├── _config.yml │ ├── blog_files/ │ │ ├── about.md │ │ └── pysheet.md │ ├── pyproject.toml │ └── python_cheat_sheet.ipynb ├── README.md ├── React/ │ ├── README.md │ └── react-placar.md ├── Ruby/ │ └── README.md ├── Ruby on Rails/ │ └── README.md ├── Scala/ │ └── README.md ├── Swift/ │ └── README.md └── TypeScript/ └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: Angular/README.md ================================================ # Angular Cheatsheet ##### Table of Contents [Basics](#basics) [Loop](#loop) [Html](#html) [Directives](#directives) [Services](#services) [Routing](#routing) [Filters](#filters) ## Basics **Setup** 0. You can use the official [Angular Seed Project](https://github.com/angular/angular-seed) for quick startup. 1. Create a new module named myApp ```javascript // ja > App.js var app = angular.module("myApp", []); ``` 2. add a directive: it tells AngularJS that the myApp module will live within the `` scope (or the whole page, ``) ```html ``` See: [more info on ng-app](https://docs.angularjs.org/api/ng/directive/ngApp) This is called “Bootstrapping”. Sometimes you want to [do it manually](https://docs.angularjs.org/guide/bootstrap#manual-initialization) (if you have multiple Angular apps for instance). 3. Create a new controller: manages the app's data. ```javascript // js > controllers > MainController.js app.controller('MainController', ['$scope', function($scope) { $scope.title = 'Top Sellers in Books'; }]); ``` 4. ng-controller is a directive that defines the controller scope ```html

{{ title }}

``` We access $scope.title using {{ title }}. That’s an expression: used to display values on the page. ### Namings **Binding** –– {{ ... }} **Expressions** –– something + '!' **Directives** –– **Template** –– (the part of the view containing the bindings and presentation logic) acts as a blueprint for how our data should be organized and presented to the user. **Controller** –– provides the context in which the bindings are evaluated and applies behavior and logic to our template. **Model** –– What the user sees after the page is fully rendered **Module** –– Child on Angular (usually it is the App in an Angular point of view) **Components** –– A combination of template + controller with an isolated scope (= no prototypal inheritance and no risk of our component affecting other parts of the application or vice versa) ([Docs](https://docs.angularjs.org/guide/component)) **DI / dependency injection** –– https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection ### misc **Price** ```html

{{ product.price | currency }}

``` AngularJS gets the value of product.price. It sends this number into the currency filter. The pipe symbol (|) takes the output on the left and "pipes" it to the right. The filter outputs a formatted currency with the dollar sign and the correct decimal places. **Date** ```javascript pubdate: new Date('2014', '03', '08') ``` ```html

{{ product.pubdate | date | uppercase }}

``` ## Loop ```javascript $scope.products = [ { name: 'The Book of Trees', price: 19, pubdate: new Date('2014', '03', '08'), cover: 'img/the-book-of-trees.jpg' }, { name: 'Program or be Programmed', price: 8, pubdate: new Date('2013', '08', '01'), cover: 'img/program-or-be-programmed.jpg' } ] ``` ```html

{{ product.name }}

{{ product.price | currency }}

{{ product.pubdate | date }}

{{ product.likes }}

``` ## Html ```html

{{ product.likes }}

``` ## Directives in js/directives/appInfo.js ```javascript app.directive('appInfo', function() { return { restrict: 'E', // specifies how directive will be used in view. 'E' means it will be used as a new HTML element. scope: { info: '=' // specifies that we will pass information into this directive through an attribute named info. The = tells the directive to look for an attribute named info in the element, like this: }, // The data in info becomes available to use in the template given by templateURL templateUrl: 'js/directives/appInfo.html', // specifies the HTML to use in order to display the data in scope.info. Here we use the HTML in js/directives/appInfo.html. link: function(scope, element, attrs) { // scope refers to the directive's scope. Any new properties attached to $scope will become available to use in the directive's template. element refers to the directive's HTML element. attrs contains the element's attributes. scope.buttonText = "Install", // property buttonText scope.installed = false, // property installed scope.download = function() { // function download() element.toggleClass('btn-active'); if(scope.installed) { scope.buttonText = "Install"; scope.installed = false; } else { scope.buttonText = "Uninstall"; scope.installed = true; } } } }; }); ``` in js/directives/appInfo.html ```html

{{ info.title }}

{{ info.developer }}

{{ info.price | currency }}

``` in index.html ```html ``` ## Services **js > services > forecast.js** ```javascript app.factory('forecast', ['$http', function($http) { // app.factory to create a new service named forecast + AngularJS's built-in $http to fetch JSON from the server return $http.get('https://s3.amazonaws.com/codecademy-content/courses/ltp4/forecast-api/forecast.json') // $http construct an HTTP GET request for the weather data (a json list from codecademy). .success(function(data) { // If the request succeeds, the weather data is returned; return data; }) .error(function(err) { // otherwise the error info is returned. return err; }); }]); ``` **js > controllers > MainController.js** ```javascript app.controller('MainController', ['$scope', 'forecast', function($scope, forecast) { // add forecast into MainController as dependency so that it's available to use. forecast.success(function(data) { // to asynchronously fetch the weather data from server $scope.fiveDay = data; // store it into $scope.fiveDay }); }]); // any properties attached to $scope become available to use in the view ``` **index.html** ```html

{{ fiveDay.city_name }}

``` ## Routing **app.config.js** ```javascript // new angular. module('phonecatApp'). config(['$locationProvider', '$routeProvider', // the services we use function config($locationProvider, $routeProvider) { $locationProvider.hashPrefix('!'); $routeProvider. // to define the application routes when('/phones', { // to map the URL /phones to template: '' }). when('/phones/:phoneId', { // mapp URL to phones + variable part named id to the URL template: '' }). otherwise('/phones'); } ]); ``` **phone-detail/phone-detail.module.js** ```javascript // new angular.module('phoneDetail', [ 'ngRoute' ]); ``` **phone-detail/phone-detail.component.js** ```javascript // new angular. module('phoneDetail'). component('phoneDetail', { template: 'TBD: Detail view for {{$ctrl.phoneId}}', controller: ['$routeParams', function PhoneDetailController($routeParams) { this.phoneId = $routeParams.phoneId; } ] }); ``` **js > app.js** ```javascript // old app.config(function ($routeProvider) { $routeProvider .when('/', { controller: 'HomeController', // to the controller HomeController templateUrl: 'views/home.html' // and the template home.html }) .when('/photos/:id', { controller: 'PhotoController', templateUrl: 'views/photo.html' }) .otherwise({ // Otherwise if a user accidentally visits a URL other than / redirectTo: '/' // we just redirect to / }); }); ``` **js > controllers > HomeController** ```javascript // old app.controller('HomeController', ['$scope', 'photos', function($scope, photos) { // use photos service photos.success(function(data) { $scope.photos = data; }); }]); ``` **js > controllers > PhotoController** ```javascript // old // $routeParams to retrieve id from the URL by using $routeParams.id // Notice injected both $routeParams and the photos service into the dependency array to make them available to use inside the controller. app.controller('PhotoController', ['$scope', 'photos', '$routeParams', function($scope, photos, $routeParams) { photos.success(function(data) { // photos service to fetch the array of photos from the server $scope.detail = data[$routeParams.id]; // $routeParams.id to access the specific photo by its index }); }]); ``` **js > services > photos** ```javascript // old // fetch the array of all photos and stores it into $scope.photos app.factory('photos', ['$http', function($http) { return $http.get('https://s3.amazonaws.com/codecademy-content/courses/ltp4/photos-api/photos.json') .success(function(data) { return data; }) .error(function(data) { return data; }); }]); ``` **views > home.html** ```html ``` **views > photo.html** ```html ``` **index.html** ```html
``` ## Filters ```javascript detail.upvotes | number // 1,266 detail.pubdate | date // Oct 18, 2014 ``` **Filter an Array** ```html Search: Search by Name:

Total number of phones: {{$ctrl.phones.length}}

``` ```html

Sort by:

```

More Points

Bootstrapping

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

platformBrowserDynamic().bootstrapModule(AppModule);

Bootstraps the app, using the root component from the specified NgModule.

NgModules

import { NgModule } from '@angular/core';

@NgModule({ declarations: ..., imports: ...,
exports: ..., providers: ..., bootstrap: ...})
class MyModule {}

Defines a module that contains components, directives, pipes, and providers.

declarations: [MyRedComponent, MyBlueComponent, MyDatePipe]

List of components, directives, and pipes that belong to this module.

imports: [BrowserModule, SomeOtherModule]

List of modules to import into this module. Everything from the imported modules is available to declarations of this module.

exports: [MyRedComponent, MyDatePipe]

List of components, directives, and pipes visible to modules that import this module.

providers: [MyService, { provide: ... }]

List of dependency injection providers visible both to the contents of this module and to importers of this module.

entryComponents: [SomeComponent, OtherComponent]

List of components not referenced in any reachable template, for example dynamically created from code.

bootstrap: [MyAppComponent]

List of components to bootstrap when this module is bootstrapped.

Template syntax
<input [value]="firstName">

Binds property value to the result of expression firstName.

<div [attr.role]="myAriaRole">

Binds attribute role to the result of expression myAriaRole.

<div [class.extra-sparkle]="isDelightful">

Binds the presence of the CSS class extra-sparkle on the element to the truthiness of the expression isDelightful.

<div [style.width.px]="mySize">

Binds style property width to the result of expression mySize in pixels. Units are optional.

<button (click)="readRainbow($event)">

Calls method readRainbow when a click event is triggered on this button element (or its children) and passes in the event object.

<div title="Hello {{ponyName}}">

Binds a property to an interpolated string, for example, "Hello Seabiscuit". Equivalent to: <div [title]="'Hello ' + ponyName">

<p>Hello {{ponyName}}</p>

Binds text content to an interpolated string, for example, "Hello Seabiscuit".

<my-cmp [(title)]="name">

Sets up two-way data binding. Equivalent to: <my-cmp [title]="name" (titleChange)="name=$event">

<video #movieplayer ...>
<button (click)="movieplayer.play()">
</video>

Creates a local variable movieplayer that provides access to the video element instance in data-binding and event-binding expressions in the current template.

<p *myUnless="myExpression">...</p>

The * symbol turns the current element into an embedded template. Equivalent to: <ng-template [myUnless]="myExpression"><p>...</p></ng-template>

<p>Card No.: {{cardNumber | myCardNumberFormatter}}</p>

Transforms the current value of expression cardNumber via the pipe called myCardNumberFormatter.

<p>Employer: {{employer?.companyName}}</p>

The safe navigation operator (?) means that the employer field is optional and if undefined, the rest of the expression should be ignored.

<svg:rect x="0" y="0" width="100" height="100"/>

An SVG snippet template needs an svg: prefix on its root element to disambiguate the SVG element from an HTML component.

<svg>
<rect x="0" y="0" width="100" height="100"/>
</svg>

An <svg> root element is detected as an SVG element automatically, without the prefix.

Built-in directives

import { CommonModule } from '@angular/common';

<section *ngIf="showSection">

Removes or recreates a portion of the DOM tree based on the showSection expression.

<li *ngFor="let item of list">

Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.

<div [ngSwitch]="conditionExpression">
<ng-template [ngSwitchCase]="case1Exp">...</ng-template>
<ng-template ngSwitchCase="case2LiteralString">...</ng-template>
<ng-template ngSwitchDefault>...</ng-template>
</div>

Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of conditionExpression.

<div [ngClass]="{'active': isActive, 'disabled': isDisabled}">

Binds the presence of CSS classes on the element to the truthiness of the associated map values. The right-hand expression should return {class-name: true/false} map.

<div [ngStyle]="{'property': 'value'}">
<div [ngStyle]="dynamicStyles()">

Allows you to assign styles to an HTML element using CSS. You can use CSS directly, as in the first example, or you can call a method from the component.

Forms

import { FormsModule } from '@angular/forms';

<input [(ngModel)]="userName">

Provides two-way data-binding, parsing, and validation for form controls.

Class decorators

import { Directive, ... } from '@angular/core';

@Component({...})
class MyComponent() {}

Declares that a class is a component and provides metadata about the component.

@Directive({...})
class MyDirective() {}

Declares that a class is a directive and provides metadata about the directive.

@Pipe({...})
class MyPipe() {}

Declares that a class is a pipe and provides metadata about the pipe.

@Injectable()
class MyService() {}

Declares that a class has dependencies that should be injected into the constructor when the dependency injector is creating an instance of this class.

Directive configuration

@Directive({ property1: value1, ... })

selector: '.cool-button:not(a)'

Specifies a CSS selector that identifies this directive within a template. Supported selectors include element, [attribute], .class, and :not().

Does not support parent-child relationship selectors.

providers: [MyService, { provide: ... }]

List of dependency injection providers for this directive and its children.

Component configuration

@Component extends @Directive, so the @Directive configuration applies to components as well

moduleId: module.id

If set, the templateUrl and styleUrl are resolved relative to the component.

viewProviders: [MyService, { provide: ... }]

List of dependency injection providers scoped to this component's view.

template: 'Hello {{name}}'
templateUrl: 'my-component.html'

Inline template or external template URL of the component's view.

styles: ['.primary {color: red}']
styleUrls: ['my-component.css']

List of inline CSS styles or external stylesheet URLs for styling the component’s view.

Class field decorators for directives and components

import { Input, ... } from '@angular/core';

@Input() myProperty;

Declares an input property that you can update via property binding (example: <my-cmp [myProperty]="someExpression">).

@Output() myEvent = new EventEmitter();

Declares an output property that fires events that you can subscribe to with an event binding (example: <my-cmp (myEvent)="doSomething()">).

@HostBinding('class.valid') isValid;

Binds a host element property (here, the CSS class valid) to a directive/component property (isValid).

@HostListener('click', ['$event']) onClick(e) {...}

Subscribes to a host element event (click) with a directive/component method (onClick), optionally passing an argument ($event).

@ContentChild(myPredicate) myChildComponent;

Binds the first result of the component content query (myPredicate) to a property (myChildComponent) of the class.

@ContentChildren(myPredicate) myChildComponents;

Binds the results of the component content query (myPredicate) to a property (myChildComponents) of the class.

@ViewChild(myPredicate) myChildComponent;

Binds the first result of the component view query (myPredicate) to a property (myChildComponent) of the class. Not available for directives.

@ViewChildren(myPredicate) myChildComponents;

Binds the results of the component view query (myPredicate) to a property (myChildComponents) of the class. Not available for directives.

Directive and component change detection and lifecycle hooks

(implemented as class methods)

constructor(myService: MyService, ...) { ... }

Called before any other lifecycle hook. Use it to inject dependencies, but avoid any serious work here.

ngOnChanges(changeRecord) { ... }

Called after every change to input properties and before processing content or child views.

ngOnInit() { ... }

Called after the constructor, initializing input properties, and the first call to ngOnChanges.

ngDoCheck() { ... }

Called every time that the input properties of a component or a directive are checked. Use it to extend change detection by performing a custom check.

ngAfterContentInit() { ... }

Called after ngOnInit when the component's or directive's content has been initialized.

ngAfterContentChecked() { ... }

Called after every check of the component's or directive's content.

ngAfterViewInit() { ... }

Called after ngAfterContentInit when the component's views and child views / the view that a directive is in has been initialized.

ngAfterViewChecked() { ... }

Called after every check of the component's views and child views / the view that a directive is in.

ngOnDestroy() { ... }

Called once, before the instance is destroyed.

Dependency injection configuration
{ provide: MyService, useClass: MyMockService }

Sets or overrides the provider for MyService to the MyMockService class.

{ provide: MyService, useFactory: myFactory }

Sets or overrides the provider for MyService to the myFactory factory function.

{ provide: MyValue, useValue: 41 }

Sets or overrides the provider for MyValue to the value 41.

Routing and navigation

import { Routes, RouterModule, ... } from '@angular/router';

const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'path/:routeParam', component: MyComponent },
{ path: 'staticPath', component: ... },
{ path: '**', component: ... },
{ path: 'oldPath', redirectTo: '/staticPath' },
{ path: ..., component: ..., data: { message: 'Custom' } }
]);

const routing = RouterModule.forRoot(routes);

Configures routes for the application. Supports static, parameterized, redirect, and wildcard routes. Also supports custom route data and resolve.


<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>

Marks the location to load the component of the active route.


<a routerLink="/path">
<a [routerLink]="[ '/path', routeParam ]">
<a [routerLink]="[ '/path', { matrixParam: 'value' } ]">
<a [routerLink]="[ '/path' ]" [queryParams]="{ page: 1 }">
<a [routerLink]="[ '/path' ]" fragment="anchor">

Creates a link to a different view based on a route instruction consisting of a route path, required and optional parameters, query parameters, and a fragment. To navigate to a root route, use the / prefix; for a child route, use the ./prefix; for a sibling or parent, use the ../ prefix.

<a [routerLink]="[ '/path' ]" routerLinkActive="active">

The provided classes are added to the element when the routerLink becomes the current active route.

class CanActivateGuard implements CanActivate {
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean { ... }
}

{ path: ..., canActivate: [CanActivateGuard] }

An interface for defining a class that the router should call first to determine if it should activate this component. Should return a boolean or an Observable/Promise that resolves to a boolean.

class CanDeactivateGuard implements CanDeactivate<T> {
canDeactivate(
component: T,
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean { ... }
}

{ path: ..., canDeactivate: [CanDeactivateGuard] }

An interface for defining a class that the router should call first to determine if it should deactivate this component after a navigation. Should return a boolean or an Observable/Promise that resolves to a boolean.

class CanActivateChildGuard implements CanActivateChild {
canActivateChild(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean { ... }
}

{ path: ..., canActivateChild: [CanActivateGuard],
children: ... }

An interface for defining a class that the router should call first to determine if it should activate the child route. Should return a boolean or an Observable/Promise that resolves to a boolean.

class ResolveGuard implements Resolve<T> {
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<any>|Promise<any>|any { ... }
}

{ path: ..., resolve: [ResolveGuard] }

An interface for defining a class that the router should call first to resolve route data before rendering the route. Should return a value or an Observable/Promise that resolves to a value.

class CanLoadGuard implements CanLoad {
canLoad(
route: Route
): Observable<boolean>|Promise<boolean>|boolean { ... }
}

{ path: ..., canLoad: [CanLoadGuard], loadChildren: ... }

An interface for defining a class that the router should call first to check if the lazy loaded module should be loaded. Should return a boolean or an Observable/Promise that resolves to a boolean.

================================================ FILE: C++/C++ Syntax.md ================================================ # C++ Syntax Cheat Sheet ## Table of Contents - [C++ Syntax Cheat Sheet](#c-syntax-cheat-sheet) - [Table of Contents](#table-of-contents) - [1.0 C++ Classes](#10-c-classes) - [1.1 Class Syntax](#11-class-syntax) - [1.1.1 Class Declaration (`.h` file)](#111-class-declaration-h-file) - [1.1.2 Class Definition (`.cpp` file)](#112-class-definition-cpp-file) - [1.1.3 Class Utilization (Another `.cpp` file)](#113-class-utilization-another-cpp-file) - [1.1.4 Getters and Setters](#114-getters-and-setters) - [1.2 Inheritance](#12-inheritance) - [1.2.1 `Rectangle` Declaration (`.h` file)](#121-rectangle-declaration-h-file) - [1.2.2 `Rectangle` Definition (`.cpp` file)](#122-rectangle-definition-cpp-file) - [1.2.3 `Rectangle` Utilization (Another `.cpp` file)](#123-rectangle-utilization-another-cpp-file) - [1.3 Polymorphism](#13-polymorphism) - [1.4 Templates](#14-templates) - [1.5 Constructor/Destructor/Copy Constructor](#15-constructordestructorcopy-constructor) - [1.5.1 Use of `explicit` in Constructors](#151-use-of-explicit-in-constructors) - [1.6 Initialization Lists](#16-initialization-lists) - [1.7 Operator Overloading](#17-operator-overloading) - [2.0 General C++ Syntax](#20-general-c-syntax) - [2.1 Namespaces](#21-namespaces) - [2.2 References/Pointers](#22-referencespointers) - [2.3 Keywords](#23-keywords) - [2.3.1 `const`](#231-const) - [2.3.2 `volatile`](#232-volatile) - [2.3.3 `inline`](#233-inline) - [2.4 Strings (find, erase, etc)](#24-strings-find-erase-etc) - [2.5 Iterators](#25-iterators) - [2.6 Exceptions](#26-exceptions) ## 1.0 C++ Classes ### 1.1 Class Syntax #### 1.1.1 Class Declaration (`.h` file) Here's a simple class representing a polygon, a shape with any number of sides. The class *declaration* typically goes in the `.h` file. The *declaration* gives the class name, any classes it may extend, declares the members and methods, and declares which members/methods are public, private, or protected. ```c++ class Polygon { // Private members and methods are only accessible via methods in the class definition // Another option is 'protected', which are members and methods only accessible in the class definition or by classes who extend this class private: int num_sides; // Number of sides std::string name // Name of the polygon // Public members and methods are accessible to anyone who creates an instance of the class public: // Constructors Polygon(const int num_sides, const std::string &name); // <--- This constructor takes the number of sides and name as arguments // Getters and Setters const int GetNumSides(void) const; void SetNumSides(const int num_sides); const std::string & GetName(void) const; void SetName(const std::string &name); }; // <--- Don't forget the semicolon! ``` #### 1.1.2 Class Definition (`.cpp` file) ```c++ #include "Polygon.h" // <--- Obtains the class declaration // Constructor // You must scope the method definitions with the class name (Polygon::) Polygon::Polygon(const int num_sides, const std::string &name) { this->num_sides = num_sides; // 'this' refers to the instance of the class. Members are accessed via pointers this->name = name; } // Get the number of sides const int Polygon::GetNumSides(void) const { return this->num_sides; } // Set the number of sides void Polygon::SetNumSides(const int num_sides) { this->num_sides = num_sides; } // Get the polygon name const std::string & Polygon::GetName(void) const { return this->name; } // Set the polygon name void Polygon::SetName(const std::string &name) { this->name = name; } ``` #### 1.1.3 Class Utilization (Another `.cpp` file) ```c++ #include #include "Polygon.h" // <--- Obtains the class declaration int main(int argc, char *argv[]) { // Create a polygon with 4 sides and the name "Rectangle" Polygon polygon = Polygon(4, "Rectangle"); // Check number of sides -- Prints "Rectangle has 4 sides" std::cout << polygon.GetName() << " has " << polygon.GetNumSides() << " sides"<< std::endl; // Change number of sides to 3 and name to "Triangle" polygon.SetNumSides(3); polygon.SetName("Triangle"); } ``` #### 1.1.4 Getters and Setters A shortcut often used for Getters/Setters is to define them in the class declaration (`.h`) file as follows: ```c++ class Car { private: int year; std::string make; public: const int GetYear(void) const { return this->year; } void SetYear(const int year) { this->year = year; } const std::string & GetMake(void) const { return this->make; } void SetMake(const std::string &make) { this->make = make; } }; ``` Another important consideration: If you have getters and setters for all of your members, you may want to reconsider the design of your class. It is more often than not that having getters and setters for every member is indicative of poor planning of the class design and interface. Getters are very common, but setters should be used more carefully. Should you have set the variable in the constructor? Is it set somewhere else in another method, perhaps even indirectly? ### 1.2 Inheritance A class can extend another class, meaning that the new class inherits all of the data from the other class, and can also override its methods, add new members, etc. Inheritance is the key feature required for polymorphism. **Example:** the class `Rectangle` can inherit the class `Polygon`. You would then say that `Rectangle` extends `Polygon`, or that class `Rectangle` is a sub-class of `Polygon`. In plain English, this means that a `Rectangle` is a more specialized version of a `Polygon`. #### 1.2.1 `Rectangle` Declaration (`.h` file) ```c++ #include "Polygon.h" // <--- You must include the declaration in order to extend the class class Rectangle: public Polygon { private: // <--- The members 'num_sides' and 'name' are already inherited from Polygon int length; int width; public: // Constructors Rectangle(const std::string &name); Rectangle(const std::string &name, const int length, const int width); // Getters and Setters <--- The methods 'GetNumSides()', 'SetNumSides()', 'GetName()' and 'SetName()' are already inherited from Polygon const int GetLength(void) const { return this->length; } void SetLength(const int) { this->length = length; } const int GetWidth(void) const { return this->width; } void SetWidth(const int) { this->width = width; } // Other Methods const int Area(void) const; }; ``` #### 1.2.2 `Rectangle` Definition (`.cpp` file) ```c++ #include "Rectangle.h" // <--- Only need to include 'Rectangle', since 'Polygon' is included in 'Rectangle.h' // This constructor calls the superclass (Polygon) constructor and sets the name and number of sides to '4', and then sets the length and width Rectangle::Rectangle(const std::string &name, const int length, const int width) : Polygon(4, name) { this->length = length; this->width = width; } // This constructor calls the superclass (Polygon) constructor, but sets the length and width to a constant value Rectangle::Rectangle(const std::string &name) : Polygon(4, name) { this->length = 1; this->width = 1; } // Compute the area of the rectangle Rectangle::Area(void) const { return this->length * this->width; } ``` #### 1.2.3 `Rectangle` Utilization (Another `.cpp` file) ```c++ #include "Rectangle.h" int main(int argc, char *argv[]) { Rectangle rectangle = Rectangle("Square", 6, 6); // Prints "Square has 4 sides, and an area of 36" std::cout << rectangle.GetName() << " has " << rectangle.GetNumSides() << " sides, and an area of " << rectangle.Area() << std::endl; } ``` ### 1.3 Polymorphism ### 1.4 Constructor/Destructor/Copy Constructor #### 1.4.1 Use of `explicit` in Constructors The keyword `explicit` should be used in single-argument constructors to avoid the following situation. Consider the class `Array`: ```c++ class Array { public: Array(int size) { this->size = size; } private: int size; }; ``` The following is now legal but ambiguous: ```c++ Array array = 12345; ``` It ends up being the equivalent of this: ```c++ Array array = Array(12345); ``` That's fine, one would suppose, but what about the following: ```c++ // Method PrintArray is defined as: Array::Print(const Array &array) array.Print(12345); ``` Uh-oh. That's now legal, compilable code, but what does it mean? It is extremely unclear to the user. To fix this, declare the single-argument `Array` constructor as `explicit`: ```c++ class Array { public: explicit Array(int size) { this->size = size; } }; ``` Now you can only use the print method as follows: ```c++ array.Print(Array(12345)); ``` ### 1.4 Initialization Lists ### 1.5 Operator Overloading [Reference](http://en.cppreference.com/w/cpp/language/operators) ### 1.6 Templates [Reference](http://en.cppreference.com/w/cpp/language/templates) ## 2.0 General C++ Syntax ### 2.1 Namespaces ### 2.2 References and Pointers ### 2.3 Keywords [Reference](http://en.cppreference.com/w/cpp/keyword) #### 2.3.1 General Keywords [`asm`](http://en.cppreference.com/w/cpp/language/asm) [`auto`](http://en.cppreference.com/w/cpp/language/auto) [`cont`](http://en.cppreference.com/w/cpp/language/cv) [`constexpr` (*since C++11*)](http://en.cppreference.com/w/cpp/language/constexpr) [`explicit`](http://en.cppreference.com/w/cpp/language/explicit) [`export` (*until C++11*)](http://en.cppreference.com/w/cpp/keyword/export) [`extern` (*language linkage*)](http://en.cppreference.com/w/cpp/language/language_linkage) [`friend`](http://en.cppreference.com/w/cpp/language/friend) [`inline`](http://en.cppreference.com/w/cpp/language/inline) [`mutable`](http://en.cppreference.com/w/cpp/language/cv) [`noexcept` (*operator*)](http://en.cppreference.com/w/cpp/language/noexcept) [`noexcept` (*function specifier*)](http://en.cppreference.com/w/cpp/language/noexcept_spec) [`nullptr`](http://en.cppreference.com/w/cpp/language/nullptr) [`override`](http://en.cppreference.com/w/cpp/language/override) [`static` (*class member specifier*)](http://en.cppreference.com/w/cpp/language/static) [`template`](http://en.cppreference.com/w/cpp/language/templates) [`this`](http://en.cppreference.com/w/cpp/language/this) [`virtual` (*function specifier*)](http://en.cppreference.com/w/cpp/language/virtual) [`virtual` (*base class specifier*)](http://en.cppreference.com/w/cpp/language/derived_class) [`volatile`](http://en.cppreference.com/w/cpp/language/cv) #### 2.3.2 Storage Class Specifiers [Reference](http://en.cppreference.com/w/cpp/language/storage_duration) * `auto` (*until C++11*) * `register` (*until C++17*) * `static` * `extern` * `thread_local` (*since C++11*) #### 2.3.3 `const` and `dynamic` Cast Conversion * [`const_cast`](http://en.cppreference.com/w/cpp/language/const_cast) * [`dynamic_cast`](http://en.cppreference.com/w/cpp/language/dynamic_cast) ### 2.4 Preprocessor Tokens * `#if`: Preprocessor version of `if(...)` * `#elif`: Preprocessor version of `else if(...)` * `#else`: Preprocessor version of `else` * `#endif`: Used to end an `#if`, `#ifdef`, or `#ifndef` * `defined()`: Returns true if the macro is defined * `#ifdef`: Same as `#if defined(...)` * `#ifndef`: Same as `#if !defined(...)` * `#define`: Defines a text macro. See [here](http://en.cppreference.com/w/cpp/preprocessor/replace) for full explanation, including macro functions and predefined macros. * `#undef`: Un-defines a text macro * `#include`: Includes a source file * `#line`: Changes the current file name and line number in the preprocessor * `#error`: Prints an error message and stops compilation * `#pragma`: Non-standard, used instead of header guards (`#ifndef HEADER_H` ...) ### 2.4 Strings (`std::string`) [Reference](http://en.cppreference.com/w/cpp/string/basic_string) ### 2.5 Iterators (`std::iterator<...>`) [Reference](http://en.cppreference.com/w/cpp/concept/Iterator) ### 2.6 Exceptions (`std::exception`) [Reference](http://en.cppreference.com/w/cpp/error/exception) ================================================ FILE: C++/Data Structures and Algorithms.md ================================================ # C++ Data Structures and Algorithms Cheat Sheet ## Table of Contents - [C++ Data Structures and Algorithms Cheat Sheet](#c-data-structures-and-algorithms-cheat-sheet) - [Table of Contents](#table-of-contents) - [1.0 Data Structures](#10-data-structures) - [1.1 Overview](#11-overview) - [1.2 Vector `std::vector`](#12-vector-stdvector) - [1.3 Deque `std::deque`](#13-deque-stddeque) - [1.4 List `std::list` and `std::forward_list`](#14-list-stdlist-and-stdforward_list) - [1.5 Map `std::map` and `std::unordered_map`](#15-map-stdmap-and-stdunordered_map) - [1.6 Set `std::set`](#16-set-stdset) - [1.7 Stack `std::stack`](#17-stack-stdstack) - [1.8 Queue `std::queue`](#18-queue-stdqueue) - [1.9 Priority Queue `std::priority_queue`](#19-priority-queue-stdpriority_queue) - [1.10 Heap `std::priority_queue`](#110-heap-stdpriority_queue) - [2.0 Trees](#20-trees) - [2.1 Binary Tree](#21-binary-tree) - [2.2 Balanced Trees](#22-balanced-trees) - [2.3 Binary Search](#23-binary-search) - [2.4 Depth-First Search](#24-depth-first-search) - [2.5 Breadth-First Search](#25-breadth-first-search) - [3.0 NP Complete Problems](#30-np-complete-problems) - [3.1 NP Complete](#31-np-complete) - [3.2 Traveling Salesman Problem](#32-traveling-salesman-problem) - [3.3 Knapsack Problem](#33-knapsack-problem) - [4.0 Algorithms](#40-algorithms) - [4.1 Insertion Sort](#41-insertion-sort) - [4.2 Selection Sort](#42-selection-sort) - [4.3 Bubble Sort](#43-bubble-sort) - [4.4 Merge Sort](#44-merge-sort) - [4.5 Quicksort](#45-quicksort) ## 1.0 Data Structures ### 1.1 Overview ![Legend](General/Legend.png) ![DataStructures](General/Data%20Structures.png "Data Structures") ![ComplexityChart](General/Complexity%20Chart.png "Complexity Chart") ![DataStructureSelection](General/Data%20Structures%20Selection.png "Data Structures Selection") ------------------------------------------------------- ### 1.2 Vector `std::vector` **Use for** * Simple storage * Adding but not deleting * Serialization * Quick lookups by index * Easy conversion to C-style arrays * Efficient traversal (contiguous CPU caching) **Do not use for** * Insertion/deletion in the middle of the list * Dynamically changing storage * Non-integer indexing **Time Complexity** | Operation | Time Complexity | |--------------|-----------------| | Insert Head | `O(n)` | | Insert Index | `O(n)` | | Insert Tail | `O(1)` | | Remove Head | `O(n)` | | Remove Index | `O(n)` | | Remove Tail | `O(1)` | | Find Index | `O(1)` | | Find Object | `O(n)` | **Example Code** ```c++ std::vector v; //--------------------------------- // General Operations //--------------------------------- // Insert head, index, tail v.insert(v.begin(), value); // head v.insert(v.begin() + index, value); // index v.push_back(value); // tail // Access head, index, tail int head = v.front(); // head int value = v.at(index); // index int tail = v.back(); // tail // Size unsigned int size = v.size(); // Iterate for(std::vector::iterator it = v.begin(); it != v.end(); it++) { std::cout << *it << std::endl; } // Remove head, index, tail v.erase(v.begin()); // head v.erase(v.begin() + index); // index v.pop_back(); // tail // Clear v.clear(); ``` ------------------------------------------------------- ### 1.3 Deque `std::deque` **Use for** * Similar purpose of `std::vector` * Basically `std::vector` with efficient `push_front` and `pop_front` **Do not use for** * C-style contiguous storage (not guaranteed) **Notes** * Pronounced 'deck' * Stands for **D**ouble **E**nded **Que**ue **Example Code** ```c++ std::deque d; //--------------------------------- // General Operations //--------------------------------- // Insert head, index, tail d.push_front(value); // head d.insert(d.begin() + index, value); // index d.push_back(value); // tail // Access head, index, tail int head = d.front(); // head int value = d.at(index); // index int tail = d.back(); // tail // Size unsigned int size = d.size(); // Iterate for(std::vector::iterator it = d.begin(); it != d.end(); it++) { std::cout << *it << std::endl; } // Remove head, index, tail d.pop_front(); // head d.erase(d.begin() + index); // index d.pop_back(); // tail // Clear d.clear(); ``` ------------------------------------------------------- ### 1.4 List `std::list` and `std::forward_list` **Use for** * Insertion into the middle/beginning of the list * Efficient sorting (pointer swap vs. copying) **Do not use for** * Direct access **Time Complexity** | Operation | Time Complexity | |--------------|-----------------| | Insert Head | `O(1)` | | Insert Index | `O(n)` | | Insert Tail | `O(1)` | | Remove Head | `O(1)` | | Remove Index | `O(n)` | | Remove Tail | `O(1)` | | Find Index | `O(n)` | | Find Object | `O(n)` | **Example Code** ```c++ std::list l; //--------------------------------- // General Operations //--------------------------------- // Insert head, index, tail l.push_front(value); // head l.insert(l.begin() + index, value); // index l.push_back(value); // tail // Access head, index, tail int head = l.front(); // head int value = std::list::iterator it = l.begin() + index; // index int tail = l.back(); // tail // Size unsigned int size = l.size(); // Iterate for(std::list::iterator it = l.begin(); it != l.end(); it++) { std::cout << *it << std::endl; } // Remove head, index, tail l.pop_front(); // head l.erase(l.begin() + index); // index l.pop_back(); // tail // Clear l.clear(); //--------------------------------- // Container-Specific Operations //--------------------------------- // Splice: Transfer elements from list to list // splice(iterator pos, list &x) // splice(iterator pos, list &x, iterator i) // splice(iterator pos, list &x, iterator first, iterator last) l.splice(l.begin() + index, list2); // Remove: Remove an element by value l.remove(value); // Unique: Remove duplicates l.unique(); // Merge: Merge two sorted lists l.merge(list2); // Sort: Sort the list l.sort(); // Reverse: Reverse the list order l.reverse(); ``` ------------------------------------------------------- ### 1.5 Map `std::map` and `std::unordered_map` **Use for** * Key-value pairs * Constant lookups by key * Searching if key/value exists * Removing duplicates * `std::map` * Ordered map * `std::unordered_map` * Hash table **Do not use for** * Sorting **Notes** * Typically ordered maps (`std::map`) are slower than unordered maps (`std::unordered_map`) * Maps are typically implemented as *binary search trees* **Time Complexity** **`std::map`** | Operation | Time Complexity | |---------------------|-----------------| | Insert | `O(log(n))` | | Access by Key | `O(log(n))` | | Remove by Key | `O(log(n))` | | Find/Remove Value | `O(log(n))` | **`std::unordered_map`** | Operation | Time Complexity | |---------------------|-----------------| | Insert | `O(1)` | | Access by Key | `O(1)` | | Remove by Key | `O(1)` | | Find/Remove Value | -- | **Example Code** ```c++ std::map m; //--------------------------------- // General Operations //--------------------------------- // Insert m.insert(std::pair("key", "value")); // Access by key std::string value = m.at("key"); // Size unsigned int size = m.size(); // Iterate for(std::map::iterator it = m.begin(); it != m.end(); it++) { std::cout << *it << std::endl; } // Remove by key m.erase("key"); // Clear m.clear(); //--------------------------------- // Container-Specific Operations //--------------------------------- // Find if an element exists by key bool exists = (m.find("key") != m.end()); // Count the number of elements with a certain key unsigned int count = m.count("key"); ``` ------------------------------------------------------- ### 1.6 Set `std::set` **Use for** * Removing duplicates * Ordered dynamic storage **Do not use for** * Simple storage * Direct access by index **Notes** * Sets are often implemented with binary search trees **Time Complexity** | Operation | Time Complexity | |--------------|-----------------| | Insert | `O(log(n))` | | Remove | `O(log(n))` | | Find | `O(log(n))` | **Example Code** ```c++ std::set s; //--------------------------------- // General Operations //--------------------------------- // Insert s.insert(20); // Size unsigned int size = s.size(); // Iterate for(std::set::iterator it = s.begin(); it != s.end(); it++) { std::cout << *it << std::endl; } // Remove s.erase(20); // Clear s.clear(); //--------------------------------- // Container-Specific Operations //--------------------------------- // Find if an element exists bool exists = (s.find(20) != s.end()); // Count the number of elements with a certain value unsigned int count = s.count(20); ``` ------------------------------------------------------- ### 1.7 Stack `std::stack` **Use for** * First-In Last-Out operations * Reversal of elements **Time Complexity** | Operation | Time Complexity | |--------------|-----------------| | Push | `O(1)` | | Pop | `O(1)` | | Top | `O(1)` | **Example Code** ```c++ std::stack s; //--------------------------------- // Container-Specific Operations //--------------------------------- // Push s.push(20); // Size unsigned int size = s.size(); // Pop s.pop(); // Top int top = s.top(); ``` ------------------------------------------------------- ### 1.8 Queue `std::queue` **Use for** * First-In First-Out operations * Ex: Simple online ordering system (first come first served) * Ex: Semaphore queue handling * Ex: CPU scheduling (FCFS) **Notes** * Often implemented as a `std::deque` **Example Code** ```c++ std::queue q; //--------------------------------- // General Operations //--------------------------------- // Insert q.push(value); // Access head, tail int head = q.front(); // head int tail = q.back(); // tail // Size unsigned int size = q.size(); // Remove q.pop(); ``` ------------------------------------------------------- ### 1.9 Priority Queue `std::priority_queue` **Use for** * First-In First-Out operations where **priority** overrides arrival time * Ex: CPU scheduling (smallest job first, system/user priority) * Ex: Medical emergencies (gunshot wound vs. broken arm) **Notes** * Often implemented as a `std::vector` **Example Code** ```c++ std::priority_queue p; //--------------------------------- // General Operations //--------------------------------- // Insert p.push(value); // Access int top = p.top(); // 'Top' element // Size unsigned int size = p.size(); // Remove p.pop(); ``` ------------------------------------------------------- ### 1.10 Heap `std::priority_queue` **Notes** * A heap is essentially an instance of a priority queue * A **min** heap is structured with the root node as the smallest and each child subsequently smaller than its parent * A **max** heap is structured with the root node as the largest and each child subsequently larger than its parent * A min heap could be used for *Smallest Job First* CPU Scheduling * A max heap could be used for *Priority* CPU Scheduling **Max Heap Example (using a binary tree)** ![MaxHeap](General/MaxHeap.png) ------------------------------------------------------- ## 2.0 Trees ### 2.1 Binary Tree * A binary tree is a tree with at most two (2) child nodes per parent * Binary trees are commonly used for implementing `O(log(n))` operations for ordered maps, sets, heaps, and binary search trees * Binary trees are **sorted** in that nodes with values greater than their parents are inserted to the **right**, while nodes with values less than their parents are inserted to the **left** **Binary Search Tree** ![BinarySearchTree](General/BinarySearchTree.png) ------------------------------------------------------- ### 2.2 Balanced Trees * Balanced trees are a special type of tree which maintains its balance to ensure `O(log(n))` operations * When trees are not balanced the benefit of `log(n)` operations is lost due to the highly vertical structure * Examples of balanced trees: * AVL Trees * Red-Black Trees ------------------------------------------------------- ### 2.3 Binary Search **Idea:** 1. If current element, return 2. If less than current element, look left 3. If more than current element, look right 4. Repeat **Data Structures:** * Tree * Sorted array **Space:** * `O(1)` **Best Case:** * `O(1)` **Worst Case:** * `O(log n)` **Average:** * `O(log n)` **Visualization:** ![BinarySearch](Searching/Animations/Binary%20Search.gif "Binary Search") ------------------------------------------------------- ### 2.4 Depth-First Search **Idea:** 1. Start at root node 2. Recursively search all adjacent nodes and mark them as searched 3. Repeat **Data Structures:** * Tree * Graph **Space:** * `O(V)`, `V = number of verticies` **Performance:** * `O(E)`, `E = number of edges` **Visualization:** ![DepthFirstSearch](Searching/Animations/Depth-First%20Search.gif "Depth-First Search") ------------------------------------------------------- ### 2.5 Breadth-First Search **Idea:** 1. Start at root node 2. Search neighboring nodes first before moving on to next level **Data Structures:** * Tree * Graph **Space:** * `O(V)`, `V = number of verticies` **Performance:** * `O(E)`, `E = number of edges` **Visualization:** ![DepthFirstSearch](Searching/Animations/Breadth-First%20Search.gif "Breadth-First Search") ------------------------------------------------------- ## 3.0 NP Complete Problems ### 3.1 NP Complete * **NP Complete** means that a problem is unable to be solved in **polynomial time** * NP Complete problems can be *verified* in polynomial time, but not *solved* ------------------------------------------------------- ### 3.2 Traveling Salesman Problem ------------------------------------------------------- ### 3.3 Knapsack Problem ------------------------------------------------------- ## 4.0 Algorithms ### 4.1 Insertion Sort #### Idea 1. Iterate over all elements 2. For each element: * Check if element is larger than largest value in sorted array 3. If larger: Move on 4. If smaller: Move item to correct position in sorted array #### Details * **Data structure:** Array * **Space:** `O(1)` * **Best Case:** Already sorted, `O(n)` * **Worst Case:** Reverse sorted, `O(n^2)` * **Average:** `O(n^2)` #### Advantages * Easy to code * Intuitive * Better than selection sort and bubble sort for small data sets * Can sort in-place #### Disadvantages * Very inefficient for large datasets #### Visualization ![InsertionSort](Sorting/Animations/Insertion%20Sort.gif "Insertion Sort") ------------------------------------------------------- ### 4.2 Selection Sort #### Idea 1. Iterate over all elements 2. For each element: * If smallest element of unsorted sublist, swap with left-most unsorted element #### Details * **Data structure:** Array * **Space:** `O(1)` * **Best Case:** Already sorted, `O(n^2)` * **Worst Case:** Reverse sorted, `O(n^2)` * **Average:** `O(n^2)` #### Advantages * Simple * Can sort in-place * Low memory usage for small datasets #### Disadvantages * Very inefficient for large datasets #### Visualization ![SelectionSort](Sorting/Animations/Selection%20Sort.gif "Selection Sort") ![SelectionSort](Sorting/Animations/Selection%20Sort%202.gif "Selection Sort 2") ------------------------------------------------------- ### 4.3 Bubble Sort #### Idea 1. Iterate over all elements 2. For each element: * Swap with next element if out of order 3. Repeat until no swaps needed #### Details * **Data structure:** Array * **Space:** `O(1)` * **Best Case:** Already sorted `O(n)` * **Worst Case:** Reverse sorted, `O(n^2)` * **Average:** `O(n^2)` #### Advantages * Easy to detect if list is sorted #### Disadvantages * Very inefficient for large datasets * Much worse than even insertion sort #### Visualization ![BubbleSort](Sorting/Animations/Bubble%20Sort.gif "Bubble Sort") ------------------------------------------------------- ### 4.4 Merge Sort #### Idea 1. Divide list into smallest unit (1 element) 2. Compare each element with the adjacent list 3. Merge the two adjacent lists 4. Repeat #### Details * **Data structure:** Array * **Space:** `O(n) auxiliary` * **Best Case:** `O(nlog(n))` * **Worst Case:** Reverse sorted, `O(nlog(n))` * **Average:** `O(nlog(n))` #### Advantages * High efficiency on large datasets * Nearly always O(nlog(n)) * Can be parallelized * Better space complexity than standard Quicksort #### Disadvantages * Still requires O(n) extra space * Slightly worse than Quicksort in some instances #### Visualization ![MergeSort](Sorting/Animations/Merge%20Sort.gif "Merge Sort") ![MergeSort](Sorting/Animations/Merge%20Sort%202.gif "Merge Sort 2") ------------------------------------------------------- ### 4.5 Quicksort #### Idea 1. Choose a **pivot** from the array 2. Partition: Reorder the array so that all elements with values *less* than the pivot come before the pivot, and all values *greater* than the pivot come after 3. Recursively apply the above steps to the sub-arrays #### Details * **Data structure:** Array * **Space:** `O(n)` * **Best Case:** `O(nlog(n))` * **Worst Case:** All elements equal, `O(n^2)` * **Average:** `O(nlog(n))` #### Advantages * Can be modified to use O(log(n)) space * Very quick and efficient with large datasets * Can be parallelized * Divide and conquer algorithm #### Disadvantages * Not stable (could swap equal elements) * Worst case is worse than Merge Sort #### Optimizations * Choice of pivot: * Choose median of the first, middle, and last elements as pivot * Counters worst-case complexity for already-sorted and reverse-sorted #### Visualization ![QuickSort](Sorting/Animations/Quicksort.gif) ================================================ FILE: C++/README.md ================================================ # C++ and Data Structures & Algorithms Cheat Sheet These are two cheat sheets I put together describing both basic [C++ syntax](C++%20Syntax.md) and many common [data structures and algorithms](Data%20Structures%20and%20Algorithms.md) in C++ for my past interviews at Google, NASA, etc. Hopefully you find them useful, and please open an issue or submit a PR if you find incorrect or missing information! ================================================ FILE: Command Line/README.md ================================================ [back to overwiev](/../..) # Command Line Cheatsheet ##### Table of Contents [Basics](#basics) [Showing & Navigating](#showing--navigating) [Copying/Moving/Removing](#copyingmovingremoving) [Input & Output Redirects](#input--output-redirects) [Sorting & Filtering](#sorting--filtering) [Environment](#environmen) ## Basics **clear** –– clears the terminal **nano** filename –– opens the nano text editor for specific file (optional) ^ –– in nano stands for ctrl ~ –– usually represents the users home directory ## Showing & Navigating **ls** –– lists all files (folders are called directories. files and directories are structured in a file system) **ls -a** –– lists all files + hidden files (-a is called an option) ls -t –– orders by time last added ls -l –– with long description (access-rights, n# of hard links, owner, group-name, size in bytes, date-last-modified, name) ls -alt –– -a, -t & -l together **pwd** –– print working directory path (the directory you’re currently in) **cd directory-name** –– change directory cd folder/childfolder –– two down cd .. –– one up – cd folder/folder –– two down **mkdir name** –– make directory **touch name** –– creates a new file inside the working directory **cat** filename –– outputs the content of a file to the console **wc** filename –– outputs the number of lines, words, and characters in file ## Copying/Moving/Removing **cp** file-to-copy place-to-paste –– copies files and paste them somewhere else cp file1 file2 file3 place-to-paste –– you can copy multiple files at once cp * place-to-paste –– copy all files from working directory (special characters like * are called wildcard, when you combine it with .txt for example would mean any file that ends with .txt) **mv** file-to-move-1 place-to-move –– moves a file mv file-to-rename new-filename –– renames a file **rm** file-to-remove –– removes a file or directory !permanently! rm -r dir-to-remove –– removes a dir and all its children !permanently! ##Input & Output Redirects echo "Hello" > world.txt –– **>** redirects the standard output (Hello) into something else (world.txt) cat file1.txt > file2.txt –– content of file1 is redirected into file2 which overrides the content of file2 by the content of file1 cat file1.txt >> file2.txt –– **>>** appends the output of file1 to file2 cat < file.txt –– takes the output from the right and inputs it into the left cat file.txt | wc –– **|** is a "pipe". The | takes the standard output of the command on the left, and pipes it as standard input to the command on the right. You can think of this as "command to command" redirection. cat text1.txt | wc | cat > text2.txt –– multiple pipes can be combined here the output of text1.txt is given to wc whose output is given to cat which places it into text.txt ## Sorting & Filtering **sort** filename –– outputs the sortet content of the file cat filename | sort > nameofsortedfile –– outputs the content of filename binds it to the sort function that then redirect that sorted output into a file **uniq** filename –– filters out adjacent, duplicate lines in a file sort file | uniq > anotherfile –– sorts a file "pipes" (|) the sorted content to uniq which filters out all adjacent duplicates and gives the result back to another file sort file | uniq -c > anotherfile -– counting the duplicated lines in file sort file | uniq -c | sort -nr > anotherfile -– counting the duplicated lines in file and sort it (by frequency) **grep** keyword filename –– searches a file for lines that have the keyword and output the result (it is case sensitive) grep -i keyword filename –– here grep is case insensitive grep -R keyword folder –– searches all files in a directory and outputs filenames and lines containing matched results grep -Rl keyword folder –– searches all files in a directory and outputs only filenames with matched results **sed** 's/keyword/replacement' filename –– find in file and replace s = substitution. So sed 's/find/replace' in_this_file (only replace the first finding) sed 's/keyword/replacement/**g**' filename –– same as above but replaces all instances not only the first finding ## Environment **nano** ~/.bash_profile –– creates a file to store environment settings. Whenever a session starts it will load it's content. (within bash_profile) **alias** pd="pwd" –– create keyboard shortcuts, for commonly used commands. (within bash_profile) **export** USER="username" –– create a variable that can be accessed by $USER (within bash_profile) export PS1=">> " –– to change the command prompt from $ to >> **source** ~/.bash_profile –– makes changes available without the fuzz to open a new console. **env** –– return a list of environment variables ================================================ FILE: Django/README.md ================================================ # Cheatsheet for Django QuerySets Current Django Version: [2.0](https://docs.djangoproject.com/en/2.0/ref/models/querysets/) ## Methods that return new [QuerySets](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#methods-that-return-new-querysets) **Can be chained:** ```python Entry.objects.filter(**kwargs).exclude(**kwargs).order_by(**kwargs) ``` * [filter](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#filter) * [exclude](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#exclude) * [annotate](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#annotate) * [order_by](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#order-by) * [reverse](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#reverse) * [distinct](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#distinct) * [values](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#values) * [values_list](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#values-list) * [dates](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#dates) * [datetimes](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#datetimes) * [none](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#none) * [all](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#all) * [union](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#union) * [intersection](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#intersection) * [difference](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#difference) * [select_related](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#select-related) * [prefetch_related](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#prefetch-related) * [extra](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#extra) * [defer](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#defer) * [only](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#only) * [using](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#using) * [select_for_update](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#select-for-update) * [raw](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#raw) ## Methods that do not return QuerySets * [get](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#get) * [create](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#create) * [get_or_create](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#get-or-create) * [update_or_create](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#update-or-create) * [bulk_create](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#bulk-create) * [count](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#count) * [in_bulk](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#in-bulk) * [iterator](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#iterator) * [latest](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#latest) * [earliest](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#earliest) * [first](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#first) * [last](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#last) * [aggregate](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#aggregate) * [exists](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#exists) * [update](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#update) * [delete](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#delete) * [as_manager](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#as-manager) ## Field lookups **Field lookups are how you specify the meat of an SQL WHERE clause. They’re specified as keyword arguments to the QuerySet methods *filter()*, *exclude()* and *get()*.** ```python Example: Entry.objects.get(id__exact=14) # note double underscore. ``` * [exact](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#exact) * [iexact](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#iexact) * [contains](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#contains) * [icontains](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#icontains) * [in](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#in) * [gt](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#gt) * [gte](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#gte) * [lt](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#lt) * [lte](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#lte) * [startswith](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#startswith) * [istartswith](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#istartswith) * [endswith](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#endswith) * [iendswith](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#iendswith) * [range](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#range) * [date](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#date) * [year](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#year) * [month](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#month) * [day](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#day) * [week](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#week) * [week_day](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#week-day) * [quarter (new in 2.0)](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#quarter) * [time](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#time) * [hour](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#hour) * [minute](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#minute) * [second](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#second) * [isnull](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#isnull) * [regex](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#regex) * [iregex](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#iregex) **Protip: Use [in](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#in) to avoid chaining [filter()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#filter) and [exclude()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#exclude)** ```python Entry.objects.filter(status__in=['Hung over', 'Sober', 'Drunk']) ``` ## Aggregation functions * [expression](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#expression) * [output_field](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#output-field) * [filter (new in 2.0)](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#id6) * [Avg](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#avg) * [Count](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#id8) * [Max](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#max) * [Min](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#min) * [StdDev](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#stddev) * [Sum](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#sum) * [Variance](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#variance) ## Query-related classes * [Q() objects](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#q-objects) * [Prefetch() objects](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#prefetch-objects) * [prefetch_related_objects()](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#prefetch-related-objects) * [FilteredRelation() objects (new in 2.0)](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#filteredrelation-objects) - - - Creative Commons License
Django-QuerySet-Cheatsheet by @chrisdl and @briandant is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
The [contributors](https://github.com/chrisdl/Django-QuerySet-Cheatsheet/graphs/contributors) are as gods among ants and shall forever be remembered as such. The Django web framework referenced in the Django-QuerySet-Cheatsheet is ​© 2005-2018 Django Software Foundation. Django is a registered trademark of the Django Software Foundation. ================================================ FILE: Elixir/README.md ================================================ # Elixir Cheat Sheet ```elixir elixir -v 1.3.1 ``` Elixir is a dynamic functional compiled language that runs over an Erlang Virtual Machine called BEAM. Erlang and its BEAM is well known for running low-lattency, distributed and fault-tolerant applications. Elixir was designed to take all that advantages in a modern coding language. Elixir data types are immutable. In Elixir a function is usually described with its arity (number of arguments), such as: `is_boolean/1`. ## File Types - `.exs` => Elixir script file - `.ex` => Elixir regular file - `.beam` => Compiled Elixir file ## Compile and Run Elixir code - `elixir .exs` => run a script file - `elixirc .ex` => compile a file to `Elixir..beam` ## Elixir Conventions - `foo function return tuple` => the result of a `foo` function is usually `{:ok, result}` or `{:error, reason}` - `foo! function may raise an error` => the result of a `foo!` is not wrapped in a tuple and it may raises an exception - Exceptions/Errors are **not used** for controlling flow - Elixir uses **fail fast** idea and the supervision trees to control process health and possible restart processes. ## Comments - `#` => single line comment There are no multi-line comment ## Code Documentation - `@moduledoc` => module documentation - `@doc` => function documentation - `@spec` => function arguments/return specification - `@typedoc` => type documentation - `@type` => type definition - `@typep` => private type definition ```elixir defmodule Math do @moduledoc """ Provides math-related functions. ## Examples iex> Math.sum(1, 2) 3 """ @spec sum(number, number) :: number @doc """ Calculates the sum of two numbers. """ def sum(a, b), do: a + b end h Math h Math.sum ``` ## Elixir Special Unbound Variable - `_` => unbound variable ## Elixir/Erlang Virtual Machine inspection - `:observer.start` => start a gui tool for inspection - `:erlang.memory` => inspect memory - `:c.memory` => inspect memory ```elixir :c.memory # [ # total: 19262624, # processes: 4932168, # processes_used: 4931184, # system: 14330456, # atom: 256337, # atom_used: 235038, # binary: 43592, # code: 5691514, # ets: 358016 # ] ``` ## Interactive Elixir - `iex` => open Interactive Elixir - `iex ` => open Interactive Elixir loading a file - `c + a` => close iex - `i ` => information about an object - `h ` => help for a function - `h ` => help for a operator - `s ` => specification for a function - `s ` => specification for a operator - `t ` => type for a function - `c ` => load and compile a `.ex` file ## Basic Types ### Integer - `1` => integer - `1_000` => integers can use `_` to make it easy to read - `0x1F` => integer - `0b1010` => binary integer notation 10 - `0o777` => octadecimal integer notation 511 - `0x1F` => hexadecimal integer notation 31 ### Float - `-1.0` => float - `5.7e-2` => float exponent notation 0.057 ### Atom - `:atom` => atom / symbol - `true` => boolean (atom) ### BitString - `<<97::size(2)>>` => bit string - `<<97,98>>` => binary - `"elixir"` => string ### Tuple - `{1, 2, 3}` => tuple ### List - `[1, 2, 3]` => list - `'elixir'` => char list - `[a: 5, b: 3]` => keyword list short notation - `[{:a, 5}, {:b, 3}]` => keyword list long notation ### Map - `%{name: "Mary", age: 29}` => map short notation (keys must be atoms) - `%{:name => "Mary", :age => 29}` => map long notation ### PID - `self() #=> #PID<0.80.0>` => current Process id ### Function - `fn -> :hello end` => anonymous function ### Reference - `make_ref() #=> #Reference<0.0.8.133>` => create a new reference ### Port - `hd Port.list() #=> #Port<0.0>` => get first port ## Type Testing - `is_nil/1` - `is_integer 1` - `is_float 4.6` - `is_number 7.8` - `is_atom :foo` - `is_boolean false` - `is_bitstring <<97:2>>` - `is_binary <<97, 98>>` - `is_list/1` - `is_tuple/1` - `is_map/1` - `is_pid self()` - `is_function(fn a, b -> a + b end)` => function - `is_function(fn a, b -> a + b end, 2)` => function with arity - `is_port hd Port.list()` - `is_reference make_ref()` - `Range.range?(1..3)` ## Converting Types - `to_char_list("hełło")` => convert a string to char list - `to_string('hełło')` => convert a char list to string - `Map.to_list(%{:a => 1, 2 => :b})` => convert a map to list of tuples or keyword list ## Number Operators - `10 / 2 => 5.0` => division always return a float - `div(10, 2) => 5` => integer division - `rem 10, 3 => 1` => integer remain of a division - `round(3.58) => 4` => float round - `trunc(3.58) => 3` => float trunc ## Boolean Operators Falsy in Elixir is `false` and `nil`, otherwise will be truthy. - `==` => equals - `!=` => different - `===` => strict equal (integer with float) - `!==` => strict different (integer with float) - `<` => less - `<=` => less or equal - `>` => greater - `>=` => greater or equal - `&&` => truthy and - `||` => truthy or - `!` => truthy not - `and` => boolean and - `or` => boolean or - `not` => boolean not It's possible to compare different data types and that's the sorting order: `number < atom < reference < functions < port < pid < tuple < list < bit string`. ## Pipe Operator - `|>` => pipe operator The return of a function will be passed as the first argument to the following. ```elixir 1..100 |> Stream.map(&(&1 * 3)) |> Stream.filter(&(rem(&1, 2) != 0)) |> Enum.sum #=> 7500 ``` ## Pattern Matching In Elixir `=` sign is not just an assign operator, but a **Match Operator**. This means that you assign variables from right side to the left based on patterns defined by the left one. If a pattern does not match a `MatchError` is raised. This powerful tool is also used to decompose complex objects like tuples, lists, etc into smaller ones: ```elixir x = 1 #=> assign 1 to x 2 = x #=> ** (MatchError) 1 = x #=> match and does not assign anything <<0, 1, x>> = <<0, 1, 2, 3>> #=> ** (MatchError) <<0, 1, x::binary>> = <<0, 1, 2, 3>> <<0, 1>> <> <> = <<0, 1, 2, 3>> <<0, 1>> <> <> = <<0, 1, 2, 3>> <<0, 1>> <> <> <> <> = <<0, 1, 2, 3>> "world" <> x = "hello" #=> ** (MatchError) "he" <> x = "hello" {x, y, z} = {1, 2} #=> ** (MatchError) {} = {1, 2} #=> ** (MatchError) {:a, :b} = {:b, :a} #=> ** (MatchError) {x, y} = {1, 2} first..last = 1..5 [x, 4] = [:a, 5] #=> ** (MatchError) [] = [:a, 5] #=> ** (MatchError) [:a, :b] = [:b, :a] #=> ** (MatchError) [x, 4] = [:a, 4] [x | y] = [] #=> ** (MatchError) [x | y] = [1] [x | y] = [1, 2, 3] [a: x] = [b: 9] #=> ** (MatchError) [a: x] = [a: 5] [{:a, x}] = [a: 5] %{a: x} = %{b: 5} #=> ** (MatchError) %{} = %{a: 5} # empty map matches any map %{a: x, b: 5} = %{b: 5, a: 7, c: 9} defmodule User do defstruct name: "John", age: 27 end john = %User{age: 29} %User{name: name} = john name #=> "John" ``` So in other words: - non variables on the left side will be used to **restrict a pattern to match** - variables using the pin operator on the left side will have its value to be used to **restrict a pattern to match** - variables on the left side will be **assigned** with right side values So **variables** and **non variables** behave differently with the match operator. In order to assert an **empty map** you have to use a guard instead of pattern match, just like: ```elixir ( fn m when map_size(m) == 0 -> "empty map" end ).(%{}) #=> "empty map" ``` ### Pin Operator The Pin Operator `^` is used to treat variables the same way non variables with the match operator. In other words, the Pin Operator will evaluate the variable and use its value to **restrict a pattern**, preserving its original value. ```elixir x = 1 #=> assign 1 to x ^x = 1 #=> match x value with right side 1 ^x = 2 #=> ** (MatchError) ``` ### Match Operator Limitation You cannot make function calls on the left side of a match. - `length([1, [2], 3]) = 3 #=> ** (CompileError) illegal pattern` ## Custom Operators You can customize an Elixir Operator like the following example: ```elixir 1 + 2 #=> 3 defmodule WrongMath do def a + b do {a, b} end end import WrongMath import Kernel, except: [+: 2] 1 + 2 #=> {1, 2} ``` ## Sigils Available delimiters for `Sigil`: `/`, `|`, `"`, `'`, `(`, `[`, `{`, `<`. - `~r` => regular expression (modifiers: `i`) - `~r/hello/i` => `i` modifies to case insensitive - `~w` => list of string words (modifiers: ) - `~w[foo bar]c` => `c` modifies to list of char lists - `~w[foo bar]a` => `c` modifies to list of atoms ```elixir ~w(one two three) #=> ["one", "two", "three"] ~w(one two three)c #=> ['one', 'two', 'three'] ~w(one two three)a #=> [:one, :two, :three] ``` ## Bit Strings - `<<97::4>>` => short notation with 4 bits - `<<97::size(4)>>` => long notation with 4 bits - `byte_size(<<5::4>>)` => bit string byte size ### Performance for Bit Strings: #### cheap functions: - `byte_size(<<97::4>>)` #### expensive functions: ## Binaries Binaries are 8 bits multiple Bit Strings. Binaries are 8 bits by default. - `<<97>>` => short notation with 8 bits - `<<97::size(8)>>` => long notation with 8 bits - `<>` => concatenate binaries/strings ### Performance for Binaries: #### cheap functions: - `byte_size(<<97>>)` #### expensive functions: ## Strings String is a Binary of code points where all elements are valid characters. Strings are surrounded by double-quotes and are encoded in `UTF-8` by default. - `"hello"` => string - `<<97, 98>>` => string "ab" - `<>` => string "ab" `?x` => code points (ASCII code) for letter `x` - `"hello #{:world}"` => string interpolation - `"\n"` => new line - `String.length("hello") #=> 5` => get the length of a string - `String.upcase("hello") #=> "HELLO"` => upcase a string - `"""` => multi-line string begin/end ### Performance for Strings: #### cheap functions: - `byte_size("hello")` #### expensive functions: - `String.length("Hello")` ## Tuples Tuple is a list that is stored contiguously in memory. - `{:ok, "hello"}` - `tuple_size({:ok, "hello"})` => tuple size - `elem({:ok, "hello"}, 0)` => get tuple element by index - `put_elem({:ok, "hello"}, 1, "world")` ### Performance for Tuples: #### cheap functions: - `tuple_size({:ok, "hello"})` - `elem({:ok, "hello"}, 1)` #### expensive functions: - `put_elem({:ok, "hello"}, 1, "world")` ## Lists **Lists** implements Enumerables protocol. List is a linked list structure where each element points to the next one in memory. When subtraction just the first ocurrence will be removed. - `[:ok, "hello"]` - `[97 | [1, 6, 9]]` => prepend - `[1, 5] ++ [3, 9] # [1, 5, 3, 9]` => concatenation - `[1, 5] -- [9, 5] # [1]` => subtraction first occurrences - `hd([1, 5, 7])` => head - `tl([1, 5, 7])` => tail - `:foo in [:foo, :bar] #=> true` => in operator ### Performance for Lists: #### cheap functions: - `[97 | [1, 6, 9]]` => prepend - `hd([1, 5, 7])` => head - `tl([1, 5, 7])` => tail #### expensive functions: - `[1, 5] ++ [3, 9] # [1, 5, 3, 9]` => concatenation - `[1, 5] -- [9, 5] # [1]` => subtraction first occurrences - `length([1, 4])` - `:foo in [:foo, :bar] #=> true` => in operator ## Char List A Char List is a List of code points where all elements are valid characters. Char Lists are surrounded by single-quote and are usually used as arguments to some old Erlang code. - `'ab'` => char list - `[97, 98]` => `'ab'` - `[?a, ?b]` => `'ab'` - `?x` => code points (ASCII code) for letter `x` - `'hello' ++ 'world' # 'helloworld'` => concatenation - `'hello' -- 'world' # 'hel'` => subtraction first occurrences - `?l in 'hello' #=> true` => in operator ### Performance for Char Lists: #### cheap functions: - `[?H | 'ello']` => prepend #### expensive functions: - `'hello' ++ 'world' # 'helloworld'` => concatenation - `'hello' -- 'world' # 'hel'` => subtraction first occurrences - `length('Hello')` - `?l in 'hello' #=> true` => in operator ## Keyword Lists Keyword list is a list of tuples where first elements are atoms. When fetching by key the first match will return. If a keyword list is the last argument of a function the square brackets `[` are optional. - `[a: 5, b: 3]` => keyword list short notation - `[{:a, 5}, {:b, 3}]` => keyword list long notation - `[{:a, 6} | [b: 7]] # [a: 6, b: 7]` => prepend - `[a: 5] ++ [a: 7] # [a: 5, a: 7]` => concatenation - `[a: 5, b: 7] -- [a: 5] # [b: 7]` => subtraction first ocurrences - `([a: 5, a: 7])[:a] # 5` => fetch by key - `length(a: 5, b: 7)` => optional squared brackets `[` ### Performance for Keyword Lists: #### cheap functions: - `[{:a, 6} | [b: 7]] # [a: 6, b: 7]` => prepend #### expensive functions: - `[a: 5] ++ [a: 7] # [a: 5, a: 7]` => concatenation - `[a: 5, b: 7] -- [a: 5] # [b: 7]` => subtraction first ocurrences - `([a: 5, a: 7])[:a] # 5` => fetch by key - `length(a: 5, b: 7)` => optional squared brackets `[` ## Maps **Maps** implements Enumerables protocol. Map holds a key value structure. - `%{name: "Mary", age: 29}` => map short notation (keys must be atoms) - `%{:name => "Mary", :age => 29}` => map long notation - `%{name: "Mary", age: 29}[:name]` => fetch `:name` hash notation - `%{name: "Mary", age: 29}[:born]` => returns nil when do not find in the hash notation - `%{name: "Mary", age: 29}.name` => fetch `:name` short notation - `%{name: "Mary", age: 29}.born # ** (KeyError)` => blows an error when key does not exists - `%{%{name: "Mary", age: 29} | age: 31}` => update value for existing key - `%{%{name: "Mary", age: 29} | born: 1990} # ** (KeyError)` => blows an error when updating non existing key - `map_size(%{name: "Mary"}) #=> 1` => map size ### Performance for Maps: #### cheap functions: - `%{name: "Mary", age: 29}[:name]` => fetch `:name` - `%{name: "Mary", age: 29}.name` => fetch `:name` short notation - `%{%{name: "Mary", age: 29} | age: 31}` => update value for existing key - `map_size(%{name: "Mary"}) #=> 1` => map size #### expensive functions: ## Structs Structs are built in top of Map. - `defstruct` => define a struct ```elixir defmodule User do defstruct name: "John", age: 27 end john = %User{} #=> %User{age: 27, name: "John"} mary = %User{name: "Mary", age: 25} #=> %User{age: 25, name: "Mary"} meg = %{john | name: "Meg"} #=> %User{age: 27, name: "Meg"} bill = Map.merge(john, %User{name: "Bill", age: 23}) john.name #=> John john[:name] #=> ** (UndefinedFunctionError) undefined function: User.fetch/2 is_map john #=> true john.__struct__ #=> User Map.keys(john) #=> [:__struct__, :age, :name] ``` ## Ranges Ranges are `Struct`. - `range = 1..10` => range definition - `Enum.reduce(1..3, 0, fn i, acc -> i + acc end) #=> 6` => range used in a reduce function to sum them up - `Enum.count(range) #=> 10` - `Enum.member?(range, 11) #=> false` ## Protocols - `defprotocol Foo` => define protocol `Foo` - `defimpl Foo, for Integer` => implement that protocol for `Integer` Here are all native data types that you can use: `Atom`, `BitString`, `Float`, `Function`, `Integer`, `List`, `Map`, `PID`, `Port`, `Reference`, `Tuple`. ```elixir defprotocol Blank do @doc "Returns true if data is considered blank/empty" def blank?(data) end defimpl Blank, for: Integer do def blank?(_), do: false end defimpl Blank, for: List do def blank?([]), do: true def blank?(_), do: false end defimpl Blank, for: Map do def blank?(map), do: map_size(map) == 0 end defimpl Blank, for: Atom do def blank?(false), do: true def blank?(nil), do: true def blank?(_), do: false end Blank.blank?(0) #=> false Blank.blank?([]) #=> true Blank.blank?([1, 2, 3]) #=> false Blank.blank?("hello") #=> ** (Protocol.UndefinedError) ``` `Structs` do not share `Protocol` implementations with `Map`. ```elixir defimpl Blank, for: User do def blank?(_), do: false end ``` You can also implement a `Protocol` for `Any`. And in this case you can derive any `Struct`. ```elixir defimpl Blank, for: Any do def blank?(_), do: false end defmodule DeriveUser do @derive Blank defstruct name: "john", age: 27 end ``` Elixir built-in most common used protocols: `Enumerable`, `String.Chars`, `Inspect`. ## Nested data Structures - `put_in/2` - `update_in/2` - `get_and_update_in/2` ```elixir users = [ john: %{name: "John", age: 27, languages: ["Erlang", "Ruby", "Elixir"]}, mary: %{name: "Mary", age: 29, languages: ["Elixir", "F#", "Clojure"]} ] users[:john].age #=> 27 users = put_in users[:john].age, 31 users = update_in users[:mary].languages, &List.delete(&1, "Clojure") ``` ## Enums and Streams **Lists** and **Maps** are Enumerables. `Enum` module perform **eager** operations, meanwhile `Stream` module perform **lazy** operations. ```elixir # eager Enum 1..100 |> Enum.map(&(&1 * 3)) |> Enum.sum #=> 15150 # lazy Stream 1..100 |> Stream.map(&(&1 * 3)) |> Enum.sum #=> 15150 ``` ## do/end Keyword List and Block Syntax In Elixir you can use either **Keyword List** syntax or **do/end Block** syntax: ```elixir sky = :gray if sky == :blue do :sunny else :cloudy end if sky == :blue, do: :sunny, else: :cloudy if sky == :blue, do: ( :sunny ), else: ( :cloudy ) ``` ## Conditional Flows (if/else/case/cond) ### if / else ```elixir sky = :gray if sky == :blue, do: :sunny, else: :cloudy ``` ### unless / else ```elixir sky = :gray unless sky != :blue, do: :sunny, else: :cloudy ``` ### case / when ```elixir sky = {:gray, 75} case sky, do: ( {:blue, _} -> :sunny {_, t} when t > 80 -> :hot _ -> :check_wheather_channel ) ``` On **when guards** short-circuiting operators `&&`, `||` and `!` are **not** allowed. ### cond `cond` is equivalent as `if/else-if/else` statements. ```elixir sky = :gray cond do: ( sky == :blue -> :sunny true -> :cloudy ) ``` ## The `with` macro - `with` => macro to combine multiple match clauses - `<-` => a matching clause, on the left - `=` => bare expression is allowed - `else` => if some matching clause fails ```elixir opts = %{width: 10, height: 20} with {:ok, width} <- Map.fetch(opts, :width), {:ok, height} <- Map.fetch(opts, :height) do {:ok, width * height} else :error -> {:error, :wrong_data} end #=> {:ok, 200} ``` ## Recursion There is traditional **no for loop** in Elixir, due to Elixir immutability There is a macro `for` that it's also called as `Comprehension` but it works differently from a traditional for loop. If you want a simple loop iteration you'll need to use **recursion**: ```elixir defmodule Logger do def log(msg, n) when n <= 0, do: () def log(msg, n) do IO.puts msg log(msg, n - 1) end end Logger.log("Hello World!", 3) # Hello World! # Hello World! # Hello World! ``` In functional programming languages **map** and **reduce** are two major algorithm concepts. They can be implemented with **recursion** or using the `Enum` module. **reduce** will reduces the array into a single element: ```elixir defmodule Math do def sum_list(list, sum \\ 0) def sum_list([], sum), do: sum def sum_list([head | tail], sum) do sum_list(tail, head + sum) end end Math.sum_list([1, 2, 3]) #=> 6 Enum.reduce([1, 2, 3], 0, &+/2) #=> 6 ``` **map** modifies an existing array (new array with new modified values): ```elixir defmodule Math do def double([]), do: [] def double([head | tail]) do [head * 2 | double(tail)] end end Math.double([1, 2, 3]) #=> [2, 4, 6] Enum.map([1, 2, 3], &(&1 * 2)) #=> [2, 4, 6] ``` ## Comprehension -> the for loop `Comprehension` is a syntax sugar for the very powerful `for special form`. You can have **generators** and **filters** in that. - `for` => `Comprehension` - `->` => **generators** - `:into` => change return to another `Collectable` type You can iterate over `Enumerable` what makes so close to a regular `for` loop on other languages: ```elixir for n <- [1, 2, 3, 4], do: n * n #=> [1, 4, 9, 16] ``` You can also iterate over multiple `Enumerable` and then create a combination between them: ```elixir for i <- [:a, :b, :c], j <- [1, 2], do: {i, j} #=> [a: 1, a: 2, b: 1, b: 2, c: 1, c: 2] ``` You can pattern match each element: ```elixir values = [good: 1, good: 2, bad: 3, good: 4] for {:good, n} <- values, do: n * n #=> [1, 4, 16] ``` Generators use `->` and they have on the right an `Enumerable` and on the left a **pattern matchable** element variable. You can have **filters** to filter **truthy** elements: ```elixir for dir <- [".", "/"], file <- File.ls!(dir), path = Path.join(dir, file), File.regular?(path) do "dir=#{dir}, file=#{file}, path=#{path}" end #=> ["dir=., file=README.md, path=./README.md", "dir=/, file=.DS_Store, path=/.DS_Store"] ``` You can use `:into` to change the return type: ```elixir for k <- [:foo, :bar], v <- 1..5, into: %{}, do: {k, v} #=> %{bar: 5, foo: 5} for k <- [:foo, :bar], v <- 1..5, into: [], do: {k, v} #=> [foo: 1, foo: 2, foo: 3, foo: 4, foo: 5, bar: 1, bar: 2, bar: 3, bar: 4, bar: 5] ``` ## Anonymous Functions - `fn` => define functions - `->` => one line function definition - `.` => call a function - `when` => guards ```elixir add = fn a, b -> a + b end add.(4, 5) #=> 9 ``` We can have multiple clauses and guards inside functions. ```elixir calc = fn x, y when x > 0 -> x + y x, y -> x * y end calc.(-1, 6) #=> 5 calc.(4, 5) #=> 45 ``` ## Modules And Named Functions - `defmodule` => define Modules - `def` => define functions inside Modules - `defp` => define private functions inside Modules - `when` => guards - `@` => module attributes - `__info__(:functions)` => list functions inside a module - `defdelegate` => delegate functions ```eilxir defmodule Math do def sum(a, b) when is_integer(a) and is_integer(b), do: a + b end Math.sum(1, 2) #=> 3 Math.__info__(:functions) #=> [sum: 2] ``` Module attribute works as constants, evaluated at compilation time: ```eilxir defmodule Math do @foo :bar def print, do: @foo end Math.print #=> :bar ``` Special Module attributes: - `@vsn` - `@moduledoc` - `@doc` - `@behaviour` - `@before_compile` ## Default Argument - `\\` => default argument ```elixir defmodule Concat do def join(a, b, sep \\ " ") do a <> sep <> b end end IO.puts Concat.join("Hello", "world") #=> Hello world IO.puts Concat.join("Hello", "world", "_") #=> Hello_world ``` Default values are **evaluated runtime**. ```elixir defmodule DefaultTest do def dowork(x \\ IO.puts "hello") do x end end DefaultTest.dowork #=> :ok # hello DefaultTest.dowork 123 #=> 123 DefaultTest.dowork #=> :ok # hello ``` Function with multiple clauses and a default value requires a **function head** where default values are set: ```elixir defmodule Concat do def join(a, b \\ nil, sep \\ " ") # head function def join(a, b, _sep) when is_nil(b) do a end def join(a, b, sep) do a <> sep <> b end end IO.puts Concat.join("Hello") #=> Hello IO.puts Concat.join("Hello", "world") #=> Hello world IO.puts Concat.join("Hello", "world", "_") #=> Hello_world ``` ## Function Capturing - `&` => function capturing - `&1` => 1st argument `&` could be used with a module function. When capturing you can use the function/operator with its arity. ```elixir &(&1 * &2).(3, 4) #=> 12 (&*/2).(3, 4) #=> 12 (&Kernel.is_atom(&1)).(:foo) #=> true (&Kernel.is_atom/1).(:foo) #=> true (&{:ok, [&1]}).(:foo) #=> {:ok, [:foo, :bar]} (&[&1, &2]).(:foo, :bar) #=> [:foo, :bar] (&[&1 | [&2]]).(:foo, :bar) #=> [:foo, :bar] ``` ## Behaviours Behaviour modules defines functions - `@callback` => defines a function to be implemented by other modules - `::` => separates the function definition to its return type ```elixir defmodule Parser do @callback parse(String.t) :: any @callback extensions() :: [String.t] end defmodule JSONParser do @behaviour Parser def parse(str), do: # ... parse JSON def extensions, do: ["json"] end ``` ## Exceptions/Errors => raise/try/rescue **Exceptions/Errors** in Elixir are `Structs`. - `raise "oops" #=> ** (RuntimeError) oops` => raises error with message - `raise ArgumentError #=> ** (ArgumentError) argument error` => raises an error by module - `raise ArgumentError, message: "oops" #=> ** (ArgumentError) oops` => raises an error by module with message - `defexception` => define an exception - `try/rescue` => catches an error - `throw/try/catch` => can be used as circuit breaking, but should be avoided - `exit("my reason")` => exiting current process - `after` => ensures some resource is cleaned up even if an exception was raised ```elixir defmodule MyError do defexception message: "default message" end is_map %MyError{} #=> true Map.keys %MyError{} #=> [:__exception__, :__struct__, :message] raise MyError #=> ** (MyError) default message raise MyError, message: "custom message" #=> ** (MyError) custom message ``` You can rescue an error with: ```elixir try do raise "oops" rescue e in RuntimeError -> e after IO.puts "I can do some clean up here" end #=> %RuntimeError{message: "oops"} try do raise "oops" rescue RuntimeError -> "Error!" end #=> "Error!" ``` `throw/catch` sometime is used for circuit breaking, but you can usually use another better way: ```elixir try do Enum.each -50..50, fn(x) -> if rem(x, 13) == 0, do: throw(x) end "Got nothing" catch x -> "Got #{x}" end #=> "Got -39" Enum.find -50..50, &(rem(&1, 13) == 0) #=> -39 ``` `exit` can be caught but this is rare in Elixir: ```elixir try do exit "I am exiting" catch :exit, _ -> "not really" end #=> "not really" ``` You can ommit `try` inside functions and use `rescue`, `catch`, `after` directly: ```elixir def without_even_trying do raise "oops" after IO.puts "cleaning up!" end ``` ## IO - `IO.puts/1 "Hello"` => prints to stdout - `IO.puts :stderr, "Hello"` => prints to stderr - `IO.gets "yes/no: "` => reads an user input ## StringIO - `{:ok, pid} = StringIO.open("my-file.md")` => open a file - `IO.read(pid, 2) #=> "he"` => read first 2 lines ## File - `{:ok, file} = File.open "hello", [:write]` => open file for reading - `IO.binwrite file, "world"` => write into file - `File.close file` => close file - `File.read "my-file.md"` => reads a file - `File.stream!("my-file.md") |> Enum.take(10)` => read the first 10 lines ```elixir {:ok, file} = File.open "my-file.md", [:write] IO.binwrite file, "hello world" File.close file File.read "my-file.md" #=> {:ok, "hello world"} ``` ## Path - `Path.join` => joins - `Path.expand("~/hello")` => expands to full path ## Processes, Tasks and Agents Process in Elixir has the same concept as threads in a lot of other languages, but extremely lightweight in terms of memory and CPU. They are isolated from each other and communicate via message passing. - `spawn/1` => fork a process - `self()` => current process - `Process.alive?(pid)` => check if process is still running - `send/2` => send message to another process - `receive/1` => receive message from another process - `after` => receive option to work with timeout - `flush()` => prints out all messages received - `spawn_link/1` => forks a process and link them, so failures are propagated - `Task.start/1` => starts a task - `Task.start_link/1` => starts a task and link it to the current process - `Process.register(pid, :foo)` => register a name for a process The idea is to have a supervisor that `spawn_link` new processes and when they fail the supervisor will restart them. This is the basics for **Fail Fast** and **Fault Tolerant** in Elixir. Tasks are used in supervision trees. ```elixir parent = self() spawn_link(fn -> send(parent, {:hello, self()}) end) receive do: ({msg, pid} -> "#{inspect pid} => #{msg}"), after: (1_000 -> "nothing after 1s") Task.start_link(fn -> send(parent, {:hello, self()}) end) receive do: ({msg, pid} -> "#{inspect pid} => #{msg}"), after: (1_000 -> "nothing after 1s") flush() ``` **State** can be stored in processes or using its abstraction: `Agent`. Manual implementation of a storage using Elixir processes: ```elixir defmodule KV do def start_link do Task.start_link(fn -> loop(%{}) end) end defp loop(map) do receive do {:get, key, caller} -> send caller, Map.get(map, key) loop(map) {:put, key, value} -> loop(Map.put(map, key, value)) end end end {:ok, pid} = KV.start_link send pid, {:put, :hello, :world} send pid, {:get, :hello, self()} flush() #=> :world ``` Implementation of a storage using `Agent`: ```elixir {:ok, pid} = Agent.start_link(fn -> %{} end) Agent.update(pid, fn map -> Map.put(map, :hello, :world) end) Agent.get(pid, fn map -> Map.get(map, :hello) end) ``` ## alias, require, import and use In order to facilitate code reuse Elixir has: `alias`, `require`, `import` (directives) and `use` (macro). - `alias Foo.Bar, as: Bar` => alias module, so Bar can be called instead of Foo.Bar - `alias Foo.Bar` => `as` is optional on alias - `require Foo` => ensure the module is compiled and available (usually for macros) - `import Foo` => requires and import functions from Foo so they can be called without the `Foo.` prefix - `import List, only: [duplicate: 2]` => only option - `import List, expect: [duplicate: 2]` => except option - `import List, only: :macros` => import only macros - `import List, only: :functions` => import only functions - `use Foo` => invokes the custom code defined in Foo as an extension point - `alias MyApp.{Foo, Bar, Baz}` => multiple alias - `require MyApp.{Foo, Bar, Baz}` => multiple require - `import MyApp.{Foo, Bar, Baz}` => multiple import All modules are defines inside `Elixir` namespace but it can be omitted for convenience. `alias`, `require` and `import` are lexically scoped, which means that it will be valid just inside the scope it was defined. This is **not a global scope**. `require` is usually used to require Elixir macro code: ```elixir Integer.is_odd(3) #=> ** (CompileError): you must require Integer before invoking the macro Integer.is_odd/1 require Integer Integer.is_odd(3) #=> true ``` `use` call `__using__` when the module is being used: ```elixir defmodule Fruit do defmacro __using__(option: option) do IO.puts "options=#{inspect option}" quote do: IO.puts "Using Fruit module" end end defmodule Meal do use Fruit, option: :hello end #=> "Good to see you've added Fruit to your meal" ``` ## Meta Programming - `quote` => shows AST (Abstract Syntax Tree) ```elixir quote do: 2 * 2 == 4 #=> { #=> :==, #=> [context: Elixir, import: Kernel], #=> [ #=> { #=> :*, #=> [context: Elixir, import: Kernel], #=> [2, 2] #=> }, #=> 4 #=> ] #=> } ``` ## Erlang libraries Elixir provider some Erlang modules as atoms. - `:crypto` => crypto functions like `:crypto.hash/2` - `:io` => io functions like `:io.format/2` - `:digraph` => deal with digraphs - `:ets` => large data structure in memory - `:dets` => large data structure on disk - `:math` => math functions like `:math.pi/0` - `:queue` => first-in first-out structure - `:rand` => rand functions like `:rand.uniform/0` - `:zip` => handle zip files - `:zlib` => handle gzip files ================================================ FILE: Git/README.md ================================================ # git-cheat-sheet This is my personal git cheat sheet. This is not a deep dive into how git works, just some of the simple stuff. # Contribute Feel free to add to the repo or fix any mistakes you see. Get started by - Forking the repo. - Clone your forked repo into your local machine. - Create a new branch `git checkout -b your-contribution`. - After making your changes, `git commit -am 'small message about what you did'`. - Then push up into the remote repo with `git push origin HEAD`. - Go to GitHub, go to your forked repo and you should see a yellow bar mentioning your branch. - After hitting that button and reviewing your changes, hit the `Make Pull Request` button near the bottom. - I will get an email, notifying me of your Pull Request (PR) and if it's good, I will merge it. To keep your fork up to date - add a remote upstream repository with `$ git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git` (the original HTTPS clone Url) - see all your remotes with `git remote -v` ``` origin https://github.com/black-shadows/rails.git (fetch) origin https://github.com/black-shadows/rails.git (push) upstream https://github.com/rails/rails.git (fetch) upstream https://github.com/rails/rails.git (push) ``` - now you have a remote called **upstream** which is the original repo - Then run `git pull upstream master`, to see your merged contribution on your local machine # Overview 1. [Starting](#starting) 1. [Git Structure](#git-structure) 1. [Git Logs](#git-logs) 1. [Undo](#undo) 1. [Branches](#branches) 1. [Merging](#merging) 1. [Example Workflow](#example-workflow) 1. [Tricks](#tricks) - [Stripspace](#stripspace) - [Previous Branch](#previous-branch) - [Clean Status](#clean-status) - [Auto Correct](#auto-correct) - [Alias](#alias) 1. [Remotes](#remotes) 1. [GitHub](#github) 1. [Creating a Git Repo](#creating-a-git-repo) 1. [Git Clone](#git-clone) 1. [Reset](#reset) 1. [Update and Delete](#update-and-delete) 1. [Stash](#stash) 1. [Gitignore](#gitignore) 1. [Compare](#compare) 1. [Version Tags](#version-tags) 1. [Collaborate](#collaborate) 1. [Archive](#archive) 1. [Troubleshooting](#troubleshooting) 1. [Security](#security) 1. [Large File Storage](#large-file-storage) ## Starting Starting is the easy part. Make sure you have git installed by opening up your terminal and running, ``` git --version ``` If you're running osx or some form of linux, chances are you already have git installed. If you're running windows, and/or just don't have git installed (it'll be obvious since entering the above command will spit out an unknown command error), head over to the [official site](https://git-scm.com/downloads) to download and install git for your computer Now that you are sure you have a working version of git, it's time to create your working repository. Go inside your project directory (in the terminal) and run `git init`, this will let git know you want it to start keeping track of your changes for this folder. ``` $ cd my_project $ git init ``` To verify, run `ls -al` and you should see the `.git` file, that is how you know you have git for this directory. If you no longer want to use git for this directory then simply delete the `.git` file. **[⬆ back to top](#overview)** ## Git Structure Git breaks things up into three 'trees' which are all maintained by git. **Working Directory** : This is your current **local** tree. This just holds what's in your repository. **Staging** : (Or sometimes known as _index_) is - as the name implies - a staging tree. This will hold all the recent changes you have selected to go into the next commit (more on that later). **HEAD** : Basically, a reference that usually points to the latest _commit_ for the repository. Moving from one tree to another is simple. ``` # You must first move files that you have changed to the staging area. # To specify a single file, $ git add # Alternatively, you can add all files that you have updated, added, or remove by entering, $ git add -A # This will put all the changes you've staged into a new commit. HEAD will now point to this newest commit. $ git commit -m "commit message" # You can do this all in online with. $ git commit -am "commit message" ``` There is a caveat to using `git commit -am "commit message"`, it will not pick up on brand new files or files that have been deleted since the last commit. We personally recommend going through this workflow: ``` git add -A # add all changes to the repo. git commit -m "commit message"` # creates a new commit with all the changes you made. ``` **[⬆ back to top](#overview)** ## Git logs The `git log` command is a way to see all previous commits made to the repository (whether by you or someone else) ``` $ git log commit cd62a7d33d8c20255ef4ba59da61ff21acbf903b Author: black-shadows Date: Fri Apr 3 03:14:41 2015 -0400 one more method commit 7b1db82140dc678eb869c742f0479ccf86168da5 Author: rperryng Date: Fri Apr 3 03:14:08 2015 -0400 succesfull merges ? commit bdc7ede1047a698955bd5b419de1ad9cada68b2c Merge: 8bc63cf cb6ae5f Author: black-shadows Date: Fri Apr 3 03:12:54 2015 -0400 Merge branch 'master' into random-branch ``` The large assortment of numbers and letters right next to the word commit is the sha_key, it's a specific hexadecimal value that references that particular commit. - The author line is simple, it's the user that made the commit - The date line is self-explanatory - and finally the commit message. The commit message helps you understand what work you did within that commit so make sure to make them as verbose as you can, especially if you are working with a team. There is one more thing that I should point out here. If the git log is large enough, git will open it in `vim`, an editor for the terminal. To exit the git log, simply press `esc`, then `:`, then `q` and hit enter. But if you want cleaner more readable information, definitely try the following: ``` $ git log --oneline -5 70693a1 Merge branch 'master' into random-branch 9f4b039 conflict feature 2 on master aa87d8a branch conflict feature 1bde9e5 added a conflict feature 6f1c4d9 fourth feature was added ``` where `-5` is an option that lets you specify the number of most recent commits you want to see. (You can use these options together with the other ones listed below). To see all the commits made by one author, ``` $ git log --author=black-shadows ``` To see all your merges (we will talk about what a merge is later), ``` $ git log --merges ``` To see the repo history in a visual branching format, ``` $ git log --graph ``` To see all the other ways of viewing git logs, you can check out the [documentation](http://git-scm.com/docs/git-log). **[⬆ back to top](#overview)** ## Undo One of the most compelling reasons to use Git is that you can roll back to a previous snapshot (commit) of the repository, in case you've made a mistake. However, reverting back to a specific commit can be really confusing if you've never done it before. Git gives you several ways to do it, and depending on the situation, one way is easier than another. First, you'll want to identify which commit you want to roll back to. enter `git log --oneline` and select the first 5-6 digits of the sha_key for the commit you want to return to. I will be using the sha_key of 184353d9 (you usually only need the first 6-7 digits of your commit). as the commit key that we want to return to. ##### Go back and checkout 1. There are no changes that have not been committed. 2. You just want to go back to an older commit, but you don't want to delete all your newer commits. ``` $ git checkout 184353d9 # Or $ git checkout -b new_branch_name 184353d9 ``` ##### Delete everything and just start restart from chosen commit 1. There are no changes that have not been committed. 2. You made a mistake and just need to go back to that commit, erasing everything you have done since then. ``` $ git reset --hard 184353d9 ``` ##### Start over from head or master 1. You just made some changes to files for testing ( you do not want to commit ). 2. You have not committed your changes yet. ``` $ git reset --hard HEAD ``` Remember that HEAD is (almost always) a pointer to the latest commit on that branch. ##### Ctrl + Z 1. You have no idea what you did, no idea where you are and you just want to go back - The reflog command is the ultimate safety net. It keeps track of everything you just did, from checking out new branches, to rebases, the reflog is essentially a way to move back through time. ``` $ git reflog # after finding the place you want to go back to $ git reset --hard ``` ##### Correcting small mistakes 1. You've already made your commit and you've noticed something small that *should* have been in that commit (usually grammar, stale debug statements or comments). This will allow you to *add* the changes to that most recent commit, as if it was there all along! ``` $ git commit --amend --no-edit ``` It's important to note that if you've already pushed the commit before fixing your mistake, you won't be able to push the corrected commit. This is because the remote repo and the local repo have conflicting versions of the same commit. If you've been working on a branch that *only* you have been working on, you can force the remote repository to accept the corrected commit. **you should only do this if you know no one else has pulled the *non* corrected commit already**. This will almost always be the case if you have been working on your own branch! ``` $ git push -f ``` **[⬆ back to top](#overview)** ## Branches The Master branch is the branch that you start in and it's the branch that you should never work directly on. Anytime you want to make changes to the project, you should checkout a different branch. Once you have finished implementing said feature you can then merge your branch into master. This is great because it allows you to organize your features and keep a controlled working version of the app to compare with. Branches are a great way to start implementing new features. When you start making a new feature, you first run `git pull` on the master branch to make sure you have all the latest code. - You should never be getting a merge error when doing a `git pull`. If you find yourself in this situation that means that you made a few commits on the master branch by accident. Stop the merge and make sure you're on a clean tree, then do this: ``` $ git checkout -b temp-changes $ git reset --hard origin/master ``` - All your changes that should not have been on master have been moved to a separate branch (temp-changes). The second line then looks at the remote directory and just sets your local version of the master branch to the same one that is on origin (origin is the name of the remote branch, usually hosted on GitHub). To create a new branch: ``` $ git checkout -b new_branch_name ``` Branch names should be descriptive to what you are trying to do. Their names cannot contain any spaces and its most common to use either `-` or `_` to separate the words ``` $ git checkout -b getting-live-messages-from-websocket ``` To see which branch you are currently in: ``` $ git status # Or $ git branch ``` To merge a branch once you are done. We will be merging the `getting-live-messages-from-websocket` branch _into_ master ``` $ git checkout master $ git merge getting-live-messages-from-websocket ``` **[⬆ back to top](#overview)** ## Merging ##### Merge ``` $ git merge branch_name ``` The `git merge` command by itself just puts all the commits into master, as if the branch you made never existed. We personally recommend using the `--no-ff` (no fast forward) flag. This will create a commit just for the act of merging your commits. It will also preserve the fact that those commits were made on a branch. If you are going to use the `--no-ff` flag, I also recommend using the `--no-edit` flag with it as well. This will automatically create the commit message for you (something like `Merge branch `) ``` $ git merge add-tests-for-app-version --no-ff --no-edit ``` * When merging, you are usually on the master branch and merge with your own branch ##### Rebase * When rebasing, you are usually on the branch you are working on. * Rebase right before you decide merge with master ``` $ git rebase master ``` _Why Rebase?_, It's a great to make a clean looking tree, it appears as if you never created a branch to begin with. Remember a rebase is simply shifting the commit that your branch branched off of, to be the HEAD of master. **[⬆ back to top](#overview)** ## Tricks ### Stripspace - Removes trailing whitespace - Collapse New lines - Adds new lines to end of file - Simply pass in the file that you want to strip ```bash $ git stripspace < text_file.txt ``` ### Previous Branch - Quickly go back to your last branch ```bash $ git checkout - ``` ### Clean Status - Add `-sb` to get a cleaner `git status` ```bash $ git status -sb ``` ### Auto Correct - Set auto correct to true for Git commands ```bash $ git config --global help.autocorrect 1 ``` - Results in: ```bash $ git comit -m "commit message" # WARNING: You called a Git command named 'comit', which does not exist. # Continuing under the assumption that you meant 'commit' # in 0.1 seconds automatically... ``` ### Alias - Add shortcuts to reduce your typing ```bash $ git config --global alias.alias_command git_command ``` Examples: - Set `git stat` to `git status -sb` ```bash $ git config --global alias.stat 'status -sb' ``` - Combine functions with `&&` ```bash $ git config --global alias.ac '!git add -A && git commit' ``` - The commit messages needs to be entered in from the editor if using the above alias ## Merge Conflicts If you try and perform a merge, there is a chance that you will end up with a merge conflict. Before we go over how to solve these problems, an important thing to learn is how to back out of the current predicament ``` $ git merge --abort # or $ git rebase --abort ``` To see which files contain merge conflicts (assuming you haven't backed out yet). Just run: ``` $ git status ``` The important thing to remember here is that you have final say as to how the merge conflict is handled. If a co-worker spent hours and days on a feature that conflicted with yours, You can simply overwrite all their hard work. ( But let's try our best not to be so selfish ;) ). ##### Edit Conflicts * Happens when two users edit the same lines of a file. After opening up the file with the conflict you should see ``` <<<<<<< HEAD def function_one ======= def function_two >>>>>>> your_branch ``` `your_branch` is the name of the branch that you are merging, `HEAD` is the latest commit on the branch that you are merging with. Going back to our example, `HEAD` would be, and usually is, the _HEAD_ of the master branch After correcting the conflict, ``` $ git add . $ git commit -am "fixing merge conflicts" ``` * If you want to simply take the changes that are in `HEAD` ``` $ git checkout --theirs ``` * If you want to keep your own changes ``` $ git checkout --yours ``` ##### Removed files conflict * One person modified the file, while another deleted the file you actually have two choices here, delete the file, or keep the changes 1. Keeping the file with new changes Simply add the file back and commit. (let's say the README.md file was modified) ``` $ git add README.md $ git commit ``` 2. deleting the file and disregarding the changes Simply remove the file and commit: ``` $ git rm REAMDE.md $ git commit ``` If you had a conflict in the middle of a rebase, after fixing your conflicts run: ``` $ git add . $ git rebase --continue ``` **[⬆ back to top](#overview)** ## Example Workflow Now that you've seen all the bits and pieces, it would probably be helpful to see what the workflow with all these different commands looks like. This is the typical situation. You're working on a project which is being tracked by git. You want to begin adding a feature or fixing a bug. Begin by checking out a new branch with a descriptive branch name. For demo purposes, the branch name will be `fix-readme-grammar`. ``` $ git checkout -b fix-readme-grammar ``` after making your changes, review your changes by running ``` $ git status ``` and usually ``` $ git diff ``` This will allow you to do a last minute review of your changes before deciding to make a new commit Once you're satisfied, add the files to the staging area ``` $ git add -A ``` Now, create your new commit ``` $ git commit -m "Restructured commit section. Fix spelling mistakes for introductory paragraph." ``` Of course, you can always combine these by entering `git add -A && git commit -m "commit message"` Now you'll want to push your changes to the remote repo. Since it's a new branch, you'll have to tell the remote repo that you want it to start tracking this new branch as well. You can set up remote tracking and push at the same time by entering ``` $ git push -u origin fix-readme-grammar ``` After your first push, you can simply use `git push` for future commits on this branch. Once you've made enough changes, commits, and pushes that you're happy enough to merge it back into master, you'll want to head over to github (or whatever service you're using for your remote repo) to submit a pull request. Once you've got the OK to merge it back in to master, ``` $ git checkout master $ git pull $ git merge fix-readme-grammar --no-ff --no-edit ``` Lastly, you'll want to delete the branches, first on your remote... ``` $ git push origin --delete fix-readme-grammar ``` ...and then on your local machine ``` $ git branch -d fix-readme-grammar ``` **[⬆ back to top](#overview)** ## Remotes We are nearing the GitHub section so it's time to introduce **Remotes** - When you use `git init` you just started git version control on that local directory (and child directory). But everything is maintained in your local machine. The concept of a remote is to start keeping a central version of the repository online, usually on a service like Github. - First you have to actually create the remote repository, which is very simple to do. Just go on github.com and click the `New Repository` icon the nav bar - Github will give you all the needed instructions as to how we move our project into the remote repo - By default the name of your repo and all remote repos are set to **origin**. Note that you never have to change this if you don't want to (most people don't) ##### Push - To push a new branch onto the remote repo ``` $ git push -u ``` - Or to make things a little nicer ``` $ git push -u origin HEAD ``` - After that, you can usually just use `git push` to push to the matching branch on remote (though you may to have tell git you want `git push` to only push to the matching branch on the remote `git config --global push.default simple`, more on this [here](http://stackoverflow.com/a/948397/3194316)) ``` $ git push ``` - This will push the current branch that you are working on The `-u` is short for `--set-upstream`, which just means that if you ever want to `pull` the remote branch, you simply have to type `git pull` while you are currently checked out in the local branch. **[⬆ back to top](#overview)** ## GitHub Github is a website that anyone can access and a great way to work on projects with other people. You can also use Github to contribute to open source, a great way to help everyone! ## Creating a Git Repo - Go to the top right of the page and click on the create new button. Then pick `New repository`. - pick the name of the repo, the name should be the name for the project that you are working on. For example the name of this repo is **git-cheat-sheet** - You'll want to initialize with a README.md file. The README.md is a file that you want other people to read before looking at your project For example, what you are reading right now is a README.md file. If you want to learn about Markdown, which is how you can make things look cool, read here: https://help.github.com/articles/github-flavored-markdown/ - And that's all! You have just created your remote repository. If you have an existing projects, you can import that project to this repo. If this is just the beginning, you can clone the remote repo to your local machine. ## Git Clone - If you look at the right side of a git repo's main page, you will see its _git clone_ URL. Copy that link to your clipboard, either with just `cmd + c` or by clicking on the clipboard icon. Then go to the local directory you want to clone the project to and run: ``` $ git clone # example $ git clone https://github.com/black-shadows/git-cheat-sheet.git ``` ## Reset Go back to commit: `git revert 073791e7dd71b90daa853b2c5acc2c925f02dbc6` Soft reset (move HEAD only; neither staging nor working dir is changed): `git reset --soft 073791e7dd71b90daa853b2c5acc2c925f02dbc6` Undo latest commit: `git reset --soft HEAD~ ` Mixed reset (move HEAD and change staging to match repo; does not affect working dir): `git reset --mixed 073791e7dd71b90daa853b2c5acc2c925f02dbc6` Hard reset (move HEAD and change staging dir and working dir to match repo): `git reset --hard 073791e7dd71b90daa853b2c5acc2c925f02dbc6` ## Update and Delete Test-Delete untracked files: `git clean -n` Delete untracked files (not staging): `git clean -f` Unstage (undo adds): `git reset HEAD index.html` Update most recent commit (also update the commit message): `git commit --amend -m "New Message"` ## Stash Put in stash: `git stash save "Message"` Show stash: `git stash list` Show stash stats: `git stash show stash@{0}` Show stash changes: `git stash show -p stash@{0}` Use custom stash item and drop it: `git stash pop stash@{0}` Use custom stash item and do not drop it: `git stash apply stash@{0}` Delete custom stash item: `git stash drop stash@{0}` Delete complete stash: `git stash clear` ## Gitignore About: https://help.github.com/articles/ignoring-files Useful templates: https://github.com/github/gitignore Add or edit gitignore: `nano .gitignore` Track empty dir: `touch dir/.gitkeep` ## Compare Compare modified files: `git diff` Compare modified files and highlight changes only: `git diff --color-words index.html` Compare modified files within the staging area: `git diff --staged` Compare branches: `git diff master..branchname` Compare branches like above: `git diff --color-words master..branchname^` Compare commits: `git diff 6eb715d` `git diff 6eb715d..HEAD` `git diff 6eb715d..537a09f` Compare commits of file: `git diff 6eb715d index.html` `git diff 6eb715d..537a09f index.html` Compare without caring about spaces: `git diff -b 6eb715d..HEAD` or: `git diff --ignore-space-change 6eb715d..HEAD` Compare without caring about all spaces: `git diff -w 6eb715d..HEAD` or: `git diff --ignore-all-space 6eb715d..HEAD` Useful comparings: `git diff --stat --summary 6eb715d..HEAD` Blame: `git blame -L10,+1 index.html` ## Version Tags Show all released versions: `git tag` Show all released versions with comments: `git tag -l -n1` Create release version: `git tag v1.0.0` Create release version with comment: `git tag -a v1.0.0 -m 'Message'` Checkout a specific release version: `git checkout v1.0.0` ## Collaborate Show remote: `git remote` Show remote details: `git remote -v` Add remote upstream from GitHub project: `git remote add upstream https://github.com/user/project.git` Add remote upstream from existing empty project on server: `git remote add upstream ssh://root@123.123.123.123/path/to/repository/.git` Fetch: `git fetch upstream` Fetch a custom branch: `git fetch upstream branchname:local_branchname` Merge fetched commits: `git merge upstream/master` Remove origin: `git remote rm origin` Show remote branches: `git branch -r` Show all branches: `git branch -a` Create and checkout branch from a remote branch: `git checkout -b local_branchname upstream/remote_branchname` Compare: `git diff origin/master..master` Push (set default with `-u`): `git push -u origin master` Push: `git push origin master` Force-Push: `git push origin master --force Pull: `git pull` Pull specific branch: `git pull origin branchname` Fetch a pull request on GitHub by its ID and create a new branch: `git fetch upstream pull/ID/head:new-pr-branch` Clone to localhost: `git clone https://github.com/user/project.git` or: `git clone ssh://user@domain.com/~/dir/.git` Clone to localhost folder: `git clone https://github.com/user/project.git ~/dir/folder` Clone specific branch to localhost: `git clone -b branchname https://github.com/user/project.git` Delete remote branch (push nothing): `git push origin :branchname` or: `git push origin --delete branchname` ## Archive Create a zip-archive: `git archive --format zip --output filename.zip master` Export/write custom log to a file: `git log --author=sven --all > log.txt` ## Troubleshooting Ignore files that have already been committed to a Git repository: http://stackoverflow.com/a/1139797/1815847 ## Security Hide Git on the web via `.htaccess`: `RedirectMatch 404 /\.git` (more info here: http://stackoverflow.com/a/17916515/1815847) ## Large File Storage Website: https://git-lfs.github.com/ Install: `brew install git-lfs` Track `*.psd` files: `git lfs track "*.psd"` (init, add, commit and push as written above) ================================================ FILE: Golang/README.md ================================================ # Go Cheat Sheet # Index 1. [Basic Syntax](#basic-syntax) 2. [Operators](#operators) * [Arithmetic](#arithmetic) * [Comparison](#comparison) * [Logical](#logical) * [Other](#other) 3. [Declarations](#declarations) 4. [Functions](#functions) * [Functions as values and closures](#functions-as-values-and-closures) * [Variadic Functions](#variadic-functions) 5. [Built-in Types](#built-in-types) 6. [Type Conversions](#type-conversions) 7. [Packages](#packages) 8. [Control structures](#control-structures) * [If](#if) * [Loops](#loops) * [Switch](#switch) 9. [Arrays, Slices, Ranges](#arrays-slices-ranges) * [Arrays](#arrays) * [Slices](#slices) * [Operations on Arrays and Slices](#operations-on-arrays-and-slices) 10. [Maps](#maps) 11. [Structs](#structs) 12. [Pointers](#pointers) 13. [Interfaces](#interfaces) 14. [Embedding](#embedding) 15. [Errors](#errors) 16. [Concurrency](#concurrency) * [Goroutines](#goroutines) * [Channels](#channels) * [Channel Axioms](#channel-axioms) 17. [Printing](#printing) 18. [Reflection](#reflection) * [Type Switch](#type-switch) * [Examples](https://github.com/a8m/reflect-examples) 19. [Snippets](#snippets) * [Http-Server](#http-server) ## Credits Most example code taken from [A Tour of Go](http://tour.golang.org/), which is an excellent introduction to Go. If you're new to Go, do that tour. Seriously. ## Go in a Nutshell * Imperative language * Statically typed * Syntax tokens similar to C (but less parentheses and no semicolons) and the structure to Oberon-2 * Compiles to native code (no JVM) * No classes, but structs with methods * Interfaces * No implementation inheritance. There's [type embedding](http://golang.org/doc/effective%5Fgo.html#embedding), though. * Functions are first class citizens * Functions can return multiple values * Has closures * Pointers, but not pointer arithmetic * Built-in concurrency primitives: Goroutines and Channels # Basic Syntax ## Hello World File `hello.go`: ```go package main import "fmt" func main() { fmt.Println("Hello Go") } ``` `$ go run hello.go` ## Operators ### Arithmetic |Operator|Description| |--------|-----------| |`+`|addition| |`-`|subtraction| |`*`|multiplication| |`/`|quotient| |`%`|remainder| |`&`|bitwise and| |`\|`|bitwise or| |`^`|bitwise xor| |`&^`|bit clear (and not)| |`<<`|left shift| |`>>`|right shift| ### Comparison |Operator|Description| |--------|-----------| |`==`|equal| |`!=`|not equal| |`<`|less than| |`<=`|less than or equal| |`>`|greater than| |`>=`|greater than or equal| ### Logical |Operator|Description| |--------|-----------| |`&&`|logical and| |`\|\|`|logical or| |`!`|logical not| ### Other |Operator|Description| |--------|-----------| |`&`|address of / create pointer| |`*`|dereference pointer| |`<-`|send / receive operator (see 'Channels' below)| ## Declarations Type goes after identifier! ```go var foo int // declaration without initialization var foo int = 42 // declaration with initialization var foo, bar int = 42, 1302 // declare and init multiple vars at once var foo = 42 // type omitted, will be inferred foo := 42 // shorthand, only in func bodies, omit var keyword, type is always implicit const constant = "This is a constant" ``` ## Functions ```go // a simple function func functionName() {} // function with parameters (again, types go after identifiers) func functionName(param1 string, param2 int) {} // multiple parameters of the same type func functionName(param1, param2 int) {} // return type declaration func functionName() int { return 42 } // Can return multiple values at once func returnMulti() (int, string) { return 42, "foobar" } var x, str = returnMulti() // Return multiple named results simply by return func returnMulti2() (n int, s string) { n = 42 s = "foobar" // n and s will be returned return } var x, str = returnMulti2() ``` ### Functions As Values And Closures ```go func main() { // assign a function to a name add := func(a, b int) int { return a + b } // use the name to call the function fmt.Println(add(3, 4)) } // Closures, lexically scoped: Functions can access values that were // in scope when defining the function func scope() func() int{ outer_var := 2 foo := func() int { return outer_var} return foo } func another_scope() func() int{ // won't compile because outer_var and foo not defined in this scope outer_var = 444 return foo } // Closures func outer() (func() int, int) { outer_var := 2 inner := func() int { outer_var += 99 // outer_var from outer scope is mutated. return outer_var } inner() return inner, outer_var // return inner func and mutated outer_var 101 } ``` ### Variadic Functions ```go func main() { fmt.Println(adder(1, 2, 3)) // 6 fmt.Println(adder(9, 9)) // 18 nums := []int{10, 20, 30} fmt.Println(adder(nums...)) // 60 } // By using ... before the type name of the last parameter you can indicate that it takes zero or more of those parameters. // The function is invoked like any other function except we can pass as many arguments as we want. func adder(args ...int) int { total := 0 for _, v := range args { // Iterates over the arguments whatever the number. total += v } return total } ``` ## Built-in Types ``` bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr byte // alias for uint8 rune // alias for int32 ~= a character (Unicode code point) - very Viking float32 float64 complex64 complex128 ``` ## Type Conversions ```go var i int = 42 var f float64 = float64(i) var u uint = uint(f) // alternative syntax i := 42 f := float64(i) u := uint(f) ``` ## Packages * Package declaration at top of every source file * Executables are in package `main` * Convention: package name == last name of import path (import path `math/rand` => package `rand`) * Upper case identifier: exported (visible from other packages) * Lower case identifier: private (not visible from other packages) ## Control structures ### If ```go func main() { // Basic one if x > 0 { return x } else { return -x } // You can put one statement before the condition if a := b + c; a < 42 { return a } else { return a - 42 } // Type assertion inside if var val interface{} val = "foo" if str, ok := val.(string); ok { fmt.Println(str) } } ``` ### Loops ```go // There's only `for`, no `while`, no `until` for i := 1; i < 10; i++ { } for ; i < 10; { // while - loop } for i < 10 { // you can omit semicolons if there is only a condition } for { // you can omit the condition ~ while (true) } ``` ### Switch ```go // switch statement switch operatingSystem { case "darwin": fmt.Println("Mac OS Hipster") // cases break automatically, no fallthrough by default case "linux": fmt.Println("Linux Geek") default: // Windows, BSD, ... fmt.Println("Other") } // as with for and if, you can have an assignment statement before the switch value switch os := runtime.GOOS; os { case "darwin": ... } // you can also make comparisons in switch cases number := 42 switch { case number < 42: fmt.Println("Smaller") case number == 42: fmt.Println("Equal") case number > 42: fmt.Println("Greater") } // cases can be presented in comma-separated lists var char byte = '?' switch char { case ' ', '?', '&', '=', '#', '+', '%': fmt.Println("Should escape") } ``` ## Arrays, Slices, Ranges ### Arrays ```go var a [10]int // declare an int array with length 10. Array length is part of the type! a[3] = 42 // set elements i := a[3] // read elements // declare and initialize var a = [2]int{1, 2} a := [2]int{1, 2} //shorthand a := [...]int{1, 2} // elipsis -> Compiler figures out array length ``` ### Slices ```go var a []int // declare a slice - similar to an array, but length is unspecified var a = []int {1, 2, 3, 4} // declare and initialize a slice (backed by the array given implicitly) a := []int{1, 2, 3, 4} // shorthand chars := []string{0:"a", 2:"c", 1: "b"} // ["a", "b", "c"] var b = a[lo:hi] // creates a slice (view of the array) from index lo to hi-1 var b = a[1:4] // slice from index 1 to 3 var b = a[:3] // missing low index implies 0 var b = a[3:] // missing high index implies len(a) a = append(a,17,3) // append items to slice a c := append(a,b...) // concatenate slices a and b // create a slice with make a = make([]byte, 5, 5) // first arg length, second capacity a = make([]byte, 5) // capacity is optional // create a slice from an array x := [3]string{"Лайка", "Белка", "Стрелка"} s := x[:] // a slice referencing the storage of x ``` ### Operations on Arrays and Slices `len(a)` gives you the length of an array/a slice. It's a built-in function, not a attribute/method on the array. ```go // loop over an array/a slice for i, e := range a { // i is the index, e the element } // if you only need e: for _, e := range a { // e is the element } // ...and if you only need the index for i := range a { } // In Go pre-1.4, you'll get a compiler error if you're not using i and e. // Go 1.4 introduced a variable-free form, so that you can do this for range time.Tick(time.Second) { // do it once a sec } ``` ## Maps ```go var m map[string]int m = make(map[string]int) m["key"] = 42 fmt.Println(m["key"]) delete(m, "key") elem, ok := m["key"] // test if key "key" is present and retrieve it, if so // map literal var m = map[string]Vertex{ "Bell Labs": {40.68433, -74.39967}, "Google": {37.42202, -122.08408}, } ``` ## Structs There are no classes, only structs. Structs can have methods. ```go // A struct is a type. It's also a collection of fields // Declaration type Vertex struct { X, Y int } // Creating var v = Vertex{1, 2} var v = Vertex{X: 1, Y: 2} // Creates a struct by defining values with keys var v = []Vertex{{1,2},{5,2},{5,5}} // Initialize a slice of structs // Accessing members v.X = 4 // You can declare methods on structs. The struct you want to declare the // method on (the receiving type) comes between the the func keyword and // the method name. The struct is copied on each method call(!) func (v Vertex) Abs() float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } // Call method v.Abs() // For mutating methods, you need to use a pointer (see below) to the Struct // as the type. With this, the struct value is not copied for the method call. func (v *Vertex) add(n float64) { v.X += n v.Y += n } ``` **Anonymous structs:** Cheaper and safer than using `map[string]interface{}`. ```go point := struct { X, Y int }{1, 2} ``` ## Pointers ```go p := Vertex{1, 2} // p is a Vertex q := &p // q is a pointer to a Vertex r := &Vertex{1, 2} // r is also a pointer to a Vertex // The type of a pointer to a Vertex is *Vertex var s *Vertex = new(Vertex) // new creates a pointer to a new struct instance ``` ## Interfaces ```go // interface declaration type Awesomizer interface { Awesomize() string } // types do *not* declare to implement interfaces type Foo struct {} // instead, types implicitly satisfy an interface if they implement all required methods func (foo Foo) Awesomize() string { return "Awesome!" } ``` ## Embedding There is no subclassing in Go. Instead, there is interface and struct embedding. ```go // ReadWriter implementations must satisfy both Reader and Writer type ReadWriter interface { Reader Writer } // Server exposes all the methods that Logger has type Server struct { Host string Port int *log.Logger } // initialize the embedded type the usual way server := &Server{"localhost", 80, log.New(...)} // methods implemented on the embedded struct are passed through server.Log(...) // calls server.Logger.Log(...) // the field name of the embedded type is its type name (in this case Logger) var logger *log.Logger = server.Logger ``` ## Errors There is no exception handling. Functions that might produce an error just declare an additional return value of type `Error`. This is the `Error` interface: ```go type error interface { Error() string } ``` A function that might return an error: ```go func doStuff() (int, error) { } func main() { result, err := doStuff() if err != nil { // handle error } else { // all is good, use result } } ``` # Concurrency ## Goroutines Goroutines are lightweight threads (managed by Go, not OS threads). `go f(a, b)` starts a new goroutine which runs `f` (given `f` is a function). ```go // just a function (which can be later started as a goroutine) func doStuff(s string) { } func main() { // using a named function in a goroutine go doStuff("foobar") // using an anonymous inner function in a goroutine go func (x int) { // function body goes here }(42) } ``` ## Channels ```go ch := make(chan int) // create a channel of type int ch <- 42 // Send a value to the channel ch. v := <-ch // Receive a value from ch // Non-buffered channels block. Read blocks when no value is available, write blocks until there is a read. // Create a buffered channel. Writing to a buffered channels does not block if less than unread values have been written. ch := make(chan int, 100) close(ch) // closes the channel (only sender should close) // read from channel and test if it has been closed v, ok := <-ch // if ok is false, channel has been closed // Read from channel until it is closed for i := range ch { fmt.Println(i) } // select blocks on multiple channel operations, if one unblocks, the corresponding case is executed func doStuff(channelOut, channelIn chan int) { select { case channelOut <- 42: fmt.Println("We could write to channelOut!") case x := <- channelIn: fmt.Println("We could read from channelIn") case <-time.After(time.Second * 1): fmt.Println("timeout") } } ``` ### Channel Axioms - A send to a nil channel blocks forever ```go var c chan string c <- "Hello, World!" // fatal error: all goroutines are asleep - deadlock! ``` - A receive from a nil channel blocks forever ```go var c chan string fmt.Println(<-c) // fatal error: all goroutines are asleep - deadlock! ``` - A send to a closed channel panics ```go var c = make(chan string, 1) c <- "Hello, World!" close(c) c <- "Hello, Panic!" // panic: send on closed channel ``` - A receive from a closed channel returns the zero value immediately ```go var c = make(chan int, 2) c <- 1 c <- 2 close(c) for i := 0; i < 3; i++ { fmt.Printf("%d ", <-c) } // 1 2 0 ``` ## Printing ```go fmt.Println("Hello, 你好, नमस्ते, Привет, ᎣᏏᏲ") // basic print, plus newline p := struct { X, Y int }{ 17, 2 } fmt.Println( "My point:", p, "x coord=", p.X ) // print structs, ints, etc s := fmt.Sprintln( "My point:", p, "x coord=", p.X ) // print to string variable fmt.Printf("%d hex:%x bin:%b fp:%f sci:%e",17,17,17,17.0,17.0) // c-ish format s2 := fmt.Sprintf( "%d %f", 17, 17.0 ) // formatted print to string variable hellomsg := ` "Hello" in Chinese is 你好 ('Ni Hao') "Hello" in Hindi is नमस्ते ('Namaste') ` // multi-line string literal, using back-tick at beginning and end ``` ## Reflection ### Type Switch A type switch is like a regular switch statement, but the cases in a type switch specify types (not values), and those values are compared against the type of the value held by the given interface value. ```go func do(i interface{}) { switch v := i.(type) { case int: fmt.Printf("Twice %v is %v\n", v, v*2) case string: fmt.Printf("%q is %v bytes long\n", v, len(v)) default: fmt.Printf("I don't know about type %T!\n", v) } } func main() { do(21) do("hello") do(true) } ``` # Snippets ## HTTP Server ```go package main import ( "fmt" "net/http" ) // define a type for the response type Hello struct{} // let that type implement the ServeHTTP method (defined in interface http.Handler) func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello!") } func main() { var h Hello http.ListenAndServe("localhost:4000", h) } // Here's the method signature of http.ServeHTTP: // type Handler interface { // ServeHTTP(w http.ResponseWriter, r *http.Request) // } ``` ================================================ FILE: Java/README.md ================================================ # Java Cheat Sheet Review Java 9 Concepts at Jet Speed. ### Complete Java Course - https://www.udemy.com/java-programming-tutorial-for-beginners/ ## Introduction ## Background ### Popularity of Java - Platform Independent or Portable - Object Oriented Language - Security - Rich API - Great IDE's - Omnipresent - Web Applications (Java EE (JSP, Servlets), Spring, Struts..) - Mobile Apps(Android) - Microservices (Spring Boot) ### Platform Independence - Build once, run anywhere ![alt text](images/java-write-once-run-anywhere.png) - Java bytecode is the instruction set of the Java virtual machine ``` graph TD A[Java Code] -->|Compiled| B(Bytecode) B --> C{Run} C -->|bytecode| D[Windows JVM] D --> K[Windows Instructions] C -->|bytecode| E[Unix JVM] E --> L[Unix Instructions] C -->|bytecode| F[Linux JVM] F --> M[Linux Instructions] C -->|bytecode| G[Any other platform JVM] G --> N[Linux Instructions] ``` ### JDK vs JVM VS JRE - JVM (Java Virtual Machine) - runs the Java bytecode. - JRE - JVM + Libraries + Other Components (to run applets and other java applications) - JDK - JRE + Compilers + Debuggers ### ClassLoader - Find and Loads Java Classes! Three Types - System Class Loader - Loads all application classes from CLASSPATH - Extension Class Loader - Loads all classes from extension directory - Bootstrap Class Loader - Loads all the Java core files Order of execution of ClassLoaders - JVM needs to find a class, it starts with System Class Loader. - If it is not found, it checks with Extension Class Loader. - If it not found, it goes to the Bootstrap Class Loader. - If a class is still not found, a ClassNotFoundException is thrown. ### First Java Program ```java public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World"); } } ``` Notes - Every line of code we write in Java is part of something called Class. We will talk about Class later. - First line defines a public class called HelloWorld. All the code in a class is between { and }. - When a program runs, Java should know which line of code has to be run first. public static void main(String[] args) is the first method that is run when a program is executed. > Java, like any other programming language, is particular about syntax!! ### Using Java and JavaC There are two steps involved in running a Java Program - Compilation - Execution #### Compilation We use javac to compile java code. - Open CommandPrompt/Terminal and cd to the folder where HelloWorld.java file is present - execute the command below ``` javac HelloWorld.java ``` - You should see two files HelloWorld.java and HelloWorld.class in the folder. - HelloWorld.class contains the java bytecode #### Execution - Now we can run the program using JVM - execute the command below ``` java HelloWorld ``` - You should see the output "Hello World" printed in the console. ### Class and Object - What is a class? - Definining an instance of a class - an object - Invoking a method on the object ### Variables - Value of a variable changes during the course of a program execution. ``` int number; number = 5; System.out.println(number);//5 number = number + 2; System.out.println(number);//7 number = number + 2; System.out.println(number);//9 ``` Declaring and Initializing Variables - Declaration is give a variable a name and type ``` TYPE variableName; ``` #### Tips - Two or more variables of single type can be declared together. - All six numeric types in Java are signed. ### Primitive Variables Variables that store value. Java defines few types like int (numbers), float(floating point numbers), char (characters). Variables of these types store the value of the variable directly. These are not objects. These are called primitive variables. An example is shown below: Primitive Variables contains bits representing the value of the variable. ``` int value = 5; ``` Different primitive types in java are char, boolean, byte, short, int, long, double, or float. Because of these primitive types, Java is NOT considered to be a pure objected oriented language. Numeric Data Types - Types : byte, short, int, long, float, double - Number of bits : 8, 16, 32, 64, 32, 64 - Range : -x to x-1 where x = Power(2, number of bits -1) char Data Type - Used to store characters. Size of character is 16 bits. Examples ``` int i = 15; long longValue = 1000000000000l; byte b = (byte)254; float f = 26.012f; double d = 123.567; boolean isDone = true; boolean isGood = false; char ch = 'a'; char ch2 = ';'; ``` ### Reference Variables ``` Animal dog = new Animal(); ``` The instance of new Animal - Animal object - is created in memory. The memory address of the object created is stored in the dog reference variable. Reference Variables contains a reference or a guide to get to the actual object in memory. #### Puzzles ``` Animal dog1 = new Animal(); dog1 = new Animal(); ``` What will happen? Two objects of type Animal are created. Only one reference variable is created. ``` Animal animal1 = new Animal(); Animal animal2 = new Animal(); animal1 = animal2; ``` What will happen? What would happen if the same was done with primitive variables? ### Identifiers Names given to a class, method, interface, variables are called identifiers. Legal Identifier Names - Combination of letters, numbers, $ and under-score(_) - Cannot start with a number - Cannot be a keyword - No limit on length of identifier ### Java Keywords List of Java Keywords - Primitives DataTypes : byte,short,int,long,float,double,char,boolean - Flow Control : if, else,for,do, while, switch, case, default, break, continue,return - Exception Handling : try, catch, finally,throw,throws,assert - Modifiers : public,private,protected,final,static,native,abstract, synchronized,transient,volatile,strictfp - Class Related : class,interface,package,extends,implements,import - Object Related : new, instanceof,super,this - Literals : true, false, null - Others : void, enum - Unused : goto,const ### Literals Any primitive data type value in source code is called Literal. There are four types of literals: - Integer & Long - Floating Point - Boolean - Double #### Literals Integer Literals - There are 3 ways of representing an Integer Literal. - Decimal. Examples: 343, 545 - Octal. Digits 0 to 7. Place 0 before a number. Examples : 070,011 - Hexadecimal. Digits 0 to 9 and alphabets A to F (10-15). Case insensitive. - An integer literal by default is int. Long Literals - All 3 integer formats: Decimal, Octal and Hexadecimal can be used to represent long by appending with L or l. Floating point Literals - Numbers with decimal points. Example: ```double d = 123.456;``` - To declare a float, append f. Example: float f = 123.456f; - Floating point literals are double by default. - Appending d or D at end of double literal is optional Example: ```double d = 123.456D;``` Boolean Literals - Valid boolean values are true and false. - TRUE, FALSE or True, False are invalid. Character Literals - Represented by single character between single quotes Example: ```char a = 'a'``` - Unicode Representation also can be used. Prefix with \u. Example: char letterA = '\u0041'; - A number value can also be assigned to character. Example: char letterB = 66; Numeric value can be from 0 to 65535; - Escape code can be used to represent a character that cannot be typed as literal. Example: char newLine = '\n'; #### Puzzles ``` int eight = 010; int nine=011; int invalid = 089;//COMPILER ERROR! 8 and 9 are invalid in Octal int sixteen = 0x10; int fifteen = 0XF; int fourteen = 0xe; int x = 23,000; long a = 123456789l; long b = 0x9ABCDEFGHL; long c = 0123456789L; float f = 123.456;//COMPILER ERROR! A double value cannot be assigned to a float. boolean b = true; boolean b=false; boolean b = TRUE;//COMPILATION ERROR boolean b = 0; //COMPILER ERROR. This is not C Language char ch = a; char a = 97; char ch1 = 66000; //COMPILER ERROR! ``` ### Tip - Assignment Operator Assignment operator evaluates the expression on the right hand side and copies the value into the variable on the left hand side. #### Basic Examples ``` int value = 35;//35 is copied into 35 int squareOfValue = value * value;//value * value = 35 * 35 is stored into squareOfValue int twiceOfValue = value * 2; ``` #### Puzzles ``` int a1 = 5; int b1 = 6; b1 = a1; // value of a1 is copied into b1 a1 = 10; // If we change a1 or b1 after this, it would not change the other variable.. b1 will remain 6 Actor actor1 = new Actor(); actor1.setName("Actor1"); //This creates new reference variable actor1 of type Actor new Actor() on the heap assigns the new Actor on the heap to reference variable Actor actor2 = actor1; actor2.setName("Actor2"); System.out.println(actor1.getName());//Actor2 ``` ### Casting - Implicit and Explicit Casting is used when we want to convert one data type to another. - A literal integer is by default int. Operation involving int-sized or less always result in int. - Floating point literals are by default double #### Implicit Casting - Implicit Casting is done directly by the compiler. - Example : Widening Conversions i.e. storing smaller values in larger variable types. ``` byte b = 10; //byte b = (int) 10; Example below compiles because compiler introduces an implicit cast. short n1 = 5; short n2 = 6; //short sum = n1 + n2;//COMPILER ERROR short sum = (short)(n1 + n2);//Needs an explicit cast byte b = 5; b += 5; //Compiles because of implicit conversion int value = 100; long number = value; //Implicit Casting float f = 100; //Implicit Casting ``` #### Explicit Casting - Explicit Casting needs to be specified by programmer in code. - Example: Narrowing Conversions. Storing larger values into smaller variable types; - Explicit casting would cause truncation of value if the value stored is greater than the size of the variable. ``` long number1 = 25678; int number2 = (int)number1;//Explicit Casting //int x = 35.35;//COMPILER ERROR int x = (int)35.35;//Explicit Casting int bigValue = 280; byte small = (byte) bigValue; System.out.println(small);//output 24. Only 8 bits remain. //float avg = 36.01;//COMPILER ERROR. Default Double float avg = (float) 36.01;//Explicit Casting float avg1 = 36.01f; float avg2 = 36.01F; //f or F is fine //byte large = 128; //Literal value bigger than range of variable type causes compilation error byte large = (byte) 128;//Causes Truncation! ``` #### Compound Assignment Operators - Examples : +=, -=, *= ``` int a = 5; a += 5; //similar to a = a + 5; a *= 10;//similar to a = a * 10; a -= 5;//similar to a = a - 5; a /= 5;//similar to a = a / 5; ``` ### Other Operators #### Remainder(%) Operator - Remainder when one number is divided by another. ``` System.out.println(10 % 4);//2 System.out.println(15 % 4);//3 ``` #### Conditional Operator - Conditional Operator is a Ternary Operator (3 Operands) - syntax : ```booleanCondition ? ResultIfTrue: ResultIfFalse;``` ``` int age = 18; System.out.println( age >= 18 ? "Can Vote": "Cannot Vote");//Can Vote age = 15; System.out.println( age >= 18 ? "Can Vote": "Cannot Vote");//Cannot Vote ``` ### Passing Variables to Methods - All variables , primitives and references , in Java, are passed to functions using copy-of-variable-value. #### Passing Variables to Methods : Example - Passing a primitive variable and modifying the value in a method - Passing a reference variable and modifying the value in a method #### Returning a Value From Method - null is a valid return value for an object. - You can return andy type that can be implicitly coverted to return type. - You cannot return anything from a void method. ### Types of Variables - Different Types of Variables: Static, Member (or instance), Local, Block #### Instance Variables - Declared inside a class outside any method. - Each instance of the class would have its own values. - Also called member value, field or property. #### Local Variables - Variables declared in a method - Local Variables can only be marked with final modifier - If the name of a Local Variable is same as the name of an instance variable, it results in shadowing. #### Member Variables - Defined at class level and without keyword static. #### Static Variable - Defined at class level and using keyword static. #### Member Variable and Static Variable - Member Variables can be accessed only through object references. - Static Variables can be accessed through a. Class Name and b. Object Reference. It is NOT recommended to use object reference to refer to static variables. #### Example Static and Member Variables ``` public class StaticAndMemberVariables { public static void main(String[] args) { Actor actor1 = new Actor(); actor1.name = "ACTOR1"; //Actor.name //Compiler Error //Below statement can be written as actor1.count++ //But NOT recommended. Actor.count++; Actor actor2 = new Actor(); actor2.name = "ACTOR2"; //Below statement can be written as actor2.count++ //But NOT recommended. Actor.count++; System.out.println(actor1.name);//ACTOR1 System.out.println(actor2.name);//ACTOR2 //Next 3 statements refer to same variable System.out.println(actor1.count);//2 System.out.println(actor2.count);//2 System.out.println(Actor.count);//2 } } class Actor { //RULE 1: Member Variables can be accessed //only through object references String name; //RULE 2:Static Variables can be accessed //through a.Class Name and b.Object Reference //It is NOT recommended to use object reference //to refer to static variables. static int count; } ``` ### Scope of a Variable - Scope of a variable defines where (which part of code) a variable can be accessed. #### Important Rules - Static Variable can be used anywhere in the class. - Member Variable can be used in any non-static method. - Local Variable can be used only in the method where it is declared. - Block Variable can be used only in the block (code between { and }) where it is declared. #### Variable Scope Examples Below code shows all these Rules in action: ``` public class VariablesExample { //RULE 1:Static Variable can be used anywhere in the class. static int staticVariable; //RULE 2:Member Variable can be used in any non-static method. int memberVariable; void method1() { //RULE 3: method1LocalVariable can be used only in method1. int method1LocalVariable; memberVariable = 5;//RULE 2 staticVariable = 5;//RULE 1 //Some Code { //RULE 4:blockVariable can be used only in this block. int blockVariable; //Some Code } //blockVariable = 5;//COMPILER ERROR - RULE 4 } void method2() { //method1LocalVariable = 5; //COMPILER ERROR - RULE3 } static void staticMethod() { staticVariable = 5;//RULE 1 //memberVariable = 5; //COMPILER ERROR - RULE 2 } } ``` #### Scope Example 1 - staticVariable is declared using keyword static. - It is available in the instance method method1 and static method named staticMethod. #### Scope Example 2 - memberVariable is declared directly in the class and does NOT use keyword static. So, it is an instance variable. - It is available in the instance method method1 but not accessible in the static method named staticMethod. #### Scope Example 3 - method1LocalVariable is declared in the method method1. So, it is a local variable. - It is available in the instance method method1 but available in any other instance or static methods. #### Scope Example 4 - blockVariable is declared in a block in method1. So, it is a block variable. - It is available only in the block where it is defined. - It is not accessible any where out side the block , even in the same method. ### Variable Initialization - Initialization defines the default value assigned to a variable if it is not initialized. #### Important Rules - Member/Static variables are alway initialized with default values. - Default values for numeric types is 0, floating point types is 0.0, boolean is false, char is '\u0000' and for a object reference variable is null. - Local variables are not initialized by default by compiler. - Using a local variable before initialization results in a compilation error. - Assigning a null value is a valid initialization for reference variables. #### Variable Initialization Examples Lets look at an example program to understand all the rules regarding variable initialization. ``` package com.in28minutes.variables; //RULE1:Member/Static variables are alway initialized with //default values.Default values for numeric types is 0, //floating point types is 0.0, boolean is false, //char is '\u0000' and object reference variable is null. //RULE2:Local/block variables are NOT initialized by compiler. //RULE3 :If local variables are used before initialization, //it would result in Compilation Error public class VariableInitialization { public static void main(String[] args) { Player player = new Player(); //score is an int member variable - default 0 System.out.println(player.score);//0 - RULE1 //name is a member reference variable - default null System.out.println(player.name);//null - RULE1 int local; //not initialized //System.out.println(local);//COMPILER ERROR! RULE3 String value1;//not initialized //System.out.println(value1);//COMPILER ERROR! RULE3 String value2 = null;//initialized System.out.println(value2);//null - NO PROBLEM. } } class Player{ String name; int score; } ``` #### Initialization Example 1 - player is an instance of the class Player. It contains member variables named name and score. - All member variables are initialized by default. Since name refers to a String i.e a reference variable it is initialized to null. score is an int variable and hence initialized to 0. #### Initialization Example 2 - local is a local variable defined in the main method. - An attempt to access a local variable without initialization would result in a compilation error. - Same is the case with value1 which is a String local variable. - If null is assigned to a reference variable, reference variable is considered to be assigned. ### Wrapper Classes - [Example 1](src/main/java/com/in28minutes/java/wrapper/WrapperExamples.java) - A wrapper class wraps (encloses) around a data type and gives it an object appearance - Wrapper: Boolean,Byte,Character,Double,Float,Integer,Long,Short - Primitive: boolean,byte,char ,double, float, int , long,short - Examples of creating wrapper classes are listed below. - Integer number = new Integer(55);//int; - Integer number2 = new Integer("55");//String - Float number3 = new Float(55.0);//double argument - Float number4 = new Float(55.0f);//float argument - Float number5 = new Float("55.0f");//String - Character c1 = new Character('C');//Only char constructor - Boolean b = new Boolean(true); - Reasons - null is a possible value - use it in a Collection - Object like creation from other types.. like String - A primitive wrapper class in the Java programming language is one of eight classes provided in the java.lang package to provide object methods for the eight primitive types. All of the primitive wrapper classes in Java are immutable. Wrapper classes are final and immutable. #### Creating Wrapper Classes ``` Integer number = new Integer(55);//int Integer number2 = new Integer("55");//String Float number3 = new Float(55.0);//double argument Float number4 = new Float(55.0f);//float argument Float number5 = new Float("55.0f");//String Character c1 = new Character('C');//Only char constructor //Character c2 = new Character(124);//COMPILER ERROR Boolean b = new Boolean(true); //"true" "True" "tRUe" - all String Values give True //Anything else gives false Boolean b1 = new Boolean("true");//value stored - true Boolean b2 = new Boolean("True");//value stored - true Boolean b3 = new Boolean("False");//value stored - false Boolean b4 = new Boolean("SomeString");//value stored - false b = false; ``` #### Wrapper Class Utility Methods - A number of utility methods are defined in wrapper classes to create and convert them. #### valueOf Methods Provide another way of creating a Wrapper Object ``` Integer seven = Integer.valueOf("111", 2);//binary 111 is converted to 7 Integer hundred = Integer.valueOf("100");//100 is stored in variable ``` #### xxxValue methods xxxValue methods help in creating primitives ``` Integer integer = Integer.valueOf(57); int primitive = seven.intValue();//57 float primitiveFloat = seven.floatValue();//57.0f Float floatWrapper = Float.valueOf(57.0f); int floatToInt = floatWrapper.intValue();//57 float floatToFloat = floatWrapper.floatValue();//57.0f ``` #### parseXxx methods parseXxx methods are similar to valueOf but they return primitive values ``` int sevenPrimitive = Integer.parseInt("111", 2);//binary 111 is converted to 7 int hundredPrimitive = Integer.parseInt("100");//100 is stored in variable ``` #### static toString method Look at the example of the toString static method below. ``` Integer wrapperEight = new Integer(8); System.out.println(Integer. toString(wrapperEight));//String Output: 8 ``` #### Overloaded static toString method 2nd parameter: radix ``` System.out.println(Integer .toString(wrapperEight, 2));//String Output: 1000 ``` #### static toYyyyString methods. Yyyy can be Hex,Binary,Octal ``` System.out.println(Integer .toHexString(wrapperEight));//String Output:8 System.out.println(Integer .toBinaryString(wrapperEight));//String Output:1000 System.out.println(Integer .toOctalString(wrapperEight));//String Output:10 ``` #### Wrapper Class , Auto Boxing ``` Integer ten = new Integer(10); ten++;//allowed. Java does the work behind the screen for us ``` #### Boxing and new instances - Auto Boxing helps in saving memory by reusing already created Wrapper objects. However wrapper classes created using new are not reused. - Two wrapper objects created using new are not same object. ``` Integer nineA = new Integer(9); Integer nineB = new Integer(9); System.out.println(nineA == nineB);//false System.out.println(nineA.equals(nineB));//true ``` - Two wrapper objects created using boxing are same object. ``` Integer nineC = 9; Integer nineD = 9; System.out.println(nineC == nineD);//true System.out.println(nineC.equals(nineD));//true ``` ### String Class - A String class can store a sequence of characters. String is not a primitive in Java but a Class in its own right. #### Strings are immutable - Value of a String Object once created cannot be modified. Any modification on a String object creates a new String object. ``` String str3 = "value1"; str3.concat("value2"); System.out.println(str3); //value1 ``` Note that the value of str3 is not modified in the above example. The result should be assigned to a new reference variable (or same variable can be reused). ``` String concat = str3.concat("value2"); System.out.println(concat); //value1value2 ``` ## Where are string literals stored in memory? All strings literals are stored in "String constant pool". If compiler finds a String literal,it checks if it exists in the pool. If it exists, it is reused. Following statement creates 1 string object (created on the pool) and 1 reference variable. ``` String str1 = "value"; ``` However, if new operator is used to create string object, the new object is created on the heap. Following piece of code create 2 objects. ``` //1. String Literal "value" - created in the "String constant pool" //2. String Object - created on the heap String str2 = new String("value"); ``` ## String vs StringBuffer vs StringBuilder - Immutability : String - Thread Safety : String(immutable), StringBuffer - Performance : StringBuilder (especially when a number of modifications are made.) - [Example 1](src/main/java/com/in28minutes/java/string/StringBufferBuilderExamples.java) #### String Constant Pool - All strings literals are stored in "String constant pool". If compiler finds a String literal,it checks if it exists in the pool. If it exists, it is reused. - Following statement creates 1 string object (created on the pool) and 1 reference variable. ``` String str1 = "value"; ``` - However, if new operator is used to create string object, the new object is created on the heap. Following piece of code create 2 objects. ``` //1. String Literal "value" - created in the "String constant pool" //2. String Object - created on the heap String str2 = new String("value"); ``` #### String Method Examples String class defines a number of methods to get information about the string content. ``` String str = "abcdefghijk"; ``` ##### Get information from String Following methods help to get information from a String. ``` //char charAt(int paramInt) System.out.println(str.charAt(2)); //prints a char - c System.out.println("ABCDEFGH".length());//8 System.out.println("abcdefghij".toString()); //abcdefghij System.out.println("ABC".equalsIgnoreCase("abc"));//true //Get All characters from index paramInt //String substring(int paramInt) System.out.println("abcdefghij".substring(3)); //cdefghij //All characters from index 3 to 6 System.out.println("abcdefghij".substring(3,7)); //defg ``` #### String Manipulation methods Most important thing to remember is a String object cannot be modified. When any of these methods are called, they return a new String with the modified value. The original String remains unchanged. ``` //String concat(String paramString) System.out.println(str.concat("lmn"));//abcdefghijklmn //String replace(char paramChar1, char paramChar2) System.out.println("012301230123".replace('0', '4'));//412341234123 //String replace(CharSequence paramCharSequence1, CharSequence paramCharSequence2) System.out.println("012301230123".replace("01", "45"));//452345234523 System.out.println("ABCDEFGHIJ".toLowerCase()); //abcdefghij System.out.println("abcdefghij".toUpperCase()); //ABCDEFGHIJ //trim removes leading and trailings spaces System.out.println(" abcd ".trim()); //abcd ``` ### String Concatenation Operator #### Three Rules of String Concatenation - RULE1: Expressions are evaluated from left to right.Except if there are parenthesis. - RULE2: number + number = number - RULE3: number + String = String ``` System.out.println(5 + "Test" + 5); //5Test5 System.out.println(5 + 5 + "Test"); //10Test System.out.println("5" + 5 + "Test"); //55Test System.out.println("5" + "5" + "25"); //5525 System.out.println(5 + 5 + "25"); //1025 System.out.println("" + 5 + 5 + "25"); //5525 System.out.println(5 + (5 + "25")); //5525 System.out.println(5 + 5 + 25); //35 ``` ### Increment and Decrement Operators - Lets learn about the increment and decrement operators in Java. #### Basics of Increment and Decrement Operators Except for a minor difference ++i,i++ is similar to i = i+1 and --i,i-- is similar to i = i-1 ++i is called pre-increment and i++ post increment #### Increment Operators Pre increment statement returns value after increment. Post increment statement returns value before increment ``` int i = 25; int j = ++i;//i is incremented to 26, assigned to j System.out.println(i + " " + j);//26 26 i = 25; j = i++;//i value(25) is assigned to j, then incremented to 26 System.out.println(i + " " + j);//26 25 ``` #### Decrement Operators Decrement Operators are similar to increment operators. ``` i = 25; j = --i;//i is decremented to 24, assigned to j System.out.println(i + " " + j);//24 24 i = 25; j = i--;//i value(25) is assigned to j, then decremented to 24 System.out.println(i + " " + j);//24 25 ``` ### Relational Operators - Relation Operators are used to compare operands. They a always return true or false. List of Relation Operators include <, <=, >, >=, ==, and !=. #### Relation Operators Examples Let's consider a few examples of relational operators. Let's assume a int variable named number with a value 7. ``` int number = 7; ``` #### greater than operator ``` System.out.println(number > 5);//true System.out.println(number > 7);//false ``` #### greater than equal to operator ``` System.out.println(number >= 7);//true ``` #### less than operator ``` System.out.println(number < 9);//true System.out.println(number < 7);//false ``` #### less than equal to operator ``` System.out.println(number <= 7);//true ``` #### is equal to operator ``` System.out.println(number == 7);//true System.out.println(number == 9);//false ``` #### NOT equal to operator ``` System.out.println(number != 9);//true System.out.println(number != 7);//false ``` > single = is assignment operator and == is comparison. Below statement uses =. ``` System.out.println(number = 7);//7 ``` #### == (equals) operator Let's look at how == equals operator works with primitives and reference variables. #### Primitive Variables - Equality for Primitives only compares values ``` int a = 5; int b = 5; ``` Below statement compares if a and b have same value. ``` System.out.println(a == b);//true ``` #### Reference Variables ``` Integer aReference = new Integer(5); Integer bReference = new Integer(5); ``` For reference variables, == compares if they are referring to the same object. ``` System.out.println(aReference == bReference);//false bReference = aReference; //Now both are referring to same object System.out.println(aReference == bReference);//true ``` ### Logical Operators - Logical Operators are &&, ||, |, &, ! and ^. #### Short Circuit And Operator - && - True when both operands are true. ``` System.out.println(true && true);//true System.out.println(true && false);//false System.out.println(false && true);//false System.out.println(false && false);//false ``` #### Short Circuit Or Operator - || True when atleast one of operands are true. ``` System.out.println(true || true);//true System.out.println(true || false);//true System.out.println(false || true);//true System.out.println(false || false);//false ``` > Certification Tip : Logical Operators work with boolean values but not numbers. ``` //System.out.println(5 || 6);//COMPILER ERROR ``` #### Short circuit operators are Lazy - They stop execution the moment result is clear. - For &&, if first expression is false,result is false. - For ||, if first expression is true, the result is true. - In above 2 situations, second expressions are not executed. ``` int i = 10; System.out.println(true || ++i==11);//true System.out.println(false && ++i==11);//false System.out.println(i);//i remains 10, as ++i expressions are not executed. ``` #### Operator & and | - Logical Operators &, | are similar to &&, || except that they don't short ciruit. - They execute the second expression even if the result is decided. > Certification Tip : While & and | are very rarely used, it is important to understand them from a certification perspective. ``` int j = 10; System.out.println(true | ++j==11);//true System.out.println(false & ++j==12);//false System.out.println(j);//j becomes 12, as both ++j expressions are executed ``` #### Operator exclusive-OR (^) - Result is true only if one of the operands is true. ``` System.out.println(true ^ false);//true System.out.println(false ^ true);//true System.out.println(true ^ true);//false System.out.println(false ^ false);//false ``` #### Not Operator (!) Result is the negation of the expression. ``` System.out.println(!false);//true System.out.println(!true);//false ``` ### Arrays - TODO : Why do we need arrays? ``` //Declaring an Array int[] marks; // Creating an array marks = new int[5]; // 5 is size of array int marks2[] = new int[5];//Declaring and creating an array in same line. System.out.println(marks2[0]);//New Arrays are always initialized with default values - 0 //Index of elements in an array runs from 0 to length - 1 marks[0] = 25; marks[1] = 30; marks[2] = 50; marks[3] = 10; marks[4] = 5; System.out.println(marks[2]);//Printing a value from array //Printing a 1D Array int marks5[] = { 25, 30, 50, 10, 5 }; System.out.println(marks5); //[I@6db3f829 System.out.println( Arrays.toString(marks5));//[25, 30, 50, 10, 5] int length = marks.length;//Length of an array: Property length //Enhanced For Loop for (int mark: marks) { System.out.println(mark); } //Fill array with a value Arrays.fill(marks, 100); //All array values will be 100 //String Arrays String[] daysOfWeek = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; ``` #### 2D Arrays Best way to visualize a 2D array is as an array of arrays. ``` int[][] matrix = { { 1, 2, 3 }, { 4, 5, 6 } }; int[][] matrixA = new int[5][6]; //Accessing elements from 2D array: System.out.println(matrix[0][0]); //1 System.out.println(matrix[1][2]); //6 //Looping a 2D array for (int[] array: matrix) { for (int number: array) { System.out.println(number); } } // Printing a 2D Array int[][] matrix3 = { { 1, 2, 3 }, { 4, 5, 6 } }; System.out.println(matrix3); //[[I@1d5a0305 System.out.println( Arrays.toString(matrix3)); //[[I@6db3f829, [I@42698403] System.out.println(Arrays.deepToString(matrix3)); //[[1, 2, 3], [4, 5, 6]] System.out.println(matrix3[0]);//[I@86c347 - matrix3[0] is a 1D Array System.out.println(Arrays.toString(matrix3[0]));//[1, 2, 3] ``` #### Other Array Operations ``` //Comparing Arrays int[] numbers1 = { 1, 2, 3 }; int[] numbers2 = { 4, 5, 6 }; System.out.println(Arrays .equals(numbers1, numbers2)); //false int[] numbers3 = { 1, 2, 3 }; System.out.println(Arrays .equals(numbers1, numbers3)); //true // Sorting an Array int rollNos[] = { 12, 5, 7, 9 }; Arrays.sort(rollNos); System.out.println(Arrays.toString(rollNos));//[5, 7, 9, 12] ``` #### Array of Objects ``` Person[] persons = new Person[3]; //By default, an array of 3 reference variables is created. //The person objects are not created System.out.println(persons[0]);//null //Let's create the new objects persons[0] = new Person(); persons[1] = new Person(); persons[2] = new Person(); //Creating and initializing person array in one statement Person[] personsAgain = { new Person(),new Person(),new Person()}; //Another example Person[][] persons2D = { { new Person(),new Person(),new Person()}, { new Person(),new Person()} }; ``` #### Array Certification Tips and Puzzles ``` //You can Declare, Create and Initialize Array on same line. int marks3[] = { 25, 30, 50, 10, 5 }; //Leaving additional comma is not a problem. (note that comma after 5) int marks4[] = { 25, 30, 50, 10, 5, }; int marks[]; //Not Readable int[] runs; //Not Readable //int values[5];//Compilation Error!Declaration of an Array should not include size. //marks = new int[];//COMPILER ERROR! Size of an array is mandatory to create an array. //Declaring 2D Array Examples: int[][] matrix1; //Recommended int[] matrix2[]; //Legal but not readable. Avoid. //Access 10th element when array has only length 5 //Runtime Exception: ArrayIndexOutOfBoundsException //System.out.println(marks[10]); //Array can contain only values of same type. //COMPILE ERROR!! //int marks4[] = {10,15.0}; //10 is int 15.0 is float //Cross assigment of primitive arrays is ILLEGAL int[] ints = new int[5]; short[] shorts = new short[5]; //ints = shorts;//COMPILER ERROR //ints = (int[])shorts;//COMPILER ERROR //The first dimension of a 2D array is mandatory matrixA = new int[3][];//FINE //matrixA = new int[][5];//COMPILER ERROR //matrixA = new int[][];//COMPILER ERROR //Each row in a 2D Array can have a different size. This is called a Ragged Array. matrixA = new int[3][];//FINE matrixA[0] = new int[3]; matrixA[0] = new int[4]; matrixA[0] = new int[5]; ``` ### If Else Condition - Conditionally execute code! - Code inside If is executed only if the condition is true. // Basic Example ``` if(true){ System.out.println("Will be printed"); } if(false){ System.out.println("Will NOT be printed");//Not executed } //Example 1 int x = 5; if(x==5){ System.out.println("x is 5");//executed since x==5 is true } //Example 2 x = 6; if(x==5){ System.out.println("x is 5");//Not executed since x==5 is false } //Example 3 int y = 10; if(y==10){ System.out.println("Y is 10");//executed-condn y==10 is true } else { System.out.println("Y is Not 10"); } //Example 4 y = 11; if(y==10){ System.out.println("Y is 10");//NOT executed } else { System.out.println("Y is Not 10");//executed } //Example 5 int z = 15; //Only one condition is executed. Rest of the conditions are skipped. if(z==10){ System.out.println("Z is 10");//NOT executed } else if(z==12){ System.out.println("Z is 12");//NOT executed } else if(z==15){ System.out.println("Z is 15");//executed. } else { System.out.println("Z is Something Else.");//NOT executed } z = 18; if(z==10){ System.out.println("Z is 10");//NOT executed } else if(z==12){ System.out.println("Z is 12");//NOT executed } else if(z==15){ System.out.println("Z is 15");//NOT executed } else { System.out.println("Z is Something Else.");//executed } //If else Example: without Blocks int number = 5; if(number < 0) number = number + 10; //Not executed number++; //This statement is not part of if. Executed. System.out.println(number);//prints 6 ``` #### If else Puzzles ``` //Puzzle 1 int k = 15; if (k > 20) { System.out.println(1); } else if (k > 10) { System.out.println(2); } else if (k < 20) { System.out.println(3); } else { System.out.println(4); } //Output is 2. //Once a condition in nested-if-else is true the rest of the code is not executed. //Puzzle 2 int l = 15; if(l<20) System.out.println("l<20"); if(l>20) System.out.println("l>20"); else System.out.println("Who am I?"); ``` //Output is "l<20" followed by "Who am I?" on next line. //else belong to the last if before it unless brackets ({}) are used. ``` Puzzle 3 ``` int m = 15; if(m>20) if(m<20) System.out.println("m>20"); else System.out.println("Who am I?"); //Nothing is printed to output. //Code above is similar to the code snippet shown below if(m>20) {//Condn is false. So, code in if is not executed if(m<20) System.out.println("m>20"); else System.out.println("Who am I?"); } ``` Puzzles Continued ``` //Puzzle 4 int x1 = 0; //Condition in if should always be boolean //if(x1) {} //COMPILER ERROR //if(x1=0) {}//COMPILER ERROR. Using = instead of == //If else condition should be boolean //Puzzle 5 boolean isTrue = false; if(isTrue==true){ System.out.println("TRUE TRUE");//Will not be printed } if(isTrue=true){ System.out.println("TRUE");//Will be printed. } //Condition is isTrue=true. This is assignment. Returns true. So, code in if is executed. ``` ### Switch Statement - Choose between a set of options. - From Java 6, String can be used as the switch argument. ``` //Example 1 int number = 2; switch (number) { case 1: System.out.println(1); break; case 2: System.out.println(2);//PRINTED break; case 3: System.out.println(3); break; default: System.out.println("Default"); break; } // Output of above example is 2.The case which is matched is executed. ``` Important Tips - There is a break statement in every case. If there is no break statement, switch continues to execute other cases. - There is a case named default. If none of the cases match default case is executed. ``` //Switch Statement Example 2 , No Breaks number = 2; switch (number) { case 1: System.out.println(1); case 2: System.out.println(2); case 3: System.out.println(3); default: System.out.println("Default"); } ``` Output of above switch ``` 2 3 Default ``` Since there is no break after case 2, execution falls through to case 3. There is no break in case 3 as well. So, execution falls through to default. > Code in switch is executed from a matching case until a break or end of switch statement is encountered. Switch Statement Example 3 , Few Break's ``` number = 2; switch (number) { case 1: System.out.println(1); break; case 2: case 3: System.out.println("Number is 2 or 3"); break; default: System.out.println("Default"); break; } ``` Program Output ``` Number is 2 or 3. ``` Case 2 matches. Since there is no code in case 2, execution falls through to case 3, executes the println. Break statement takes execution out of the switch. Switch Statement Example 4 , Let's Default - default is executed if none of the case's match. ``` number = 10; switch (number) { case 1: System.out.println(1); break; case 2: System.out.println(2); break; case 3: System.out.println(3); break; default: System.out.println("Default"); break; } ``` Code Output ``` Default ``` Switch Statement Example 5 - Default need not be Last ``` number = 10; switch (number) { default: System.out.println("Default"); break; case 1: System.out.println(1); break; case 2: System.out.println(2); break; case 3: System.out.println(3); break; } ``` Output ``` Default ``` #### Switch statement Example 6 Switch can be used only with char, byte, short, int, String or enum ``` long l = 15; /*switch(l){//COMPILER ERROR. Not allowed. }*/ Case value should be a compile time constant. ``` number = 10; switch (number) { //case number>5://COMPILER ERROR. Cannot have a condition //case number://COMPILER ERROR. Should be constant. } ``` ## Loops A loop is used to run same code again and again. ### While Loop ``` int count = 0; while(count < 5){//while this condn is true, loop is executed. System.out.print(count); count++; } //Output - 01234 ``` While loop Example 2 ``` count = 5; while(count < 5){//condn is false. So, code in while is not executed. System.out.print(count); count++; }//Nothing is printed to output ``` ### Do While Loop - The difference between a while and a do while is that the code in do while is executed at least once. - In a do while loop, condition check occurs after the code in loop is executed once. Do While loop Example 1 ``` int count = 0; do{ System.out.print(count); count++; }while(count < 5);//while this condn is true, loop is executed. //output is 01234 ``` Do While loop Example 2 ``` count = 5; do{ System.out.print(count); count++; }while(count < 5); //output is 5 ``` ### For Loop For loop is used to loop code specified number of times. For Loop Example 1 ``` for (int i = 0; i < 10; i++) { System.out.print(i); } //Output - 0123456789 ``` Syntax - For loop statement has 3 parts - Initialization => int i=0. Initialization happens the first time a for loop is run. - Condition => i<10. Condition is checked every time before the loop is executed. - Operation (Increment or Decrement usually) => i++. Operation is invoked at the start of every loop (except for first time). For Loop Example 2: There can be multiple statements in Initialization or Operation separated by commas ``` for (int i = 0,j = 0; i < 10; i++,j--) { System.out.print(j); } //Output - 0123456789 ``` #### Enhanced For Loop Enhanced for loop can be used to loop around array's or List's. ``` int[] numbers = {1,2,3,4,5}; for(int number:numbers){ System.out.print(number); } //Output - 12345 ``` Any of 3 parts in a for loop can be empty. ``` for (;;) { System.out.print("I will be looping for ever.."); } //Infinite loop => Loop executes until the program is terminated. ``` ### Break Statement Break statement breaks out of a loop Example 1 ``` for (int i = 0; i < 10; i++) { System.out.print(i); if (i == 5) { break; } } //Output - 012345 //Even though the for loop runs from 0 to 10, execution stops at i==5 because of the break statement. ÒBreak statementÓ stops the execution of the loop and takes execution to the first statement after the loop. ``` Break can be used in a while also. ``` int i = 0; while (i < 10) { System.out.print(i); if (i == 5) { break; } i++; } //Output - 012345 ``` Break statement takes execution out of inner most loop. ```java for (int j = 0; j < 2; j++) { for (int k = 0; k < 10; k++) { System.out.print(j + "" + k); if (k == 5) { break;//Takes out of loop using k } } } //Output - 000102030405101112131415 //Each time the value of k is 5 the break statement is executed. //The break statement takes execution out of the k loop and proceeds to the next value of j. ``` Labels can be used to label and refer to specific for loop in a nested for loop. ``` outer: for (int j = 0; j < 2; j++) { for (int k = 0; k < 10; k++) { System.out.print(j + "" + k); if (k == 5) { break outer;//Takes out of loop using j } } } //Output - 000102030405 ``` ### Continue Statement - Continue statement skips rest of the statements in the loop and starts next iteration ``` for (int i = 0; i < 10; i++) { if (i == 5) { continue; } System.out.print(i); } //Output => 012346789 //Note that the output does not contain 5. //When i==5 continue is executed. Continue skips rest of the code and goes to next loop iteration. //So, the print statement is not executed when i==5. ``` Continue can be used in a while also ``` int i = 0; while (i < 10) { i++; if (i == 5) { continue; } System.out.print(i); } //Output - 1234678910 ``` Continue statement takes execution to next iteration of inner most loop. ``` for (int j = 0; j < 2; j++) { for (int k = 0; k < 10; k++) { if (k == 5) { continue;//skips to next iteration of k loop } System.out.print(j + "" + k); } } //Output - 000102030406070809101112131416171819 //When k==5 the print statement in the loop is skipped due to continue. //So 05 and 05 are not printed to the console. ``` Label Example ``` outer: for (int j = 0; j < 2; j++) { for (int k = 0; k < 10; k++) { if (k == 5) { continue outer;//skips to next iteration of j loop } System.out.print(j + "" + k); } } //Output - 00010203041011121314 //When k==5 is true, continue outer is called. //So, when value of k is 5, the loop skips to the next iteration of j. ``` ### Enum - Enum allows specifying a list of valid values (or allowed values) for a Type. #### Enum Declaration Consider the example below. It declares an enum Season with 4 possible values. ``` enum Season { WINTER, SPRING, SUMMER, FALL }; ``` #### Enum Example 1 ``` //Enum can be declared outside a class enum SeasonOutsideClass { WINTER, SPRING, SUMMER, FALL }; public class Enum { // Enum can be declared inside a class enum Season { WINTER, SPRING, SUMMER, FALL }; public static void main(String[] args) { /* * //Uncommenting gives compilation error //enum cannot be created in a *
ethod enum InsideMethodNotAllowed { WINTER, SPRING, SUMMER, FALL }; */ // Converting String to Enum Season season = Season.valueOf("FALL"); // Converting Enum to String System.out.println(season.name());// FALL // Default ordinals of enum // By default java assigns ordinals in order System.out.println(Season.WINTER.ordinal());// 0 System.out.println(Season.SPRING.ordinal());// 1 System.out.println(Season.SUMMER.ordinal());// 2 System.out.println(Season.FALL.ordinal());// 3 // Looping an enum => We use method values for (Season season1 : Season.values()) { System.out.println(season1.name()); // WINTER SPRING SUMMER FALL (separate lines) } // Comparing two Enums Season season1 = Season.FALL; Season season2 = Season.FALL; System.out.println(season1 == season2);// true System.out.println(season1.equals(season2));// true } } ``` Enum Rules - Enums can be declared in a separate class(SeasonOutsideClass) or as member of a class(Season). Enums cannot be declared in a method. Conversion of Enum : Function valueOf(String) is used to convert a string to enum. ``` //Converting String to Enum Season season = Season.valueOf("FALL"); ``` Function name() is used to find String value of an enum. ``` //Converting Enum to String System.out.println(season.name());//FALL ``` Java assigns default ordinals to an enum in order. However, it is not recommended to use ordinals to perform logic. ``` //Default ordinals of enum // By default java assigns ordinals in order System.out.println(Season.WINTER.ordinal());//0 System.out.println(Season.SPRING.ordinal());//1 System.out.println(Season.SUMMER.ordinal());//2 System.out.println(Season.FALL.ordinal());//3 ``` Looping around an Enum - List of values allowed for an Enum can be obtained by invoking the function values(). ``` //Looping an enum => We use method values for (Season season1: Season.values()) { System.out.println(season1.name()); //WINTER SPRING SUMMER FALL (separate lines) } ``` Comparing two Enums ``` //Comparing two Enums Season season1 = Season.FALL; Season season2 = Season.FALL; System.out.println(season1 == season2);//true System.out.println(season1.equals(season2));//true ``` #### Enum Example 2 ``` package com.in28minutes.java.beginners.concept.examples.enums; public class EnumAdvanced { // Enum with a variable,method and constructor enum SeasonCustomized { WINTER(1), SPRING(2), SUMMER(3), FALL(4); // variable private int code; // method public int getCode() { return code; } // Constructor-only private or (default) // modifiers are allowed SeasonCustomized(int code) { this.code = code; } // Getting value of enum from code public static SeasonCustomized valueOf(int code) { for (SeasonCustomized season : SeasonCustomized.values()) { if (season.getCode() == code) return season; } throw new RuntimeException("value not found");// Just for kicks } // Using switch statement on an enum public int getExpectedMaxTemperature() { switch (this) { case WINTER: return 5; case SPRING: case FALL: return 10; case SUMMER: return 20; } return -1;// Dummy since Java does not recognize this is possible :) } }; public static void main(String[] args) { SeasonCustomized season = SeasonCustomized.WINTER; /* * //Enum constructor cannot be invoked directly //Below line would * cause COMPILER ERROR SeasonCustomized season2 = new * SeasonCustomized(1); */ System.out.println(season.getCode());// 1 System.out.println(season.getExpectedMaxTemperature());// 5 System.out.println(SeasonCustomized.valueOf(4));// FALL } } ``` #### More Enum Basics - Enums can contain variables, methods, constructors. In example 2, we created a local variable called code with a getter. - We also created a constructor with code as a parameter. ``` //variable private int code; //method public int getCode() { return code; } //Constructor-only private or (default) //modifiers are allowed SeasonCustomized(int code) { this.code = code; } ``` Each of the Season Type's is created by assigning a value for code. ``` WINTER(1), SPRING(2), SUMMER(3), FALL(4); ``` Enum constructors can only be (default) or (private) access. Enum constructors cannot be directly invoked. ``` /*//Enum constructor cannot be invoked directly //Below line would cause COMPILER ERROR SeasonCustomized season2 = new SeasonCustomized(1); */ ``` Example below shows how we can use a switch around an enum. ``` // Using switch statement on an enum public int getExpectedMaxTemperature() { switch (this) { case WINTER: return 5; case SPRING: case FALL: return 10; case SUMMER: return 20; } return -1; } ``` #### Enum Example 3 ``` package com.in28minutes.java.beginners.concept.examples.enums; public class EnumAdvanced2 { // Enum with a variable,method and constructor enum SeasonCustomized { WINTER(1) { public int getExpectedMaxTemperature() { return 5; } }, SPRING(2), SUMMER(3) { public int getExpectedMaxTemperature() { return 20; } }, FALL(4); // variable private int code; // method public int getCode() { return code; } // Constructor-only private or (default) // modifiers are allowed SeasonCustomized(int code) { this.code = code; } public int getExpectedMaxTemperature() { return 10; } }; public static void main(String[] args) { SeasonCustomized season = SeasonCustomized.WINTER; System.out.println(season.getExpectedMaxTemperature());// 5 System.out.println(SeasonCustomized.FALL.getExpectedMaxTemperature());// 10 } } ``` Enum Constant Class - In the example above, take a look at how the Winter Type is declared: It provides an overriding implementation for the getExpectedMaxTemperature method already declared in the Enum. This feature in an Enum is called a Constant Class. ``` WINTER(1) { public int getExpectedMaxTemperature() { return 5; } } ``` ### Inheritance Inheritance allows extending a functionality of a class and also promotes reuse of existing code. #### Every Class extends Object class - Every class in Java is a sub class of the class Object. - When we create a class in Java, we inherit all the methods and properties of Object class. ``` String str = "Testing"; System.out.println(str.toString()); System.out.println(str.hashCode()); System.out.println(str.clone()); if(str instanceof Object){ System.out.println("I extend Object");//Will be printed } ``` Create a class Actor ``` public class Actor { public void act(){ System.out.println("Act"); }; } ``` We can extend this class by using the keyword ```extends```. ```Hero class extends Actor``` ``` //IS-A relationship. Hero is-a Actor public class Hero extends Actor { public void fight(){ System.out.println("fight"); }; } ``` Since Hero extends Animal, the methods defined in Animal are also available through an instance of Hero class. ``` Hero hero = new Hero(); //act method inherited from Actor hero.act();//Act hero.fight();//fight ``` Let's look at another class extending Actor class - Comedian. ``` //IS-A relationship. Comedian is-a Actor public class Comedian extends Actor { public void performComedy(){ System.out.println("Comedy"); }; } ``` Methods in Animal class can be executed from an instance of Comedian class. ``` Comedian comedian = new Comedian(); //act method inherited from Actor comedian.act();//Act comedian.performComedy();//Comedy ``` #### Super class reference variable can hold an object of sub class ``` Actor actor1 = new Comedian(); Actor actor2 = new Hero(); ``` Object is super class of all classes. So, an Object reference variable can hold an instance of any class. ``` //Object is super class of all java classes Object object = new Hero(); ``` #### Inheritance: IS-A Relationship We should use inheritance only when there is an IS-A relationship between classes. For example, Comedian IS-A Actor, Hero IS-A Actor are both true. So, inheritance is correct relationship between classes. - Comedian is called a Sub Class. Actor is Super Class. Multiple Inheritance results in a number of complexities. Java does not support Multiple Inheritance. ``` class Dog extends Animal, Pet { //COMPILER ERROR } ``` We can create an inheritance chain. ``` class Pet extends Animal { } class Dog extends Pet { } ``` #### Inheritance and Polymorphism Polymorphism is defined as "Same Code" having "Different Behavior". Example ``` public class Animal { public String shout() { return "Don't Know!"; } } class Cat extends Animal { public String shout() { return "Meow Meow"; } } class Dog extends Animal { public String shout() { return "BOW BOW"; } public void run(){ } } ``` Execution ``` Animal animal1 = new Animal(); System.out.println(animal1.shout()); //Don't Know! Animal animal2 = new Dog();//Animal reference used to store Dog object //Reference variable type => Animal //Object referred to => Dog //Dog's bark method is called. System.out.println(animal2.shout()); //BOW BOW //Cannot invoke sub class method with super class reference variable. //animal2.run();//COMPILE ERROR ``` ### Puzzle and Tips - instanceof Operator in depth instanceof operator checks if an object is of a particular type. ``` class SuperClass { }; class SubClass extends SuperClass { }; interface Interface { }; class SuperClassImplementingInteface implements Interface { }; class SubClass2 extends SuperClassImplementingInteface { }; class SomeOtherClass { }; SubClass subClass = new SubClass(); Object subClassObj = new SubClass(); SubClass2 subClass2 = new SubClass2(); SomeOtherClass someOtherClass = new SomeOtherClass(); //We can run instanceof operator on the different instances created earlier. System.out.println(subClass instanceof SubClass);//true System.out.println(subClass instanceof SuperClass);//true System.out.println(subClassObj instanceof SuperClass);//true System.out.println(subClass2 instanceof SuperClassImplementingInteface);//true //instanceof can be used with interfaces as well. //Since Super Class implements the interface, below code prints true. System.out.println(subClass2 instanceof Interface);//true //If the type compared is unrelated to the object, a compilation error occurs. //System.out.println(subClass // instanceof SomeOtherClass);//Compiler Error //Object referred by subClassObj(SubClass)- NOT of type SomeOtherClass System.out.println(subClassObj instanceof SomeOtherClass);//false ``` ### Class, Object, State and Behavior - In this tutorial, lets look at a few important object oriented concepts. #### Class, Object, State and Behavior Example ``` package com.in28minutes; public class CricketScorer { //Instance Variables - constitute the state of an object private int score; //Behavior - all the methods that are part of the class //An object of this type has behavior based on the //methods four, six and getScore public void four(){ score = score + 4; } public void six(){ score = score + 6; } public int getScore() { return score; } public static void main(String[] args) { CricketScorer scorer = new CricketScorer(); scorer.six(); //State of scorer is (score => 6) scorer.four(); //State of scorer is (score => 10) System.out.println(scorer.getScore()); } } ``` #### Class A class is a Template. - In above example, class CricketScorer is the template for creating multiple objects. A class defines state and behavior that an object can exhibit. #### Object An instance of a class. - In the above example, we create an object using new CricketScorer(). - The reference of the created object is stored in scorer variable. - We can create multiple objects of the same class. #### State State represents the values assigned to instance variables of an object at a specific time. Consider following code snippets from the above example. - The value in score variable is initially 0. - It changes to 6 and then 10. State of an object might change with time. ``` scorer.six(); //State of scorer is (score => 6) scorer.four(); //State of scorer is (score => 10) ``` #### Behavior Behaviour of an object represents the different methods that are supported by it. - Above example the behavior supported is six(), four() and getScore(). ### toString method toString() method in Java is used to print the content of an object. Example ``` class Animal { public Animal(String name, String type) { this.name = name; this.type = type; } String name; String type; } Animal animal = new Animal("Tommy", "Dog"); //Output does not show the content of animal (what name? and what type?). System.out.println(animal);//com.in28minutes.Animal@f7e6a96 To show the content of the animal object, we can override the default implementation of toString method provided by Object class. //Adding toString to Animal class class Animal { public Animal(String name, String type) { this.name = name; this.type = type; } String name; String type; public String toString() { return "Animal [name=" + name + ", type=" + type + "]"; } } Animal animal = new Animal("Tommy","Dog"); //Output now shows the content of the animal object. System.out.println(animal);//Animal [name=Tommy, type=Dog] ``` ### equals method equals method is used to compare if two objects are having the same content. - Default implementation of equals method is defined in Object class. The implementation is similar to == operator. - By default, two object references are equal only if they are pointing to the same object. - However, we can override equals method and provide a custom implementation to compare the contents for an object. Example ``` class Client { private int id; public Client(int id) { this.id = id; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; return result; } } // == comparison operator checks if the object references are pointing to the same object. // It does NOT look at the content of the object. Client client1 = new Client(25); Client client2 = new Client(25); Client client3 = client1; //client1 and client2 are pointing to different client objects. System.out.println(client1 == client2);//false //client3 and client1 refer to the same client objects. System.out.println(client1 == client3);//true //similar output to == System.out.println(client1.equals(client2));//false System.out.println(client1.equals(client3));//true //overriding equals method class Client { private int id; public Client(int id) { this.id = id; } @Override public boolean equals(Object obj) { Client other = (Client) obj; if (id != other.id) return false; return true; } } ``` Signature of the equals method is "public boolean equals(Object obj) ". - Note that "public boolean equals(Client client)" will not override the equals method defined in Object. Parameter should be of type Object. - The implementation of equals method checks if the id's of both objects are equal. If so, it returns true. - Note that this is a basic implementation of equals. Example ``` Client client1 = new Client(25); Client client2 = new Client(25); Client client3 = client1; //both id's are 25 System.out.println(client1.equals(client2));//true //both id's are 25 System.out.println(client1.equals(client3));//true ``` Any equals implementation should satisfy these properties: - Reflexive. For any reference value x, x.equals(x) returns true. - Symmetric. For any reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true. - Transitive. For any reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) must return true. - Consistent. For any reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, if no information used in equals is modified. - For any non-null reference value x, x.equals(null) should return false. Let's now provide an implementation of equals which satisfy these properties: ``` //Client class @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Client other = (Client) obj; if (id != other.id) return false; return true; } ``` ### hashCode method - HashCode's are used in hashing to decide which group (or bucket) an object should be placed into. - A group of object's might share the same hashcode. - The implementation of hash code decides effectiveness of Hashing. - A good hashing function evenly distributes object's into different groups (or buckets). hashCode method properties - If obj1.equals(obj2) is true, then obj1.hashCode() should be equal to obj2.hashCode() - obj.hashCode() should return the same value when run multiple times, if values of obj used in equals() have not changed. - If obj1.equals(obj2) is false, it is NOT required that obj1.hashCode() is not equal to obj2.hashCode(). Two unequal objects MIGHT have the same hashCode. Example ``` //Client class @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; return result; } ``` ### Abstract Class An abstract class cannot be instantiated. ``` public abstract class AbstractClassExample { public static void main(String[] args) { //An abstract class cannot be instantiated //Below line gives compilation error if uncommented //AbstractClassExample ex = new AbstractClassExample(); } } //Abstract class can contain instance and static variables public abstract class AbstractClassExample { //Abstract class can contain instance and static variables public int publicVariable; private int privateVariable; static int staticVariable; } //An Abstract method does not contain body. //Abstract Class can contain 0 or more abstract methods //Abstract method does not have a body abstract void abstractMethod1(); abstract void abstractMethod2(); //Abstract method can be declared only in Abstract Class. class NormalClass{ abstract void abstractMethod();//COMPILER ERROR } // Abstract class can contain fully defined non-abstract methods. public abstract class AbstractClassExample { //Abstract class can contain instance and static variables public int publicVariable; private int privateVariable; static int staticVariable; //Abstract Class can contain 0 or more abstract methods //Abstract method does not have a body abstract void abstractMethod1(); abstract void abstractMethod2(); //Abstract Class can contain 0 or more non-abstract methods public void nonAbstractMethod(){ System.out.println("Non Abstract Method"); } public static void main(String[] args) { //An abstract class cannot be instantiated //Below line gives compilation error if uncommented //AbstractClassExample ex = new AbstractClassExample(); } } //Extending an abstract class class SubClass2 extends AbstractClassExample { void abstractMethod1() { System.out.println("Abstract Method1"); } void abstractMethod2() { System.out.println("Abstract Method2"); } } // A concrete sub class should implement all abstract methods. // Below class gives compilation error if uncommented /* class SubClass extends AbstractClassExample { } */ //An abstract sub class need not implement all abstract methods. abstract class AbstractSubClass extends AbstractClassExample { void abstractMethod1() { System.out.println("Abstract Method1"); } //abstractMethod2 is not defined. } ``` Tips - Abstract Methods cannot be paired with final or private access modifiers. - A variable cannot be abstract. ### Constructors - Constructor is invoked whenever we create an instance(object) of a Class. We cannot create an object without a constructor. If we do not provide a constructor, compiler provides a default no-argument constructor. #### Constructor Example 1: Default Constructor In the example below, there are no Constructors defined in the Animal class. Compiler provides us with a default constructor, which helps us create an instance of animal class. ``` public class Animal { String name; public static void main(String[] args) { // Compiler provides this class with a default no-argument constructor. // This allows us to create an instance of Animal class. Animal animal = new Animal(); } } ``` #### Constructor Example 2: Creating a Constructor If we provide a constructor in the class, compiler will NOT provide a default constructor. In the example below we provided a constructor "public Animal(String name)". So, compiler will not provide the default constructor. Constructor has the same name as the class and no return type. It can accept any number of parameters. ``` class Animal { String name; // This is called a one argument constructor. public Animal(String name) { this.name = name; } public static void main(String[] args) { // Since we provided a constructor, compiler does not // provide a default constructor. // Animal animal = new Animal();//COMPILER ERROR! // The only way we can create Animal1 object is by using Animal animal = new Animal("Tommy"); } } ``` #### Constructor Example 3: Provide No Argument Constructor If we want to allow creation of an object with no constructor arguments, we can provide a no argument constructor as well. ``` class Animal { String name; public Animal() { this.name = "Default Name"; } // This is called a one argument constructor. public Animal(String name) { this.name = name; } public static void main(String[] args) { // Since we provided a constructor, compiler does not // provide a default constructor. // Animal animal = new Animal();//COMPILER ERROR! // The only way we can create Animal1 object is by using Animal animal = new Animal("Tommy"); } } ``` #### Constructor Example 4: Calling a Super Class Constructor A constructor can invoke another constructor, or a super class constructor, but only as first statement in the constructor. Another constructor in the same class can be invoked from a constructor, using this({parameters}) method call. To call a super class constructor, super({parameters}) can be used. Both example constructors below can replace the no argument "public Animal() " constructor in Example 3. ``` public Animal() { super(); this.name = "Default Name"; } public Animal() { this("Default Name"); } ``` #### super() or this() should be first statements in a Constructor. Below examples will throw a compilation error if the super or this calls are uncommented. ``` public Animal() { this.name = "Default Name"; //super(), if called, should always the first statement in a constructor. //super(); //COMPILER ERROR } public Animal() { System.out.println("Creating an Animal"); //this(string), if called, should always the first statement in a constructor. //this("Default Name");//COMPILER ERROR } ``` #### Constructor Example 5 Member variables/methods should not be used in constructor calls (super or this). Static variables or methods can be used. ``` public Animal() { //member variable cannot be used in a constructor call this(name);//COMPILER ERROR since name is member variable } ``` #### Constructor Example 6: Constructor cannot be directly called A constructor cannot be explicitly called from any method except another constructor. ``` class Animal { String name; public Animal() { } public method() { Animal();// Compiler error } } ``` #### Constructor Example 7: Super Class Constructor is invoked automatically If a super class constructor is not explicitly called from a sub class constructor, super class (no argument) constructor is automatically invoked (as first line) from a sub class constructor. Consider the example below: ``` class Animal { public Animal() { System.out.println("Animal Constructor"); } } class Dog extends Animal { public Dog() { System.out.println("Dog Constructor"); } } class Labrador extends Dog { public Labrador() { System.out.println("Labrador Constructor"); } } public class ConstructorExamples { public static void main(String[] args) { Labrador labrador = new Labrador(); } } //Output - Animal Constructor Dog Constructor Labrador Constructor ``` It is almost as if super() method is invoked as the first line of every constructor. The example code below shows how the code above behaves. ``` class Animal { public Animal() { super();// IMPLICIT CALL System.out.println("Animal Constructor"); } } class Dog extends Animal { public Dog() { super();// IMPLICIT CALL System.out.println("Dog Constructor"); } } class Labrador extends Dog { public Labrador() { super();// IMPLICIT CALL System.out.println("Labrador Constructor"); } } ``` #### Constructor Example 8 Since a subclass constructor explicitly calls a super class constructor with no arguments, this can cause a few compiler errors. ``` class Animal { String name; public Animal(String name) { this.name = name; System.out.println("Animal Constructor"); } } class Dog extends Animal { public Dog() { // COMPILER ERROR! No constructor for Animal() System.out.println("Dog Constructor"); } } ``` public Dog() makes an implicit super() call i.e. a call to Animal() (no argument) constructor. But no such constructor is defined in Animal class. #### Constructor Example 9 Similar example below except that the Dog no argument constructor is not provided by programmer. However, the compiler would give the no argument constructor, which would invoke super() method. This would again result in a compilation error. ``` class Animal { String name; public Animal(String name) { this.name = name; System.out.println("Animal Constructor"); } } class Dog extends Animal {// COMPILER ERROR! No constructor for Animal() } ``` Two ways to fix above errors. 1.Create a no arguments constructor in Animal class. 2.Make a explicit super("Default Dog Name") call in the Dog() constructor. #### Creating a super class no argument constructor ``` class Animal { String name; public Animal() { } public Animal(String name) { this.name = name; System.out.println("Animal Constructor"); } } ``` #### Making an explicity super call ``` class Dog extends Animal { public Dog() { // COMPILER ERROR! No constructor for Animal() super("Default Dog Name"); System.out.println("Dog Constructor"); } } ``` #### Constructors are NOT inherited. ``` class Animal { String name; public Animal(String name) { this.name = name; System.out.println("Animal Constructor with name"); } } class Dog extends Animal { } public class ConstructorExamples { public static void main(String[] args) { // Dog dog = new Dog("Terry");//COMPILER ERROR } } ``` new Dog("Terry") is not allowed even though there is a constructor in the super class Animal with signature public Animal(String name). Solution is to create an explicit constructor in sub class invoking the super class constructor. Add below constructor to Dog class. ``` class Dog extends Animal { public Dog() { super("Default Dog Name"); } } ``` ### Coupling - Coupling is a measure of how much a class is dependent on other classes. There should minimal dependencies between classes. So, we should always aim for low coupling between classes. #### Coupling Example Problem Consider the example below: ``` class ShoppingCartEntry { public float price; public int quantity; } class ShoppingCart { public ShoppingCartEntry[] items; } class Order { private ShoppingCart cart; private float salesTax; public Order(ShoppingCart cart, float salesTax) { this.cart = cart; this.salesTax = salesTax; } // This method know the internal details of ShoppingCartEntry and // ShoppingCart classes. If there is any change in any of those // classes, this method also needs to change. public float orderTotalPrice() { float cartTotalPrice = 0; for (int i = 0; i < cart.items.length; i++) { cartTotalPrice += cart.items[i].price * cart.items[i].quantity; } cartTotalPrice += cartTotalPrice * salesTax; return cartTotalPrice; } } ``` Method orderTotalPrice in Order class is coupled heavily with ShoppingCartEntry and ShoppingCart classes. It uses different properties (items, price, quantity) from these classes. If any of these properties change, orderTotalPrice will also change. This is not good for Maintenance. #### Coupling Example Solution Consider a better implementation with lesser coupling between classes below: In this implementation, changes in ShoppingCartEntry or CartContents might not affect Order class at all. ``` class ShoppingCartEntry { float price; int quantity; public float getTotalPrice() { return price * quantity; } } class CartContents { ShoppingCartEntry[] items; public float getTotalPrice() { float totalPrice = 0; for (ShoppingCartEntry item:items) { totalPrice += item.getTotalPrice(); } return totalPrice; } } class Order { private CartContents cart; private float salesTax; public Order(CartContents cart, float salesTax) { this.cart = cart; this.salesTax = salesTax; } public float totalPrice() { return cart.getTotalPrice() * (1.0f + salesTax); } } ``` ### Cohesion - Cohesion is a measure of how related the responsibilities of a class are. A class must be highly cohesive i.e. its responsibilities (methods) should be highly related to one another. #### Cohesion Example Problem Example class below is downloading from internet, parsing data and storing data to database. The responsibilities of this class are not really related. This is not cohesive class. ``` class DownloadAndStore{ void downloadFromInternet(){ } void parseData(){ } void storeIntoDatabase(){ } void doEverything(){ downloadFromInternet(); parseData(); storeIntoDatabase(); } } ``` #### Cohesion Example Solution This is a better way of approaching the problem. Different classes have their own responsibilities. ``` class InternetDownloader { public void downloadFromInternet() { } } class DataParser { public void parseData() { } } class DatabaseStorer { public void storeIntoDatabase() { } } class DownloadAndStore { void doEverything() { new InternetDownloader().downloadFromInternet(); new DataParser().parseData(); new DatabaseStorer().storeIntoDatabase(); } } ``` ### Encapsulation - Encapsulation is Òhiding the implementation of a Class behind a well defined interfaceÓ. Encapsulation helps us to change implementation of a class without breaking other code. #### Encapsulation Approach 1 In this approach we create a public variable score. The main method directly accesses the score variable, updates it. #### Example Class ``` public class CricketScorer { public int score; } ``` Let's use the CricketScorer class. ``` public static void main(String[] args) { CricketScorer scorer = new CricketScorer(); scorer.score = scorer.score + 4; } ``` #### Encapsulation Approach 2 In this approach, we make score as private and access value through get and set methods. However, the logic of adding 4 to the score is performed in the main method. #### Example Class ``` public class CricketScorer { private int score; public int getScore() { return score; } public void setScore(int score) { this.score = score; } } ``` Let's use the CricketScorer class. ``` public static void main(String[] args) { CricketScorer scorer = new CricketScorer(); int score = scorer.getScore(); scorer.setScore(score + 4); } ``` #### Encapsulation Approach 3 In this approach - For better encapsulation, the logic of doing the four operation also is moved to the CricketScorer class. #### Example Class ``` public class CricketScorer { private int score; public void four() { score += 4; } } ``` Let's use the CricketScorer class. ``` public static void main(String[] args) { CricketScorer scorer = new CricketScorer(); scorer.four(); } ``` #### Encapsulation Example In terms of encapsulation Approach 3 > Approach 2 > Approach 1. In Approach 3, the user of scorer class does not even know that there is a variable called score. Implementation of Scorer can change without changing other classes using Scorer. ### Interface - An interface defines a contract for responsibilities (methods) of a class. Let's look at a few examples of interfaces. #### Defining an Interface An interface is declared by using the keyword interface. Look at the example below: Flyable is an interface. ``` //public abstract are not necessary public abstract interface Flyable { //public abstract are not necessary public abstract void fly(); } ``` #### An interface can contain abstract methods -- NOT TRUE ANY MORE In the above example, fly method is abstract since it is only declared (No definition is provided). #### Implementing an Interface We can define a class implementing the interface by using the implements keyword. Let us look at a couple of examples: #### Example 1 Class Aeroplane implements Flyable and implements the abstract method fly(). ``` public class Aeroplane implements Flyable{ @Override public void fly() { System.out.println("Aeroplane is flying"); } } ``` #### Example 2 ``` public class Bird implements Flyable{ @Override public void fly() { System.out.println("Bird is flying"); } } ``` #### Using the Interface and Implementation The interface classes can directly be instantiated and stored in the class reference variables ``` Bird bird = new Bird(); bird.fly();//Bird is flying Aeroplane aeroplane = new Aeroplane(); aeroplane.fly();//Aeroplane is flying ``` An interface reference variable can hold objects of any implementation of interface. ``` Flyable flyable1 = new Bird(); Flyable flyable2 = new Aeroplane(); ``` #### Variables in an interface Variables in an interface are always public, static, final. Variables in an interface cannot be declared private. ``` interface ExampleInterface1 { //By default - public static final. No other modifier allowed //value1,value2,value3,value4 all are - public static final int value1 = 10; public int value2 = 15; public static int value3 = 20; public static final int value4 = 25; //private int value5 = 10;//COMPILER ERROR } ``` #### Methods in an interface Interface methods are by default public and abstract. A concrete default method (fully defined method) can be created in an interface. Consider the example below: ``` interface ExampleInterface1 { //By default - public abstract. No other modifier allowed void method1();//method1 is public and abstract //private void method6();//COMPILER ERROR! } ``` #### Extending an Interface An interface can extend another interface. Consider the example below: ``` interface SubInterface1 extends ExampleInterface1{ void method3(); } ``` Class implementing SubInterface1 should implement both methods - method3 and method1(from ExampleInterface1) An interface cannot extend a class. ``` /* //COMPILE ERROR IF UnCommented //Interface cannot extend a Class interface SubInterface2 extends Integer{ void method3(); } */ ``` A class can implement multiple interfaces. It should implement all the method declared in all Interfaces being implemented. ``` interface ExampleInterface2 { void method2(); } class SampleImpl implements ExampleInterface1,ExampleInterface2{ /* A class should implement all the methods in an interface. If either of method1 or method2 is commented, it would result in compilation error. */ public void method2() { System.out.println("Sample Implementation for Method2"); } public void method1() { System.out.println("Sample Implementation for Method1"); } } ``` #### Interface , Things to Remember A class should implement all the methods in an interface, unless it is declared abstract. A Class can implement multiple interfaces. No new checked exceptions can be thrown by implementations of methods in an interface. ### Method Overloading - A method having the same name as another method (in same class or a sub class) but having different parameters is called an Overloaded Method. #### Method Overloading Example 1 doIt method is overloaded in the below example: ``` class Foo{ public void doIt(int number){ } public void doIt(String string){ } } ``` #### Method Overloading Example 2 Overloading can also be done from a sub class. ``` class Bar extends Foo{ public void doIt(float number){ } } ``` #### Overloading - Other Rules An overloaded method should have different arguments than the original method. It can also have a different return type. A method cannot be overloaded just by only changing the return type. Overloaded methods are always treated as if they are different methods altogether. Overloading does not put any restrictions on access modifiers or exceptions thrown from the method. Overloaded method invocation is based on the Type of the Reference variable. It is NOT based on the object it refers to. - Java Example - Constructors - public HashMap(int initialCapacity, float loadFactor) - public HashMap() { - public HashMap(int initialCapacity) - Methods - public boolean addAll(Collection c) - public boolean addAll(int index, Collection c) - [Rules](src/main/java/com/in28minutes/java/oops/inheritance/overloading/OverloadingRules.java) ### Method Overriding - Creating a Sub Class Method with same signature as that of a method in SuperClass is called Method Overriding. #### Method Overriding Example 1: Let's define an Animal class with a method shout. ``` public class Animal { public String bark() { return "Don't Know!"; } } ``` Let's create a sub class of Animal , Cat - overriding the existing shout method in Animal. ``` class Cat extends Animal { public String bark() { return "Meow Meow"; } } ``` bark method in Cat class is overriding the bark method in Animal class. - Java Example - HashMap public int size() overrides AbstractMap public int size() - [Example](src/main/java/com/in28minutes/java/oops/inheritance/overriding/OverridingRules.java) #### Overriding Method Cannot have lesser visibility Overriding method cannot have lesser visibility than the Super Class method. Consider these two examples #### Example 1 ``` class SuperClass{ public void publicMethod(){ } } class SubClass{ //Cannot reduce visibility of SuperClass Method //So, only option is public public void publicMethod() { } } ``` publicMethod in SubClass can only be declared as public. Keyword protected, private or (default) instead of public would result in Compilation Error. #### Example 2 ``` class SuperClass{ void defaultMethod(){ } } class SubClass{ //Can be overridden with public,(default) or protected //private would give COMPILE ERROR! public void defaultMethod(){ } } ``` defaultMethod in SuperClass is declared with default access. Any method overriding it can have access default or greater. So default, protected and public are fine. Overriding method cannot be private. #### Overriding method cannot throw new Checked Exceptions Consider the example below: ``` class SuperClass{ public void publicMethod() throws FileNotFoundException{ } } class SubClass{ //Cannot throw bigger exceptions than Super Class public void publicMethod() /*throws IOException*/ { } } ``` publicMethod() in SuperClass throws FileNotFoundException. So, the SubClass publicMethod() can throw FileNotFoundException or any sub class of FileNotFoundException. It can also not throw an Exception (as in the example). But, it cannot throw any new Exception. For example, Òpublic void publicMethod() throws IOExceptionÓ would cause compilation error. #### Other Overriding Rules A Sub Class can override only those methods that are visible to it. Methods marked as static or final cannot be overridden. You can call the super class method from the overriding method using keyword super. #### Overriding and Polymorphism Example Overridden method invocation is based on the object referred to. It is not based on the Type of the Reference variable. This is called Polymorphism. Consider the example below: ``` class Animal{ public void bark(){ System.out.println("Animal Bark"); } } class Dog extends Animal{ public void bark(){ System.out.println("Dog Bark"); } } public class PolymorphismExample { public static void main(String[] args) { Animal[] animals = {new Dog(),new Animal()}; animals[0].bark();//Dog bark animals[1].bark();//Animal bark } } ``` animals[0] contains a reference to Dog Object. When animals[0].bark() method is called method in Dog class is invoked even though the type of reference variable is Animal. animals[1] contains a reference to Animal Object. When animals[1].bark() method is called method in Animal class is invoked. #### Covariant Returns A sub class is considered to be of same type as its super class. So, in interfaces or abstract class, it is fine to provide implementations using the Sub Class Types as Return Types.(com.in28minutes.SameType) ### Class Modifiers - Let us learn about a few Java Class Modifiers. #### Access Modifiers Access modifier for a class can be public or (default), It cannot be private or protected. ``` public class PublicClass{ } class DefaultClass{ } protected class Error{//COMPILER ERROR } private class Error{//COMPILER ERROR } ``` #### Non-access modifiers strictfp, final, abstract modifiers are valid on a class. ### Class Access Modifiers - Lets learn about a few Java Class Access Modifiers. #### public class modifier A public class is visible to all other classes. #### default class modifier A class is called a Default Class is when there is no access modifier specified on a class. Default classes are visible inside the same package only. Default access is also called Package access. #### Default Class Modifier Examples #### Default Access Class Example package com.in28minutes.classmodifiers.defaultaccess.a; ``` /* No public before class. So this class has default access*/ class DefaultAccessClass { //Default access is also called package access } ``` #### Another Class in Same Package: Has access to default class ``` package com.in28minutes.classmodifiers.defaultaccess.a; public class AnotherClassInSamePackage { //DefaultAccessClass and AnotherClassInSamePackage //are in same package. //So, DefaultAccessClass is visible. //An instance of the class can be created. DefaultAccessClass defaultAccess; } ``` #### Class in Different Package: NO access to default class ``` package com.in28minutes.classmodifiers.defaultaccess.b; public class ClassInDifferentPackage { //Class DefaultAccessClass and Class ClassInDifferentPackage //are in different packages (*.a and *.b) //So, DefaultAccessClass is not visible to ClassInDifferentPackage //Below line of code will cause compilation error if uncommented //DefaultAccessClass defaultAccess; //COMPILE ERROR!! } ``` ### Method and Variable Access Modifiers - Method and variable access modifiers can be public, protected, private or (default) #### Two Access Modifier Questions When we talk about access modifiers, we would discuss two important questions #### Is Accessible through reference/instance variable? We create an instance of the class and try to access the variables and methods declared in the class. ``` ExampleClass example = new ExampleClass(); example.publicVariable = 5; example.publicMethod(); ``` #### Is Accessible through Inheritance? Can we access the super class variables and methods from a Sub Class? ``` public class SubClass extends ExampleClass { void subClassMethod(){ publicVariable = 5; protectedVariable = 5; } } ``` #### Important Access Things to Remember A sub class trying to access through reference/instance variables, will have the same access as a normal class (non sub class). Access modifiers cannot be applied to local variables #### Access Modifiers Example Let's consider the following class with variables and methods declared with all 4 access modifiers: ``` package com.in28minutes.membermodifiers.access; public class ExampleClass { int defaultVariable; public int publicVariable; private int privateVariable; protected int protectedVariable; void defaultMethod(){ } public void publicMethod(){ } private void privateMethod(){ } protected void protectedMethod(){ } } ``` #### Method Access Modifiers Let's discuss about access modifiers in order of increasing access. #### private a. Private variables and methods can be accessed only in the class they are declared. b. Private variables and methods from SuperClass are NOT available in SubClass. #### default or package a. Default variables and methods can be accessed in the same package Classes. b. Default variables and methods from SuperClass are available only to SubClasses in same package. #### protected a. Protected variables and methods can be accessed in the same package Classes. b. Protected variables and methods from SuperClass are available to SubClass in any package #### public a. Public variables and methods can be accessed from every other Java classes. b. Public variables and methods from SuperClass are all available directly in the SubClass #### Access Modifier Example: Class in Same Package Look at the code below to understand what can be accessed and what cannot be. ``` package com.in28minutes.membermodifiers.access; public class TestClassInSamePackage { public static void main(String[] args) { ExampleClass example = new ExampleClass(); example.publicVariable = 5; example.publicMethod(); //privateVariable is not visible //Below Line, uncommented, would give compiler error //example.privateVariable=5; //COMPILE ERROR //example.privateMethod(); example.protectedVariable = 5; example.protectedMethod(); example.defaultVariable = 5; example.defaultMethod(); } } ``` #### Access Modifier Example: Class in Different Package Look at the code below to understand what can be accessed and what cannot be. ``` package com.in28minutes.membermodifiers.access.different; import com.in28minutes.membermodifiers.access.ExampleClass; public class TestClassInDifferentPackage { public static void main(String[] args) { ExampleClass example = new ExampleClass(); example.publicVariable = 5; example.publicMethod(); //privateVariable,privateMethod are not visible //Below Lines, uncommented, would give compiler error //example.privateVariable=5; //COMPILE ERROR //example.privateMethod();//COMPILE ERROR //protectedVariable,protectedMethod are not visible //Below Lines, uncommented, would give compiler error //example.protectedVariable = 5; //COMPILE ERROR //example.protectedMethod();//COMPILE ERROR //defaultVariable,defaultMethod are not visible //Below Lines, uncommented, would give compiler error //example.defaultVariable = 5;//COMPILE ERROR //example.defaultMethod();//COMPILE ERROR } } ``` #### Access Modifier Example: Sub Class in Same Package Look at the code below to understand what can be accessed and what cannot be. ``` package com.in28minutes.membermodifiers.access; public class SubClassInSamePackage extends ExampleClass { void subClassMethod(){ publicVariable = 5; publicMethod(); //privateVariable is not visible to SubClass //Below Line, uncommented, would give compiler error //privateVariable=5; //COMPILE ERROR //privateMethod(); protectedVariable = 5; protectedMethod(); defaultVariable = 5; defaultMethod(); } } ``` #### Access Modifier Example: Sub Class in Different Package Look at the code below to understand what can be accessed and what cannot be. ``` package com.in28minutes.membermodifiers.access.different; import com.in28minutes.membermodifiers.access.ExampleClass; public class SubClassInDifferentPackage extends ExampleClass { void subClassMethod(){ publicVariable = 5; publicMethod(); //privateVariable is not visible to SubClass //Below Line, uncommented, would give compiler error //privateVariable=5; //COMPILE ERROR //privateMethod(); protectedVariable = 5; protectedMethod(); //privateVariable is not visible to SubClass //Below Line, uncommented, would give compiler error //defaultVariable = 5; //COMPILE ERROR //defaultMethod(); } } ``` ### Final modifier - Let's discuss about Final modifier in Java. #### Final class cannot be extended Consider the class below which is declared as final. ``` final public class FinalClass { } ``` Below class will not compile if uncommented. FinalClass cannot be extended. ``` /* class ExtendingFinalClass extends FinalClass{ //COMPILER ERROR } */ ``` Example of Final class in Java is the String class. Final is used very rarely as it prevents re-use of the class. #### Final methods cannot be overriden. Consider the class FinalMemberModifiersExample with method finalMethod which is declared as final. ``` public class FinalMemberModifiersExample { final void finalMethod(){ } } ``` Any SubClass extending above class cannot override the finalMethod(). ``` class SubClass extends FinalMemberModifiersExample { //final method cannot be over-riddent //Below method, uncommented, causes compilation Error /* final void finalMethod(){ } */ } ``` #### Final variable values cannot be changed. Once initialized, the value of a final variable cannot be changed. ``` final int finalValue = 5; //finalValue = 10; //COMPILER ERROR ``` #### Final arguments value cannot be modified. Consider the example below: ``` void testMethod(final int finalArgument){ //final argument cannot be modified //Below line, uncommented, causes compilation Error //finalArgument = 5;//COMPILER ERROR } ``` ### Other Non access Modifiers - A class cannot be both abstract and final #### strictfp This modifier can be used on a class and a method. This (strictfp) cannot be used on a variable. IEEE standard for floating points would be followed in the method or class where strictfp modifier is specified. #### volatile Volatile can only be applied to instance variables. A volatile variable is one whose value is always written to and read from "main memory". Each thread has its own cache in Java. The volatile variable will not be stored on a Thread cache. #### native Can be applied only to methods. These methods are implemented in native languages (like C) ### Static Variables and Methods - Static variables and methods are class level variables and methods. There is only one copy of the static variable for the entire Class. Each instance of the Class (object) will NOT have a unique copy of a static variable. Let's start with a real world example of a Class with static variable and methods. #### Static Variable/Method , Example count variable in Cricketer class is static. The method to get the count value getCount() is also a static method. ``` public class Cricketer { private static int count; public Cricketer() { count++; } static int getCount() { return count; } public static void main(String[] args) { Cricketer cricketer1 = new Cricketer(); Cricketer cricketer2 = new Cricketer(); Cricketer cricketer3 = new Cricketer(); Cricketer cricketer4 = new Cricketer(); System.out.println(Cricketer.getCount());//4 } } ``` 4 instances of the Cricketer class are created. Variable count is incremented with every instance created in the constructor. #### Static Variables and Methods Example 2 Example class below explains all the rules associated with access static variables and static methods. ``` public class StaticModifierExamples { private static int staticVariable; private int instanceVariable; public static void staticMethod() { //instance variables are not accessible in static methods //instanceVariable = 10; //COMPILER ERROR //Also, this Keyword is not accessible. this refers to object. //static methods are class methods //static variables are accessible in static methods staticVariable = 10; } public void instanceMethod() { //static and instance variables are accessible in instance methods instanceVariable = 10; staticVariable = 10; } public static void main(String[] args) { //static int i =5; //COMPILER ERROR StaticModifierExamples example = new StaticModifierExamples(); //instance variables and methods are only accessible through object references example.instanceVariable = 10; example.instanceMethod(); //StaticModifierExamples.instanceVariable = 10;//COMPILER ERROR //StaticModifierExamples.instanceMethod();//COMPILER ERROR //static variables and methods are accessible through object references and Class Name. example.staticVariable = 10; example.staticMethod(); StaticModifierExamples.staticVariable = 10; StaticModifierExamples.staticMethod(); } } ``` In a static method, instance variables are not accessible. Keyword this is also not accessible. However static variables are accessible. ``` public static void staticMethod() { //instance variables are not accessible in static methods //instanceVariable = 10; //COMPILER ERROR //Also, this Keyword is not accessible. this refers to object. //static methods are class methods //static variables are accessible in static methods staticVariable = 10; } ``` In instance methods, both static and instance variables are accessible. ``` public void instanceMethod() { instanceVariable = 10; staticVariable = 10; } ``` Instance variables and methods are only accessible through object references. ``` example.instanceVariable = 10; example.instanceMethod(); //StaticModifierExamples.instanceVariable = 10;//COMPILER ERROR //StaticModifierExamples.instanceMethod();//COMPILER ERROR ``` Static variables and methods are accessible through object references and Class Name. ``` example.staticVariable = 10; example.staticMethod(); StaticModifierExamples.staticVariable = 10; StaticModifierExamples.staticMethod(); ``` It is always recommended to use Class Name to access a static variable or method. This is because static methods are class level methods. It is not appropriate to use instance references to call static methods (even though it compiles and works). #### Static methods cannot be overridden Consider the example below: ``` class Animal{ static void StaticMethod(){ System.out.println("Animal Static Method"); } } class Dog extends Animal{ static void StaticMethod(){ System.out.println("Dog Static Method"); } } ``` When code below is run, static method in Animal is executed. Static method invocation is based on the type of reference variable. It does not depend on the type of object referred to. ``` Animal animal = new Dog(); animal.StaticMethod();//Animal Static Method ``` #### Local variables cannot be declared as static Example below: ``` public static void main(String[] args) { //static int i =5; //COMPILER ERROR } ``` ### Class Contents - Let's discuss what a Java class can contain and what it cannot. #Section Java Source File Rules A Java Source File can contain a.0 or 1 Public Classes b.0 or 1 or More Non Public Classes Order should be 1. Package Statement 2. Imports 3. Class Declarations Comments can be anywhere in the file. If there is a public class, file name should the (name of public class) + ".java". If name of public class is Scorer, name of file should be Scorer.java. If there is no public class, there are no restrictions on file name. #### Example Class ``` /* Comments Anywhere*/ package com.in28minutes.classcontent; class DefaultClass1{ } /* Comments Anywhere*/ class DefaultClass2{ } /* Comments Anywhere*/ public class PublicClass1 { } /* Cannot have another Public Class. public class PublicClass2 { } */ ``` ### Nested Class - Nested Classes are classes which are declared inside other classes. #### Nested Class Example Consider the following example: ``` class OuterClass { public class InnerClass { } public static class StaticNestedClass { } public void exampleMethod() { class MethodLocalInnerClass { }; } } ``` #### Inner Class Generally the term inner class is used to refer to a non-static class declared directly inside another class. Consider the example of class named InnerClass. #### Static Inner Class A class declared directly inside another class and declared as static. In the example above, class name StaticNestedClass is a static inner class. #### Method Inner Class A class declared directly inside a method. In the example above, class name MethodLocalInnerClass is a method inner class. ### Inner Class - Inner Class is a very important Java Concept. Let's learn about it in this tutorial. #### Inner Class Example Consider the following Example: ``` class OuterClass { private int outerClassInstanceVariable; public class InnerClass { private int innerClassVariable; public int getInnerClassVariable() { return innerClassVariable; } public void setInnerClassVariable( int innerClassVariable) { this.innerClassVariable = innerClassVariable; } public void privateVariablesOfOuterClassAreAvailable() { outerClassInstanceVariable = 5; // we can access the value System.out.println("Inner class ref is " + this); //Accessing outer class reference variable System.out.println("Outer class ref is " + OuterClass.this); } } public void createInnerClass(){ //Just use the inner class name to create it InnerClass inner = new InnerClass(); } } public class InnerClassExamples { public static void main(String[] args) { // COMPILER ERROR! You cannot create an inner class on its own. // InnerClass innerClass = new InnerClass(); OuterClass example = new OuterClass(); // To create an Inner Class you need an instance of Outer Class OuterClass.InnerClass innerClass = example.new InnerClass(); } } ``` Inner class cannot be directly instantiated. ``` // InnerClass innerClass = new InnerClass(); //Compiler Error ``` To create an Inner Class you need an instance of Outer Class. ``` OuterClass example = new OuterClass(); OuterClass.InnerClass innerClass = example.new InnerClass(); ``` #### Creating an Inner Class instance in outer class Consider the method createInnerClass from the example above: This method shows how to create an inner class instance. ``` public void createInnerClass(){ //Just use the inner class name to create it InnerClass inner = new InnerClass(); } ``` #### Instance variables of Outer Class are available in inner class Consider the method privateVariablesOfOuterClassAreAvailable from InnerClass declared above: ``` public void privateVariablesOfOuterClassAreAvailable() { outerClassInstanceVariable = 5; // we can access the value System.out.println("Inner class ref is " + this); //Accessing outer class reference variable System.out.println("Outer class ref is " + OuterClass.this); } ``` ### Static Inner Nested Class - Let's learn about Static Inner Nested Class in this Java tutorial. #### Static Inner Nested Class Example Consider the example below: ``` class OuterClass { private int outerClassInstanceVariable; public static class StaticNestedClass { private int staticNestedClassVariable; public int getStaticNestedClassVariable() { return staticNestedClassVariable; } public void setStaticNestedClassVariable( int staticNestedClassVariable) { this.staticNestedClassVariable = staticNestedClassVariable; } public void privateVariablesOfOuterClassAreNOTAvailable() { // outerClassInstanceVariable = 5; //COMPILE ERROR } } } public class InnerClassExamples { public static void main(String[] args) { // Static Nested Class can be created without needing to create its // parent. Without creating NestedClassesExample, we created // StaticNestedClass OuterClass.StaticNestedClass staticNestedClass1 = new OuterClass.StaticNestedClass(); staticNestedClass1.setStaticNestedClassVariable(5); OuterClass.StaticNestedClass staticNestedClass2 = new OuterClass.StaticNestedClass(); staticNestedClass2.setStaticNestedClassVariable(10); // Static Nested Class member variables are not static. They can have // different values. System.out.println(staticNestedClass1 .getStaticNestedClassVariable()); //5 System.out.println(staticNestedClass2 .getStaticNestedClassVariable()); //10 } } ``` #### Creating Static Nested Class Static Nested Class can be created without needing to create its parent. Without creating NestedClassesExample, we createdStaticNestedClass. ``` OuterClass.StaticNestedClass staticNestedClass1 = new OuterClass.StaticNestedClass(); ``` #### Member variables are not static Static Nested Class member variables are not static. They can have different values. ``` System.out.println(staticNestedClass1 .getStaticNestedClassVariable()); //5 System.out.println(staticNestedClass2 .getStaticNestedClassVariable()); //10 ``` #### Outer class instance variables are not accessible. Instance variables of outer class are not available in the Static Class. ``` public void privateVariablesOfOuterClassAreNOTAvailable() { // outerClassInstanceVariable = 5; //COMPILE ERROR } ``` ### Method Inner Class - Let us learn about Method Inner Class in this tutorial. #### Method Inner Class Example Consider the example below: MethodLocalInnerClass is declared in exampleMethod(); ``` class OuterClass { private int outerClassInstanceVariable; public void exampleMethod() { int localVariable; final int finalVariable = 5; class MethodLocalInnerClass { public void method() { //Can access class instance variables System.out .println(outerClassInstanceVariable); //Cannot access method's non-final local variables //localVariable = 5;//Compiler Error System.out.println(finalVariable);//Final variable is fine.. } } //MethodLocalInnerClass can be instantiated only in this method MethodLocalInnerClass m1 = new MethodLocalInnerClass(); m1.method(); } //MethodLocalInnerClass can be instantiated only in the method where it is declared //MethodLocalInnerClass m1 = new MethodLocalInnerClass();//COMPILER ERROR } ``` #### Method inner class is not accessible outside the method Look at the commented code below exampleMethod. MethodLocalInnerClass can be instantiated only in the method where it is declared. #### Method inner class can access class instance variables ``` //Can access class instance variables System.out.println(outerClassInstanceVariable); ``` #### Method inner class cannot access method's non-final local variables ``` //Cannot access method's non-final local variables //localVariable = 5;//Compiler Error System.out.println(finalVariable);//Final variable is fine.. ``` ### Variable Arguments - Variable Arguments allow calling a method with different number of parameters. #### Variable Arguments Example ``` //int(type) followed ... (three dot's) is syntax of a variable argument. public int sum(int... numbers) { //inside the method a variable argument is similar to an array. //number can be treated as if it is declared as int[] numbers; int sum = 0; for (int number: numbers) { sum += number; } return sum; } public static void main(String[] args) { VariableArgumentExamples example = new VariableArgumentExamples(); //3 Arguments System.out.println(example.sum(1, 4, 5));//10 //4 Arguments System.out.println(example.sum(1, 4, 5, 20));//30 //0 Arguments System.out.println(example.sum());//0 } ``` #### Variable Arguments Syntax Data Type followed ... (three dot's) is syntax of a variable argument. ``` public int sum(int... numbers) { ``` Inside the method a variable argument is similar to an array. For Example: number can be treated in below method as if it is declared as int[] numbers; ``` public int sum(int... numbers) { int sum = 0; for (int number: numbers) { sum += number; } return sum; } ``` #### Variable Argument: only Last Parameter Variable Argument should be always the last parameter (or only parameter) of a method. Below example gives a compilation error ``` public int sum(int... numbers, float value) {//COMPILER ERROR } ``` #### Variable Argument of Type Custom Class Even a class can be used a variable argument. In the example below, bark method is overloaded with a variable argument method. ``` class Animal { void bark() { System.out.println("Bark"); } void bark(Animal... animals) { for (Animal animal: animals) { animal.bark(); } } } ``` ### Exception Handling - In this tutorial, let's understand the need for exception handling and learn how to handle exceptions. #### Example without Exception Handling Let's first look an example without exception handling. Method main throws an exception because toString method is invoked on a null object. ``` public static void main(String[] args) { String str = null; str.toString(); } ``` Output of above program is ``` Exception in thread "main" java.lang.NullPointerException at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.main(ExceptionHandlingExample1.java:6) ``` #### Exception Example 2 , Propagation of an Exception In this example, main invokes method1, which invokes method2 which throws a NullPointerException. Check the output of this program. ``` public static void main(String[] args) { method1(); } private static void method1() { method2(); } private static void method2() { String str = null; str.toString(); } //Output - Exception in thread "main" java.lang.NullPointerException at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.method2(ExceptionHandlingExample1.java:15) at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.method1(ExceptionHandlingExample1.java:10) at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.main(ExceptionHandlingExample1.java:6) ``` Look at the stack trace. Exception which is thrown in method2 is propagating to method1 and then to main. This is because there is no exception handling in all 3 methods - main, method1 and method2 #### Exception Example 3: Execution of method stopped Look at the example below: A println method call is added after every method call. ``` public static void main(String[] args) { method1(); System.out.println("Line after Exception - Main"); } private static void method1() { method2(); System.out.println("Line after Exception - Method 1"); } private static void method2() { String str = null; str.toString(); System.out.println("Line after Exception - Method 2"); } //Output - Exception in thread "main" java.lang.NullPointerException at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.method2(ExceptionHandlingExample1.java:18) at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.method1(ExceptionHandlingExample1.java:12) at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.main(ExceptionHandlingExample1.java:7) ``` Note that none of the lines with text "Line after Exception - ****" are executed. If an exception occurs, lines after the line where exception occurred are not executed. Since all three methods main, method1() and method2() do not have any Exception Handling, exception propagates from method2 to method1 to main. #### Exception Handling Example 4: Try catch block Let's add a try catch block in method2 ``` public static void main(String[] args) { method1(); System.out.println("Line after Exception - Main"); } private static void method1() { method2(); System.out.println("Line after Exception - Method 1"); } private static void method2() { try { String str = null; str.toString(); System.out.println("Line after Exception - Method 2"); } catch (Exception e) { // NOT PRINTING EXCEPTION TRACE- BAD PRACTICE System.out.println("Exception Handled - Method 2"); } } ``` Output ``` Exception Handled - Method 2 Line after Exception - Method 1 Line after Exception - Main ``` Since Exception Handling is added in the method method2, the exception did not propogate to method1. You can see the "Line after Exception - **" in the output for main, method1 since they are not affected by the exception thrown. Since the exception was handled in method2, method1 and main are not affected by it. This is the main essence of exception handling. However, note that the line after the line throwing exception in method2 is not executed. Few important things to remember from this example. 1.If exception is handled, it does not propogate further. 2.In a try block, the lines after the line throwing the exception are not executed. #### Exception Handling Example 5: Need for Finally Consider the example below: In method2, a connection is opened. However, because of the exception thrown, connection is not closed. This results in unclosed connections. ``` package com.in28minutes.exceptionhandling; class Connection { void open() { System.out.println("Connection Opened"); } void close() { System.out.println("Connection Closed"); } } public class ExceptionHandlingExample1 { // Exception Handling Example 1 // Let's add a try catch block in method2 public static void main(String[] args) { method1(); System.out.println("Line after Exception - Main"); } private static void method1() { method2(); System.out.println("Line after Exception - Method 1"); } private static void method2() { try { Connection connection = new Connection(); connection.open(); // LOGIC String str = null; str.toString(); connection.close(); } catch (Exception e) { // NOT PRINTING EXCEPTION TRACE- BAD PRACTICE System.out.println("Exception Handled - Method 2"); } } } ``` Output ``` Connection Opened Exception Handled - Method 2 Line after Exception - Method 1 Line after Exception - Main ``` Connection that is opened is not closed. Because an exception has occurred in method2, connection.close() is not run. This results in a dangling (un-closed) connection. #### Exception Handling Example 6 - Finally Finally block is used when code needs to be executed irrespective of whether an exception is thrown. Let us now move connection.close(); into a finally block. Also connection declaration is moved out of the try block to make it visible in the finally block. ``` private static void method2() { Connection connection = new Connection(); connection.open(); try { // LOGIC String str = null; str.toString(); } catch (Exception e) { // NOT PRINTING EXCEPTION TRACE - BAD PRACTICE System.out.println("Exception Handled - Method 2"); } finally { connection.close(); } } ``` Output ``` Connection Opened Exception Handled - Method 2 Connection Closed Line after Exception - Method 1 Line after Exception - Main ``` Connection is closed even when exception is thrown. This is because connection.close() is called in the finally block. Finally block is always executed (even when an exception is thrown). So, if we want some code to be always executed we can move it to finally block. Code in finally is NOT executed only in two situations. If exception is thrown in finally. If JVM Crashes in between (for example, System.exit()). #### finally is executed even if there is a return statement in catch or try ``` private static void method2() { Connection connection = new Connection(); connection.open(); try { // LOGIC String str = null; str.toString(); return; } catch (Exception e) { // NOT PRINTING EXCEPTION TRACE - BAD PRACTICE System.out.println("Exception Handled - Method 2"); return; } finally { connection.close(); } } ``` #### Exception Handling Syntax Let's look at a few quirks about Exception Handling syntax. #### try without a catch is allowed ``` private static void method2() { Connection connection = new Connection(); connection.open(); try { // LOGIC String str = null; str.toString(); } finally { connection.close(); } } ``` Output: ``` Connection Opened Connection Closed Exception in thread "main" java.lang.NullPointerException at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.method2(ExceptionHandlingExample1.java:33) at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.method1(ExceptionHandlingExample1.java:22) at com.in28minutes.exceptionhandling.ExceptionHandlingExample1.main(ExceptionHandlingExample1.java:17) ``` Try without a catch is useful when you would want to do something (close a connection) even if an exception occurred without handling the exception. #### Try without both catch and finally is not allowed. Below method would give a Compilation Error!! (End of try block) ``` private static void method2() { Connection connection = new Connection(); connection.open(); try { // LOGIC String str = null; str.toString(); }//COMPILER ERROR!! } ``` #### Exception Handling Hierarchy Throwable is the highest level of Error Handling classes. Below class definitions show the pre-defined exception hierarchy in Java. ``` //Pre-defined Java Classes class Error extends Throwable{} class Exception extends Throwable{} class RuntimeException extends Exception{} ``` Below class definitions show creation of a programmer defined exception in Java. ``` //Programmer defined classes class CheckedException1 extends Exception{} class CheckedException2 extends CheckedException1{} class UnCheckedException extends RuntimeException{} class UnCheckedException2 extends UnCheckedException{} ``` #### Errors Error is used in situations when there is nothing a programmer can do about an error. Ex: StackOverflowError, OutOfMemoryError. #### Exception Exception is used when a programmer can handle the exception. #### Un-Checked Exception RuntimeException and classes that extend RuntimeException are called unchecked exceptions. For Example: RuntimeException,UnCheckedException,UnCheckedException2 are unchecked or RunTime Exceptions. There are subclasses of RuntimeException (which means they are subclasses of Exception also.) #### Checked Exception Other Exception Classes (which don't fit the earlier definition). These are also called Checked Exceptions. Exception, CheckedException1,CheckedException2 are checked exceptions. They are subclasses of Exception which are not subclasses of RuntimeException. #### Throwing RuntimeException in method Method addAmounts in Class AmountAdder adds amounts. If amounts are of different currencies it throws an exception. ``` class Amount { public Amount(String currency, int amount) { this.currency = currency; this.amount = amount; } String currency;// Should be an Enum int amount;// Should ideally use BigDecimal } // AmountAdder class has method addAmounts which is throwing a RuntimeException class AmountAdder { static Amount addAmounts(Amount amount1, Amount amount2) { if (!amount1.currency.equals(amount2.currency)) { throw new RuntimeException("Currencies don't match"); } return new Amount(amount1.currency, amount1.amount + amount2.amount); } } public class ExceptionHandlingExample2 { public static void main(String[] args) { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR", 5)); } } ``` #### Output ``` Exception in thread "main" java.lang.RuntimeException: Currencies don't match at com.in28minutes.exceptionhandling.AmountAdder.addAmounts(ExceptionHandlingExample2.java:17) at com.in28minutes.exceptionhandling.ExceptionHandlingExample2.main(ExceptionHandlingExample2.java:28) ``` Exception message shows the type of exception(java.lang.RuntimeException) and the string message passed to the RuntimeException constructor("Currencies don't match"); #### Throwing Exception (Checked Exception) in method Let us now try to change the method addAmounts to throw an Exception instead of RuntimeException. It gives us a compilation error. ``` class AmountAdder { static Amount addAmounts(Amount amount1, Amount amount2) { if (!amount1.currency.equals(amount2.currency)) { throw new Exception("Currencies don't match");// COMPILER ERROR!// Unhandled exception type Exception } return new Amount(amount1.currency, amount1.amount + amount2.amount); } } ``` All classes that are not RuntimeException or subclasses of RuntimeException but extend Exception are called CheckedExceptions. The rule for CheckedExceptions is that they should be handled or thrown. Handled means it should be completed handled - i.e. not throw out of the method. Thrown means the method should declare that it throws the exception #### Throws Exception Example Let's look at how to declare throwing an exception from a method. ``` class AmountAdder { static Amount addAmounts(Amount amount1, Amount amount2) throws Exception { if (!amount1.currency.equals(amount2.currency)) { throw new Exception("Currencies don't match"); } return new Amount(amount1.currency, amount1.amount + amount2.amount); } } ``` Look at the line "static Amount addAmounts(Amount amount1, Amount amount2) throws Exception". This is how we declare that a method throws Exception. This results in compilation error in main method. This is because Main method is calling a method which is declaring that it might throw Exception. Main method again has two options a. Throw b. Handle Code with main method throwing the exception below ``` public static void main(String[] args) throws Exception { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR", 5)); } ``` #### Output ``` Exception in thread "main" java.lang.Exception: Currencies don't match at com.in28minutes.exceptionhandling.AmountAdder.addAmounts(ExceptionHandlingExample2.java:17) at com.in28minutes.exceptionhandling.ExceptionHandlingExample2.main(ExceptionHandlingExample2.java:28) ``` #### Handling an Exception main can also handle the exception instead of declaring throws. Code for it below. ``` public static void main(String[] args) { try { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR",5)); } catch (Exception e) { System.out.println("Exception Handled in Main"); } } ``` #### Output ``` Exception Handled in Main ``` #### Custom Defined Exception Classes For the scenario above we can create a customized exception, CurrenciesDoNotMatchException. If we want to make it a Checked Exception, we can make it extend Exception class. Otherwise, we can extend RuntimeException class. #### Extending Exception Class ``` class CurrenciesDoNotMatchException extends Exception{ } ``` No we can change the method addAmounts to throw CurrenciesDoNotMatchException - even the declaration of the method changed. ``` class AmountAdder { static Amount addAmounts(Amount amount1, Amount amount2) throws CurrenciesDoNotMatchException { if (!amount1.currency.equals(amount2.currency)) { throw new CurrenciesDoNotMatchException(); } return new Amount(amount1.currency, amount1.amount + amount2.amount); } } ``` main method needs to be changed to catch: CurrenciesDoNotMatchException ``` public class ExceptionHandlingExample2 { public static void main(String[] args) { try { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR", 5)); } catch (CurrenciesDoNotMatchException e) { System.out.println("Exception Handled in Main" + e.getClass()); } } } ``` Output: ``` Exception Handled in Mainclass com.in28minutes.exceptionhandling.CurrenciesDoNotMatchException ``` Let's change main method to handle Exception instead of CurrenciesDoNotMatchException ``` public class ExceptionHandlingExample2 { public static void main(String[] args) { try { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR",5)); } catch (Exception e) { System.out.println("Exception Handled in Main" + e.getClass()); } } } ``` Output: ``` Exception Handled in Mainclass com.in28minutes.exceptionhandling.CurrenciesDoNotMatchException ``` There is no change in output from the previous example. This is because Exception catch block can catch Exception and all subclasses of Exception. #### Extend RuntimeException Let's change the class CurrenciesDoNotMatchException to extend RuntimeException instead of Exception ``` class CurrenciesDoNotMatchException extends RuntimeException{ } ``` Output: ``` Exception Handled in Mainclass com.in28minutes.exceptionhandling.CurrenciesDoNotMatchException ``` Change methods addAmounts in AmountAdder to remove the declaration " throws CurrenciesDoNotMatchException" No compilation error occurs since RuntimeException and subclasses of RuntimeException are not Checked Exception's. So, they don't need to be handled or declared. If you are interested in handling them, go ahead and handle them. But, java does not require you to handle them. Remove try catch from main method. It is not necessary since CurrenciesDoNotMatchException is now a RuntimeException. ``` public class ExceptionHandlingExample2 { public static void main(String[] args) { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR", 5)); } } ``` Output: ``` Exception in thread "main" com.in28minutes.exceptionhandling.CurrenciesDoNotMatchException at com.in28minutes.exceptionhandling.AmountAdder.addAmounts(ExceptionHandlingExample2.java:21) at com.in28minutes.exceptionhandling.ExceptionHandlingExample2.main(ExceptionHandlingExample2.java:30) ``` #### Multiple Catch Blocks Now, let's add two catch blocks to the main ``` public class ExceptionHandlingExample2 { public static void main(String[] args) { try { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR", 5)); } catch (CurrenciesDoNotMatchException e) { System.out.println("Handled CurrenciesDoNotMatchException"); } catch (Exception e) { System.out.println("Handled Exception"); } } } ``` Output: ``` Handled CurrenciesDoNotMatchException ``` We can have two catch blocks for a try. Order of Handling of exceptions: a. Same Class b. Super Class. #### Specific Exceptions before Generic Exceptions Specific Exception catch blocks should be before the catch block for a Generic Exception. For example, CurrenciesDoNotMatchException should be before Exception. Below code gives a compilation error. ``` public static void main(String[] args) { try { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("DOLLAR", 5)); } catch (Exception e) { // COMPILER ERROR!! System.out.println("Handled Exception"); } catch (CurrenciesDoNotMatchException e) { System.out.println("Handled CurrenciesDoNotMatchException"); } } ``` #### Catch block handles only specified Exceptions (and sub types) A catch block of type ExceptionType can only catch types ExceptionType and sub classes of ExceptionType. For Example: Let us change the main method code as shown below. Main method throws a NullPointerException. ``` public static void main(String[] args) { try { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("RUPEE", 5)); String string = null; string.toString(); } catch (CurrenciesDoNotMatchException e) { System.out.println("Handled CurrenciesDoNotMatchException"); } } //Output : Exception in thread "main" java.lang.NullPointerException at com.in28minutes.exceptionhandling.ExceptionHandlingExample2.main(ExceptionHandlingExample2.java:34) ``` Since NullPointerException is not a sub class of CurrenciesDoNotMatchException it wouldn't be handled by the catch block. Instead a NullPointerException would be thrown out by the main method. #### Exception Handling Best Practices In all above examples we have not followed an Exception Handling good practice(s). Never Completely Hide Exceptions. At the least log them. printStactTrace method prints the entire stack trace when an exception occurs. If you handle an exception, it is always a good practice to log the trace. ``` public static void main(String[] args) { try { AmountAdder.addAmounts(new Amount("RUPEE", 5), new Amount("RUPEE", 5)); String string = null; string.toString(); } catch (CurrenciesDoNotMatchException e) { System.out.println("Handled CurrenciesDoNotMatchException"); e.printStackTrace(); } } ``` ### Console - Console is used to read input from keyboard and write output. #### Getting a Console reference ``` //Console console = new Console(); //COMPILER ERROR Console console = System.console(); ``` #### Console utility methods ``` console.printf("Enter a Line of Text"); String text = console.readLine(); console.printf("Enter a Password"); ``` Password doesn't show what is being entered ``` char[] password = console.readPassword(); console.format("\nEntered Text is %s", text); ``` ### Format or Printf - Format or Printf functions help us in printing formatted output to the console. #### Format/Printf Examples Let's look at a few examples to quickly understand printf function. ``` System.out.printf("%d", 5);//5 System.out.printf("My name is %s", "Rithu");//My name is Rithu System.out.printf("%s is %d Years old", "Rithu", 5);//Rithu is 5 Years old ``` In the simplest form, string to be formatted starts with % followed by conversion indicator => b - boolean c - char d - integer f - floating point s - string. #### Other Format/Printf Examples ``` //Prints 12 using minimum 5 character spaces. System.out.printf("|%5d|", 12); //prints | 12| //Prints 1234 using minimum 5 character spaces. System.out.printf("|%5d|", 1234); //prints | 1234| //In above example 5 is called width specifier. //Left Justification can be done by using - System.out.printf("|%-5d|", 12); //prints |12 | //Using 0 pads the number with 0's System.out.printf("%05d", 12); //prints 00012 //Using , format the number using comma's System.out.printf("%,d", 12345); //prints 12,345 //Using ( prints negative numbers between ( and ) System.out.printf("%(d", -12345); //prints (12345) System.out.printf("%(d", 12345); //prints 12345 //Using + prints + or - before the number System.out.printf("%+d", -12345); //prints -12345 System.out.printf("%+d", 12345); //prints +12345 ``` For floating point numbers, precision can be specified after dot(.). Below example uses a precision of 2, so .5678 gets changed to .57 ``` System.out.printf("%5.2f", 1234.5678); //prints 1234.57 ``` An error in specifying would give a RuntimeException. In below example a string is passed to %d argument. ``` System.out.printf("%5d","Test"); //Throws java.util.IllegalFormatConversionException //To change the order of printing and passing of arguments, argument index can be used System.out.printf("%3$.1f %2$s %1$d", 123, "Test", 123.4); //prints 123.4 Test 123 //format method has the same behavior as printf method System.out.format("%5.2f", 1234.5678);//prints 1234.57 ``` ### String Buffer & String Builder - StringBuffer and StringBuilder are used when you want to modify values of a string frequently. String Buffer class is thread safe where as String Builder is NOT thread safe. #### String Buffer Examples ``` StringBuffer stringbuffer = new StringBuffer("12345"); stringbuffer.append("6789"); System.out.println(stringbuffer); //123456789 //All StringBuffer methods modify the value of the object. ``` #### String Builder Examples ``` StringBuilder sb = new StringBuilder("0123456789"); //StringBuilder delete(int startIndex, int endIndexPlusOne) System.out.println(sb.delete(3, 7));//012789 StringBuilder sb1 = new StringBuilder("abcdefgh"); //StringBuilder insert(int indext, String whatToInsert) System.out.println(sb1.insert(3, "ABCD"));//abcABCDdefgh StringBuilder sb2 = new StringBuilder("abcdefgh"); //StringBuilder reverse() System.out.println(sb2.reverse());//hgfedcba ``` Similar functions exist in StringBuffer also. #### Method Chaining All functions also return a reference to the object after modifying it.This allows a concept called method chaining. ``` StringBuilder sb3 = new StringBuilder("abcdefgh"); System.out.println(sb3.reverse().delete(5, 6).insert(3, "---"));//hgf---edba ``` ### Date - Date is no longer the class Java recommends for storing and manipulating date and time. Most of methods in Date are deprecated. Use Calendar class instead. Date internally represents date-time as number of milliseconds (a long value) since 1st Jan 1970. #### Creating Date Object ``` //Creating Date Object Date now = new Date(); System.out.println(now.getTime()); ``` #### Manipulating Date Object Lets now look at adding a few hours to a date object. All date manipulation to date needs to be done by adding milliseconds to the date. For example, if we want to add 6 hour, we convert 6 hours into millseconds. 6 hours = 6 * 60 * 60 * 1000 milliseconds. Below examples shows specific code. ``` Date date = new Date(); //Increase time by 6 hrs date.setTime(date.getTime() + 6 * 60 * 60 * 1000); System.out.println(date); //Decrease time by 6 hrs date = new Date(); date.setTime(date.getTime() - 6 * 60 * 60 * 1000); System.out.println(date); ``` #### Formatting Dates Formatting Dates is done by using DateFormat class. Let's look at a few examples. ``` //Formatting Dates System.out.println(DateFormat.getInstance().format( date));//10/16/12 5:18 AM ``` Formatting Dates with a locale ``` System.out.println(DateFormat.getDateInstance( DateFormat.FULL, new Locale("it", "IT")) .format(date));//martedÒ 16 ottobre 2012 System.out.println(DateFormat.getDateInstance( DateFormat.FULL, Locale.ITALIAN) .format(date));//martedÒ 16 ottobre 2012 //This uses default locale US System.out.println(DateFormat.getDateInstance( DateFormat.FULL).format(date));//Tuesday, October 16, 2012 System.out.println(DateFormat.getDateInstance() .format(date));//Oct 16, 2012 System.out.println(DateFormat.getDateInstance( DateFormat.SHORT).format(date));//10/16/12 System.out.println(DateFormat.getDateInstance( DateFormat.MEDIUM).format(date));//Oct 16, 2012 System.out.println(DateFormat.getDateInstance( DateFormat.LONG).format(date));//October 16, 2012 ``` #### Format Date's using SimpleDateFormat Let's look at a few examples of formatting dates using SimpleDateFormat. ``` System.out.println(new SimpleDateFormat("yy-MM-dd") .format(date));//12-10-16 System.out .println(new SimpleDateFormat("yy-MMM-dd") .format(date));//12-Oct-16 System.out.println(new SimpleDateFormat( "yyyy-MM-dd").format(date));//2012-10-16 //Parse Dates using DateFormat Date date2 = DateFormat.getDateInstance( DateFormat.SHORT).parse("10/16/12"); System.out.println(date2);//Tue Oct 16 00:00:00 GMT+05:30 2012 //Creating Dates using SimpleDateFormat Date date1 = new SimpleDateFormat("yy-MM-dd") .parse("12-10-16"); System.out.println(date1);//Tue Oct 16 00:00:00 GMT+05:30 2012 ``` #### Default Locale ``` Locale defaultLocale = Locale.getDefault(); System.out.println(defaultLocale .getDisplayCountry());//United States System.out.println(defaultLocale .getDisplayLanguage());//English ``` ### Calendar - Calendar class is used in Java to manipulate Dates. Calendar class provides easy ways to add or reduce days, months or years from a date. It also provide lot of details about a date (which day of the year? Which week of the year? etc.) #### Calendar is abstract Calendar class cannot be created by using new Calendar. The best way to get an instance of Calendar class is by using getInstance() static method in Calendar. ``` //Calendar calendar = new Calendar(); //COMPILER ERROR Calendar calendar = Calendar.getInstance(); ``` #### Calendar set day, month and year Setting day, month or year on a calendar object is simple. Call the set method with appropriate Constant for Day, Month or Year. Next parameter is the value. ``` calendar.set(Calendar.DATE, 24); calendar.set(Calendar.MONTH, 8);//8 - September calendar.set(Calendar.YEAR, 2010); ``` #### Calendar get method Let's get information about a particular date - 24th September 2010. We use the calendar get method. The parameter passed indicates what value we would want to get from the calendar , day or month or year or .. Few examples of the values you can obtain from a calendar are listed below. ``` System.out.println(calendar.get(Calendar.YEAR));//2010 System.out.println(calendar.get(Calendar.MONTH));//8 System.out.println(calendar.get(Calendar.DATE));//24 System.out.println(calendar.get(Calendar.WEEK_OF_MONTH));//4 System.out.println(calendar.get(Calendar.WEEK_OF_YEAR));//39 System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//267 System.out.println(calendar.getFirstDayOfWeek());//1 -> Calendar.SUNDAY ``` #### Calendar - Modify a Date We can use the calendar add and roll methods to modify a date. Calendar add method can be used to find a date 5 days or 5 months before the date by passing a ,5 i.e. a negative 5. ``` calendar.add(Calendar.DATE, 5); System.out.println(calendar.getTime());//Wed Sep 29 2010 calendar.add(Calendar.MONTH, 1); System.out.println(calendar.getTime());//Fri Oct 29 2010 calendar.add(Calendar.YEAR, 2); System.out.println(calendar.getTime());//Mon Oct 29 2012 ``` #### Roll method Roll method will only the change the value being modified. YEAR remains unaffected when MONTH is changed, for instance. ``` calendar.roll(Calendar.MONTH, 5); System.out.println(calendar.getTime());//Mon Mar 29 2012 ``` #### Creating calendar: Example 2 ``` Calendar gregorianCalendar = new GregorianCalendar( 2011, 7, 15); ``` #### Formatting Calendar object. Done by getting the date using calendar.getTime() and using the usual formatting of dates. ``` System.out.println(DateFormat.getInstance().format( calendar.getTime()));//3/29/12 11:39 AM ``` ### Number Format - Number format is used to format a number to different locales and different formats. #### Format number Using Default locale ``` System.out.println(NumberFormat.getInstance().format(321.24f));//321.24 ``` #### Format number using locale Formatting a number using Netherlands locale ``` System.out.println(NumberFormat.getInstance(new Locale("nl")).format(4032.3f));//4.032,3 ``` Formatting a number using Germany locale ``` System.out.println(NumberFormat.getInstance(Locale.GERMANY).format(4032.3f));//4.032,3 ``` #### Formatting a Currency using Default locale ``` System.out.println(NumberFormat.getCurrencyInstance().format(40324.31f));//$40,324.31 ``` #### Format currency using locale ``` Formatting a Currency using Netherlands locale System.out.println(NumberFormat.getCurrencyInstance(new Locale("nl")).format(40324.31f));//? 40.324,31 ``` Setting maximum fraction digits for a float ``` NumberFormat numberFormat = NumberFormat.getInstance(); System.out.println(numberFormat.getMaximumFractionDigits());//3 numberFormat.setMaximumFractionDigits(5); System.out.println(numberFormat.format(321.24532f));//321.24533 ``` #### Parsing using NumberFormat Parsing a float value using number format ``` System.out.println(numberFormat.parse("9876.56"));//9876.56 ``` Parsing only number value using number format ``` numberFormat.setParseIntegerOnly(true); System.out.println(numberFormat.parse("9876.56"));//9876 ``` ### Collection Interfaces - Arrays are not dynamic. Once an array of a particular size is declared, the size cannot be modified. To add a new element to the array, a new array has to be created with bigger size and all the elements from the old array copied to new array. Collections are used in situations where data is dynamic. Collections allow adding an element, deleting an element and host of other operations. There are a number of Collections in Java allowing to choose the right Collection for the right context. Before looking into Collection classes, let's take a quick look at all the important collection interfaces and the operations they allow. #### Collection Interface Most important methods declared in the collection interface are the methods to add and remove an element. add method allows adding an element to a collection and delete method allows deleting an element from a collection. size() methods returns number of elements in the collection. Other important methods defined as part of collection interface are shown below. ``` interface Collection extends Iterable { boolean add(E paramE); boolean remove(Object paramObject); int size(); boolean isEmpty(); void clear(); boolean contains(Object paramObject); boolean containsAll(Collection paramCollection); boolean addAll(Collection paramCollection); boolean removeAll(Collection paramCollection); boolean retainAll(Collection paramCollection); Iterator iterator(); //A NUMBER OF OTHER METHODS AS WELL.. } ``` #### List Interface List interface extends Collection interface. So, it contains all methods defined in the Collection interface. In addition, List interface allows operation specifying the position of the element in the Collection. Any implementation of the List interface would maintain the insertion order. When a new element is inserted, it is inserted at the end of the list of elements. We can also use the void add(int paramInt, E paramE); method to insert an element at a specific position. We can also set and get the elements at a particular index in the list using corresponding methods. Other important methods are listed below: ``` interface List extends Collection { boolean addAll(int paramInt, Collection paramCollection); E get(int paramInt); E set(int paramInt, E paramE); void add(int paramInt, E paramE); E remove(int paramInt); int indexOf(Object paramObject); int lastIndexOf(Object paramObject); ListIterator listIterator(); ListIterator listIterator(int paramInt); List subList(int paramInt1, int paramInt2); } ``` #### Map Interface First and foremost, Map interface does not extend Collection interface. So, it does not inherit any of the methods from the Collection interface. A Map interface supports Collections that use a key value pair. A key-value pair is a set of linked data items: a key, which is a unique identifier for some item of data, and the value, which is either the data or a pointer to the data. Key-value pairs are used in lookup tables, hash tables and configuration files. A key value pair in a Map interface is called an Entry. Put method allows to add a key, value pair to the Map. ``` V put(K paramK, V paramV); ``` Get method allows to get a value from the Map based on the key. ``` V get(Object paramObject); ``` Other important methods are shown below: ``` interface Map { int size(); boolean isEmpty(); boolean containsKey(Object paramObject); boolean containsValue(Object paramObject); V get(Object paramObject); V put(K paramK, V paramV); V remove(Object paramObject); void putAll(Map paramMap); void clear(); Set keySet(); Collection values(); Set> entrySet(); boolean equals(Object paramObject); int hashCode(); public static abstract interface Entry { K getKey(); V getValue(); V setValue(V paramV); boolean equals(Object paramObject); int hashCode(); } } ``` #### Set Interface Set Interface extends Collection Interface. Set interface only contains the methods from the Collection interface with added restriction that it cannot contain duplicates. ``` // Unique things only - Does not allow duplication. // If obj1.equals(obj2) then only one of them can be in the Set. interface Set extends Collection { } ``` #### SortedSet Interface SortedSet Interface extends the Set Interface. So, it does not allow duplicates. In addition, an implementation of SortedSet interface maintains its elements in a sorted order. It adds operations that allow getting a range of values (subSet, headSet, tailSet). Important Operations listed below: ``` public interface SortedSet extends Set { SortedSet subSet(E fromElement, E toElement); SortedSet headSet(E toElement); SortedSet tailSet(E fromElement); E first(); E last(); Comparator comparator(); } ``` #### SortedMap Interface SortedMap interface extends the Map interface. In addition, an implementation of SortedMap interface maintains keys in a sorted order. Methods are available in the interface to get a ranges of values based on their keys. ``` public interface SortedMap extends Map { Comparator comparator(); SortedMap subMap(K fromKey, K toKey); SortedMap headMap(K toKey); SortedMap tailMap(K fromKey); K firstKey(); K lastKey(); } ``` #### Queue Interface Queue Interface extends Collection interface. Queue Interface is typically used for implementation holding elements in order for some processing. Queue interface offers methods peek() and poll() which get the element at head of the queue. The difference is that poll() method removes the head from queue also. peek() would keep head of the queue unchanged. ``` interface Queue extends Collection { boolean offer(E paramE); E remove(); E poll(); E element(); E peek(); } ``` #### Iterator interface Iterator interface enables us to iterate (loop around) a collection. All collections define a method iterator() that gets an iterator of the collection. hasNext() checks if there is another element in the collection being iterated. next() gets the next element. ``` public interface Iterator { boolean hasNext(); E next(); } ``` ### Collections - Collections can only hold Objects - not primitives. #### ArrayList ArrayList implements the list interface. So, ArrayList stores the elements in insertion order (by default). Element's can be inserted into and removed from ArrayList based on their position. Let's look at how to instantiate an ArrayList of integers. ``` List integers = new ArrayList(); ``` Code like below is permitted because of auto boxing. 5 is auto boxed into Integer object and stored in ArrayList. ``` integers.add(5);//new Integer(5) ``` Add method (by default) adds the element at the end of the list. #### ArrayList of String Example Below example shows how to create and use a String ArrayList. ArrayList can have duplicates (since List can have duplicates). size() method gets number of elements in the ArrayList. contains(Object) method checks if an element is present in the arraylist. ``` List arraylist = new ArrayList(); //adds at the end of list arraylist.add("Sachin");//[Sachin] //adds at the end of list arraylist.add("Dravid");//[Sachin, Dravid] //adds at the index 0 arraylist.add(0, "Ganguly");//[Ganguly, Sachin, Dravid] //List allows duplicates - Sachin is present in the list twice arraylist.add("Sachin");//[ Ganguly, Sachin, Dravid, Sachin] System.out.println(arraylist.size());//4 System.out.println(arraylist.contains("Dravid"));//true ``` #### Iterating around a list ``` Iterator arraylistIterator = arraylist .iterator(); while (arraylistIterator.hasNext()) { String str = arraylistIterator.next(); System.out.println(str);//Prints the 4 names in the list on separate lines. } ``` #### Other ArrayList (List) methods indexOf() function - returns index of element if element is found. Negative number otherwise. ``` //example1 - value is present System.out.println(arraylist.indexOf("Dravid"));//2 //example2 - value is not present System.out.println(arraylist.indexOf("Bradman"));//-1 ``` get() function - get value at specified index. ``` System.out.println(arraylist.get(1));//Sachin ``` #### remove() function remove() function has two variations. ``` //Using the object as parameter //Dravid is removed from the list arraylist.remove("Dravid");//[Ganguly, Sachin, Sachin] //Using index as argument. //Object at index 1 (Sachin) is removed arraylist.remove(1);//[Ganguly, Sachin] ``` #### Sorting Collections ``` List numbers = new ArrayList(); numbers.add("one"); numbers.add("two"); numbers.add("three"); numbers.add("four"); System.out.println(numbers);//[one, two, three, four] //Strings - By Default - are sorted alphabetically Collections.sort(numbers); System.out.println(numbers);//[four, one, three, two] ``` #### List of Objects of a Custom Class Consider the following class Cricketer. ``` class Cricketer{ int runs; String name; public Cricketer(String name, int runs) { super(); this.name = name; this.runs = runs; } @Override public String toString() { return name + " " + runs; } } ``` Let's now try to sort a list containing objects of Cricketer class. ``` List cricketers = new ArrayList(); cricketers.add(new Cricketer("Bradman", 9996)); cricketers.add(new Cricketer("Sachin", 14000)); cricketers.add(new Cricketer("Dravid", 12000)); cricketers.add(new Cricketer("Ponting", 11000)); System.out.println(cricketers); //[Bradman 9996, Sachin 14000, Dravid 12000, Ponting 11000] //Cricketer class does not implement Comparable Interface //Collections.sort(cricketers); //COMPILER ERROR ``` We get a compiler error since Cricketer class does not implement Comparable interface. We were able to sort numbers in earlier example because String class implements Comparable. Let's make the Cricketer class implement the Comparable Interface. ``` class Cricketer implements Comparable { //OTHER CODE/PROGRAM same as previous //compareTo takes an argument of the same type of the class //compareTo returns -1 if this < that // 1 if this > that // 0 if this = that @Override public int compareTo(Cricketer that) { if (this.runs > that.runs) { return 1; } if (this.runs < that.runs) { return -1; } return 0; } } ``` Now let's try to sort the cricketers. ``` Collections.sort(cricketers); System.out.println(cricketers); //[Bradman 9996, Ponting 11000, Dravid 12000, Sachin 14000] ``` Other option to sort collections is by creating a separate class which implements Comparator interface. Example below: ``` class DescendingSorter implements Comparator { //compareTo returns -1 if cricketer1 < cricketer2 // 1 if cricketer1 > cricketer2 // 0 if cricketer1 = cricketer2 //Since we want to sort in descending order, //we should return -1 when runs are more @Override public int compare(Cricketer cricketer1, Cricketer cricketer2) { if (cricketer1.runs > cricketer2.runs) { return -1; } if (cricketer1.runs < cricketer2.runs) { return 1; } return 0; } } ``` Let's now try to sort the previous defined collection: ``` Collections .sort(cricketers, new DescendingSorter()); System.out.println(cricketers); //[Sachin 14000, Dravid 12000, Ponting 11000, Bradman 9996] ``` #### Convert List to Array There are two ways. First is to use toArray(String) function. Example below. This creates an array of String's ``` List numbers1 = new ArrayList(); numbers1.add("one"); numbers1.add("two"); numbers1.add("three"); numbers1.add("four"); String[] numbers1Array = new String[numbers1.size()]; numbers1Array = numbers1.toArray(numbers1Array); System.out.println(Arrays.toString(numbers1Array)); //prints [one, two, three, four] ``` Other is to use toArray() function. Example below. This creates an array of Objects. ``` Object[] numbers1ObjArray = numbers1.toArray(); System.out.println(Arrays .toString(numbers1ObjArray)); //[one, two, three, four] ``` #### Convert Array to List ``` String values[] = { "value1", "value2", "value3" }; List valuesList = Arrays.asList(values); System.out.println(valuesList);//[value1, value2, value3] ``` #### Other List interface implementations Other classes that implement List interface are Vector and LinkedList. #### Vector Vector has the same operations as an ArrayList. However, all methods in Vector are synchronized. So, we can use Vector if we share a list between two threads and we would want to them synchronized. #### LinkedList Linked List extends List and Queue.Other than operations exposed by the Queue interface, LinkedList has the same operations as an ArrayList. However, the underlying implementation of Linked List is different from that of an ArrayList. ArrayList uses an Array kind of structure to store elements. So, inserting and deleting from an ArrayList are expensive operations. However, search of an ArrayList is faster than LinkedList. LinkedList uses a linked representation. Each object holds a link to the next element. Hence, insertion and deletion are faster than ArrayList. But searching is slower. ### Set Interface - HashSet, LinkedHashSet and TreeSet implement the Set interface. Let's look at examples of these collection classes. #### HashSet HashSet implements set interface. Sets do not allow duplicates. HashSet does not support ordering. #### HashSet Example ``` Set hashset = new HashSet(); hashset.add("Sachin"); System.out.println(hashset);//[Sachin] hashset.add("Dravid"); System.out.println(hashset);//[Sachin, Dravid] ``` Let's try to add Sachin to the Set now. Sachin is Duplicate. So will not be added. returns false. ``` hashset.add("Sachin");//returns false since element is not added System.out.println(hashset);//[Sachin, Dravid] ``` #### LinkedHashSet LinkedHashSet implements set interface and exposes similar operations to a HashSet. Difference is that LinkedHashSet maintains insertion order. When we iterate a LinkedHashSet, we would get the elements back in the order in which they were inserted. #### TreeSet TreeSet implements Set, SortedSet and NavigableSet interfaces.TreeSet is similar to HashSet except that it stores element's in Sorted Order. ``` Set treeSet = new TreeSet(); treeSet.add("Sachin"); System.out.println(treeSet);//[Sachin] ``` Notice that the list is sorted after inserting Dravid. ``` //Alphabetical order treeSet.add("Dravid"); System.out.println(treeSet);//[Dravid, Sachin] ``` Notice that the list is sorted after inserting Ganguly. ``` treeSet.add("Ganguly"); System.out.println(treeSet);//[Dravid, Ganguly, Sachin] //Sachin is Duplicate. So will not be added. returns false. treeSet.add("Sachin");//returns false since element is not added System.out.println(treeSet);//[Dravid, Ganguly, Sachin] ``` Objects that are inserted into a TreeSet should be comparable. #### TreeSet - NavigableSet interface examples 1 TreeSet implements this interface. Let's look at an example with TreeSet. Note that elements in TreeSet are sorted. ``` TreeSet numbersTreeSet = new TreeSet(); numbersTreeSet.add(55); numbersTreeSet.add(25); numbersTreeSet.add(35); numbersTreeSet.add(5); numbersTreeSet.add(45); ``` NavigableSet interface has following methods. Lower method finds the highest element lower than specified element. Floor method finds the highest element lower than or equal to specified element. Corresponding methods for finding lowest number higher than specified element are higher and ceiling. A few examples using the Set created earlier below. ``` //Find the highest number which is lower than 25 System.out.println(numbersTreeSet.lower(25));//5 //Find the highest number which is lower than or equal to 25 System.out.println(numbersTreeSet.floor(25));//25 //Find the lowest number higher than 25 System.out.println(numbersTreeSet.higher(25));//35 //Find the lowest number higher than or equal to 25 System.out.println(numbersTreeSet.ceiling(25));//25 ``` #### NavigableSet subSet,headSet,tailSet Methods in TreeSet ``` TreeSet exampleTreeSet = new TreeSet(); exampleTreeSet.add(55); exampleTreeSet.add(25); exampleTreeSet.add(105); exampleTreeSet.add(35); exampleTreeSet.add(5); System.out.println(exampleTreeSet);//[5, 25, 35, 55, 105] ``` All the three methods - subSet,headSet,tailSet - are inclusive with Lower Limit and NOT inclusive with higher limit. In the sub set below, Lower Limit is inclusive - 25 included. Higher limit is not inclusive - 55 excluded. ``` //Get sub set with values >=25 and <55 SortedSet subTreeSet = exampleTreeSet .subSet(25, 55); System.out.println(subTreeSet);//[25, 35] ``` In the sub set below, Higher limit not inclusive - 55 excluded. ``` //Get sub set with values <55 SortedSet headTreeSet = exampleTreeSet .headSet(55); System.out.println(headTreeSet);//[5, 25, 35] //Get sub set with values >=35 SortedSet tailTreeSet = exampleTreeSet .tailSet(35); System.out.println(tailTreeSet);//[35, 55, 105] //In the sub set, Lower limit inclusive - 35 included. //Get sub set with value >=25 and <=55 (both inclusive parameters - true) SortedSet subTreeSetIncl = exampleTreeSet .subSet(25, true, 55, true); System.out.println(subTreeSetIncl);//[25, 35, 55] //Get sub set with value >25 and <55 (both inclusive parameters - false) SortedSet subTreeSetNotIncl = exampleTreeSet .subSet(25, false, 55, false); System.out.println(subTreeSetNotIncl);//[35] //Get sub set with values <=55. Inclusive set to true. SortedSet headTreeSetIncl = exampleTreeSet .headSet(55, true); System.out.println(headTreeSetIncl);//[5, 25, 35, 55] //Get sub set with values >35. Inclusive set to false. SortedSet tailTreeSetNotIncl = exampleTreeSet .tailSet(35, false); System.out.println(tailTreeSetNotIncl);//[55, 105] ``` All the sub set methods - subSet,headSet,tailSet - return dynamic sub sets. When original set is modified (addition or deletion), corresponding changes can affect the sub sets as well. ``` System.out.println(exampleTreeSet);//[5, 25, 35, 55, 105] System.out.println(subTreeSet);//[25, 35] System.out.println(headTreeSet);//[5, 25, 35] System.out.println(tailTreeSet);//[35, 55, 105] ``` Let's now insert a value 30 into the exampleTreeSet. Remember that subTreeSet, headTreeSet, tailTreeSet are sub sets of exampleTreeSet. ``` exampleTreeSet.add(30); System.out.println(exampleTreeSet);//[5, 25, 30, 35, 55, 105] System.out.println(subTreeSet);//[25, 30, 35] System.out.println(headTreeSet);//[5, 30, 25, 35] System.out.println(tailTreeSet);//[35, 55, 105] ``` 30 is in the range of subTreeSet and headTreeSet. So, it is printed as part of exampleTreeSet, subTreeSet and headTreeSet. ``` //Let's now add 65 to the set exampleTreeSet.add(65); System.out.println(exampleTreeSet);//[5, 25, 30, 35, 55, 65, 105] System.out.println(subTreeSet);//[25, 30, 35] System.out.println(headTreeSet);//[5, 30, 25, 35] System.out.println(tailTreeSet);//[35, 55, 65, 105] ``` 65 is printed as part of exampleTreeSet and tailTreeSet. Key thing to remember is that all the sub sets are dynamic. If you modify the original set,the sub set might be affected. #### TreeSet - NavigableSet interface methods - pollFirst, pollLast and more ``` TreeSet treeSetOrig = new TreeSet(); treeSetOrig.add(55); treeSetOrig.add(25); treeSetOrig.add(35); treeSetOrig.add(5); System.out.println(treeSetOrig);//[5, 25, 35, 55] //descendingSet method returns the tree set in reverse order TreeSet treeSetDesc = (TreeSet) treeSetOrig .descendingSet(); System.out.println(treeSetDesc);//[55, 35, 25, 5] ``` pollFirst returns the first element and removes it from the set. ``` System.out.println(treeSetOrig);//[5, 25, 35, 55] System.out.println(treeSetOrig.pollFirst());//5 System.out.println(treeSetOrig);//[25, 35, 55] //In above example element 5 is removed from the set and also removed from the tree set. ``` pollLast returns the last element and removes it from the set. ``` System.out.println(treeSetOrig);//[25, 35, 55] System.out.println(treeSetOrig.pollLast());//55 System.out.println(treeSetOrig);//[25, 35] ``` ### Map Interface - Let's take a look at different implementations of the Map interface. #### HashMap HashMap implements Map interface , there by supporting key value pairs. #### HashMap Example ``` Map hashmap = new HashMap(); hashmap.put("sachin", new Cricketer("Sachin", 14000)); hashmap.put("dravid", new Cricketer("Dravid", 12000)); hashmap.put("ponting", new Cricketer("Ponting", 11500)); hashmap.put("bradman", new Cricketer("Bradman", 9996)); ``` #### Hash Map Methods get method gets the value of the matching key. ``` System.out.println(hashmap.get("ponting"));//Ponting 11500 //if key is not found, returns null. System.out.println(hashmap.get("lara"));//null ``` If existing key is reused, it would replace existing value with the new value passed in. ``` //In the example below, an entry with key "ponting" is already present. //Runs are updated to 11800. hashmap.put("ponting", new Cricketer("Ponting", 11800)); //gets the recently updated value System.out.println(hashmap.get("ponting"));//Ponting 11800 ``` #### TreeMap TreeMap is similar to HashMap except that it stores keys in sorted order. It implements NavigableMap interface and SortedMap interfaces along with the Map interface. ``` Map treemap = new TreeMap(); treemap.put("sachin", new Cricketer("Sachin", 14000)); System.out.println(treemap); //{sachin=Sachin 14000} ``` We will now insert a Cricketer with key dravid. In sorted order,dravid comes before sachin. So, the value with key dravid is inserted at the start of the Map. ``` treemap.put("dravid", new Cricketer("Dravid", 12000)); System.out.println(treemap); //{dravid=Dravid 12000, sachin=Sachin 14000} ``` We will now insert a Cricketer with key ponting. In sorted order, ponting fits in between dravid and sachin. ``` treemap.put("ponting", new Cricketer("Ponting", 11500)); System.out.println(treemap); //{dravid=Dravid 12000, ponting=Ponting 11500, sachin=Sachin 14000} treemap.put("bradman", new Cricketer("Bradman", 9996)); System.out.println(treemap); //{bradman=Bradman 9996, dravid=Dravid 12000, ponting=Ponting 11500, sachin=Sachin 14000} ``` #### NavigableMap Interface Examples (TreeMap) Set I Let's look at an example with TreeMap. Note that keys in TreeMap are sorted. ``` TreeMap numbersTreeMap = new TreeMap(); numbersTreeMap.put(55, new Cricketer("Sachin", 14000)); numbersTreeMap.put(25, new Cricketer("Dravid", 12000)); numbersTreeMap.put(35, new Cricketer("Ponting", 12000)); numbersTreeMap.put(5, new Cricketer("Bradman", 9996)); numbersTreeMap .put(45, new Cricketer("Lara", 10000)); ``` lowerKey method finds the highest key lower than specified key. floorKey method finds the highest key lower than or equal to specified key. Corresponding methods for finding lowest key higher than specified key are higher and ceiling. A few examples using the Map created earlier below. ``` //Find the highest key which is lower than 25 System.out.println(numbersTreeMap.lowerKey(25));//5 //Find the highest key which is lower than or equal to 25 System.out.println(numbersTreeMap.floorKey(25));//25 //Find the lowest key higher than 25 System.out.println(numbersTreeMap.higherKey(25));//35 //Find the lowest key higher than or equal to 25 System.out.println(numbersTreeMap.ceilingKey(25));//25 ``` #### NavigableMap Interface Examples (TreeMap) Set II Methods similar to subSet,headSet,tailSet (of TreeSet) are available in TreeMap as well. They are called subMap, headMap, tailMap.They have the similar signatures and results as the corresponding TreeSet Methods. They are inclusive with Lower Limit and NOT inclusive with higher limit - unless the (optional) inclusive flag is passed. The resultant sub map's are dynamic. If original map get modified, the sub map might be affected as well. ``` TreeMap exampleTreeMap = new TreeMap(); exampleTreeMap.put(55, new Cricketer("Sachin", 14000)); exampleTreeMap.put(25, new Cricketer("Dravid", 12000)); exampleTreeMap.put(5, new Cricketer("Bradman", 9996)); exampleTreeMap .put(45, new Cricketer("Lara", 10000)); //Lower limit (5) inclusive, Uppper Limit(25) NOT inclusive System.out.println(exampleTreeMap.subMap(5, 25));//{5=Bradman 9996} System.out.println(exampleTreeMap.headMap(30)); //{5=Bradman 9996, 25=Dravid 12000} System.out.println(exampleTreeMap.tailMap(25)); //{25=Dravid 12000, 45=Lara 10000, 55=Sachin 14000} ``` #### NavigableMap Interface Examples (TreeMap) Set III Consider the next set of method examples below: ``` TreeMap treeMapOrig = new TreeMap(); treeMapOrig.put(55, new Cricketer("Sachin", 14000)); treeMapOrig.put(25, new Cricketer("Dravid", 12000)); treeMapOrig.put(5, new Cricketer("Bradman", 9996)); treeMapOrig.put(45, new Cricketer("Lara", 10000)); System.out.println(treeMapOrig); //{5=Bradman 9996, 25=Dravid 12000, 45=Lara 10000, 55=Sachin 14000} ``` descendingMap method returns the tree set in reverse order. ``` NavigableMap treeMapDesc = treeMapOrig .descendingMap(); System.out.println(treeMapDesc); //{55=Sachin 14000, 45=Lara 10000, 25=Dravid 12000, 5=Bradman 9996} ``` pollFirstEntry returns the first entry in the map and removes it from the map. ``` System.out.println(treeMapOrig); //{5=Bradman 9996, 25=Dravid 12000, 45=Lara 10000, 55=Sachin 14000} System.out.println(treeMapOrig.pollFirstEntry());//5=Bradman 9996 System.out.println(treeMapOrig); //{25=Dravid 12000, 45=Lara 10000, 55=Sachin 14000} //In above example element 5 is removed from the set and also removed from the tree set. ``` pollLastEntry returns the last entry from the map and removes it from the map. ``` System.out.println(treeMapOrig); //{25=Dravid 12000, 45=Lara 10000, 55=Sachin 14000} System.out.println(treeMapOrig.pollLastEntry());//55=Sachin 14000 System.out.println(treeMapOrig); //{25=Dravid 12000, 45=Lara 10000} ``` ### PriorityQueue - PriorityQueue implements the Queue interface. #### PriorityQueue Example ``` //Using default constructor - uses natural ordering of numbers //Smaller numbers have higher priority PriorityQueue priorityQueue = new PriorityQueue(); ``` #### Adding an element into priority queue - offer method ``` priorityQueue.offer(24); priorityQueue.offer(15); priorityQueue.offer(9); priorityQueue.offer(45); System.out.println(priorityQueue);//[9, 24, 15, 45] ``` #### Peek method examples ``` //peek method get the element with highest priority. System.out.println(priorityQueue.peek());//9 //peek method does not change the queue System.out.println(priorityQueue);//[9, 24, 15, 45] //poll method gets the element with highest priority. System.out.println(priorityQueue.poll());//9 //peek method removes the highest priority element from the queue. System.out.println(priorityQueue);//[24, 15, 45] //This comparator gives high priority to the biggest number. Comparator reverseComparator = new Comparator() { public int compare(Integer paramT1, Integer paramT2) { return paramT2 - paramT1; } }; ``` #### Priority Queue and Comparator We can create priority queue using a comparator class i.e. custom defined priority. ``` PriorityQueue priorityQueueDesc = new PriorityQueue( 20, reverseComparator); priorityQueueDesc.offer(24); priorityQueueDesc.offer(15); priorityQueueDesc.offer(9); priorityQueueDesc.offer(45); //45 is the largest element. Our custom comparator gives priority to highest number. System.out.println(priorityQueueDesc.peek());//45 ``` #### Collections static methods ``` static int binarySearch(List, key) //Can be used only on sorted list static int binarySearch(List, key, Comparator) static void reverse(List)//Reverse the order of elements in a List. static Comparator reverseOrder(); //Return a Comparator that sorts the reverse of the collection current sort sequence. static void sort(List) static void sort(List, Comparator) ``` ### Generics - Generics are used to create Generic Classes and Generic methods which can work with different Types(Classes). #### Need for Generics , Example Consider the class below: ``` class MyList { private List values; void add(String value) { values.add(value); } void remove(String value) { values.remove(value); } } ``` MyList can be used to store a list of Strings only. ``` MyList myList = new MyList(); myList.add("Value 1"); myList.add("Value 2"); ``` To store integers, we need to create a new class. This is problem that Generics solve. Instead of hard-coding String class as the only type the class can work with, we make the class type a parameter to the class. #### Generics Example Let's replace String with T and create a new class. ``` class MyListGeneric { private List values; void add(T value) { values.add(value); } void remove(T value) { values.remove(value); } T get(int index) { return values.get(index); } } ``` Note the declaration of class: ``` class MyListGeneric ``` Instead of T, We can use any valid identifier If a generic is declared as part of class declaration, it can be used any where a type can be used in a class - method (return type or argument), member variable etc. For Example: See how T is used as a parameter and return type in the class MyListGeneric. Now the MyListGeneric class can be used to create a list of Integers or a list of Strings ``` MyListGeneric myListString = new MyListGeneric(); myListString.add("Value 1"); myListString.add("Value 2"); MyListGeneric myListInteger = new MyListGeneric(); myListInteger.add(1); myListInteger.add(2); ``` #### Generics Restrictions In MyListGeneric, Type T is defined as part of class declaration. Any Java Type can be used a type for this class. If we would want to restrict the types allowed for a Generic Type, we can use a Generic Restrictions. Consider the example class below: ``` class MyListRestricted { private List values; void add(T value) { values.add(value); } void remove(T value) { values.remove(value); } T get(int index) { return values.get(index); } } ``` In declaration of the class, we specified a constraint "T extends Number". We can use the class MyListRestricted with any class extending Number - Float, Integer, Double etc. ``` MyListRestricted restrictedListInteger = new MyListRestricted(); restrictedListInteger.add(1); restrictedListInteger.add(2); ``` String not valid substitute for constraint "T extends Number". ``` //MyListRestricted restrictedStringList = //new MyListRestricted();//COMPILER ERROR ``` #### Generic Method Example A generic type can be declared as part of method declaration as well. Then the generic type can be used anywhere in the method (return type, parameter type, local or block variable type). Consider the method below: ``` static X doSomething(X number){ X result = number; //do something with result return result; } ``` The method can now be called with any Class type extend Number. ``` Integer i = 5; Integer k = doSomething(i); ``` #### Generics and Collections Example 1 Consider the classes below: ``` class Animal { } class Dog extends Animal { } ``` Let's create couple of Arrays and Lists as shown below: ``` Animal[] animalsArray = { new Animal(), new Dog() }; Dog[] dogsArray = { new Dog(), new Dog() }; List animalsList = Arrays.asList(animalsArray); List dogsList = Arrays.asList(dogsArray); ``` Let's create a couple of static methods as shown below: ``` static void doSomethingArray(Animal[] animals) { //do Something with Animals } static void doSomethingList(List animals) { //do Something with Animals } ``` Array method can be called with Animal[] or Dog[] ``` doSomethingArray(animalsArray); doSomethingArray(dogsArray); ``` List method works with List. Gives compilation error with List. ``` doSomethingList(animalsList); //List not compatible with List //doSomethingList(dogsList);//COMPILER ERROR ``` Summary : List not compatible with List even thought Dog extends Animal. However, Dog[] is compatible with Animal[]. #### Generics and Collections Example 2 - extends Consider the methods below: ``` static void doSomethingListModified(List animals) { //Adding an element into a list declared with ? is prohibited. //animals.add(new Animal());//COMPILER ERROR! //animals.add(new Dog());//COMPILER ERROR! } ``` Method declared with List compiles with both List and List ``` doSomethingListModified(animalsList); doSomethingListModified(dogsList); ``` #### Generics and Collections Example 3 - Super Method declared with List compiles with both List and List. ``` static void doSomethingListModifiedSuper(List animals) { //Adding an element into a list declared with ? is prohibited. //animals.add(new Animal());//COMPILER ERROR! //animals.add(new Dog());//COMPILER ERROR! } ``` List of any super class of Dog is fine. List of any Subclass of Dog is not valid parameter. ``` doSomethingListModifiedSuper(animalsList); doSomethingListModifiedSuper(dogsList); ``` #### Generics and Collections Example 4 , extends with interface Below method can be called with a List declared with any type implementing the interface Serializable. ``` static void doSomethingListInterface(List animals) { //Adding an element into a list declared with ? is prohibited. //animals.add(new Animal());//COMPILER ERROR! //animals.add(new Dog());//COMPILER ERROR! } ``` #### Generics and Collections , Few more Examples and Rules A method declared with List can only be called with a List declared with type Object. None of the other classes are valid. A method declared with List can be called with a List of any type. //A method declared with List can be called with a List of any type - since all classes are sub classes of Object. ? can only be used in Declaring a type. Cannot be used as part of definition. ``` List listAnimals = new ArrayList(); //COMPILES //List genericList = new ArrayList(); //COMPILER ERROR ``` #### Generics and Collection , Compatibility with old code Consider the method below: It is declared to accept a Generic ArrayList. The method adds a string to the arraylist. ``` static void addElement(ArrayList something){ something.add(new String("String")); } ``` Consider the code below: ``` ArrayList numbers = new ArrayList(); numbers.add(5); numbers.add(6); addElement(numbers); ``` We are passing a ArrayList to a method accepting ArrayList as parameter. We are trying to a add a string to it as well, inside the method. Compiling this class would give a warning: javac gives warning because multiplyNumbersBy2(ArrayList) is invoked with a Specific ArrayList and in the method addElement an element is added to ArrayList. ``` //com/rithus/generics/GenericsExamples.java uses unchecked or unsafe operations. //Recompile with -Xlint:unchecked for details. ``` To get more details run javac specifying the parameter Xlint:unchecked. ``` javac -Xlint:unchecked com/rithus/generics/GenericsExamples.java //com/rithus/generics/GenericsExamples.java:21: warning: [unchecked] //unchecked call to add(E) as a member of the raw type java.util.ArrayList //something.add(new String("String")); // ^ ``` ### Files - Let us first look at the File class which helps us to create and delete files and directories. File class cannot be used to modify the content of a file. #### File Class #### Create a File Object ``` File file = new File("FileName.txt"); ``` #### File basic Methods Check if the file exists. ``` System.out.println(file.exists()); ``` If file does not exist creates it and returns true. If file exists, returns false. ``` System.out.println(file.createNewFile()); ``` Getting full path of file. ``` System.out.println(file.getAbsolutePath()); System.out.println(file.isFile());//true System.out.println(file.isDirectory());//false ``` Renaming a file ``` File fileWithNewName = new File("NewFileName.txt"); file.renameTo(fileWithNewName); //There is no method file.renameTo("NewFileName.txt"); ``` #### File Class - Directory A File class in Java represents a file and directory. ``` File directory = new File("src/com/rithus"); ``` Print full directory path ``` System.out.println(directory.getAbsolutePath()); System.out.println(directory.isDirectory());//true ``` This does not create the actual file. ``` File fileInDir = new File(directory,"NewFileInDirectory.txt"); ``` Actual file is created when we invoke createNewFile method. ``` System.out.println(fileInDir.createNewFile()); //true - First Time ``` Print the files and directories present in the folder. ``` System.out.println(Arrays.toString(directory.list())); ``` #### Creating a directory ``` File newDirectory = new File("newfolder"); System.out.println(newDirectory.mkdir());//true - First Time ``` #### Creating a file in a new directory ``` File notExistingDirectory = new File("notexisting"); File newFile = new File(notExistingDirectory,"newFile"); //Will throw Exception if uncommented: No such file or directory //newFile.createNewFile(); System.out.println(newDirectory.mkdir());//true - First Time ``` #### Read and write from a File Implementations of Writer and Reader abstract classes help us to write and read (content of) files. Writer methods - flush, close, append (text) Reader methods - read, close (NO FLUSH) Writer implementations - FileWriter,BufferedWriter,PrintWriter Reader implementations - FileReader,BufferedReader ### FileWriter and FileReader - FileWriter and FileReader provide basic file writing and reading operations. Let's write an example to write and read from a file using FileReader and FileWriter. #### FileWriter Class We can write to a file using FileWriter class. #### Write a string to a file using FileWriter ``` //FileWriter helps to write stuff into the file FileWriter fileWriter = new FileWriter(file); fileWriter.write("How are you doing?"); //Always flush before close. Writing to file uses Buffering. fileWriter.flush(); fileWriter.close(); ``` #### FileWriter Constructors FileWriter Constructors can accept file(File) or the path to file (String) as argument. When a writer object is created, it creates the file - if it does not exist. ``` FileWriter fileWriter2 = new FileWriter("FileName.txt"); fileWriter2.write("How are you doing Buddy?"); //Always flush before close. Writing to file uses Buffering. fileWriter2.flush(); fileWriter2.close(); ``` #### FileReader Class File Reader can be used to read entire content from a file at one go. #### Read from file using FileReader ``` FileReader fileReader = new FileReader(file); char[] temp = new char[25]; //fileReader reads entire file and stores it into temp System.out.println(fileReader.read(temp));//18 - No of characters Read from file System.out.println(Arrays.toString(temp));//output below //[H, o, w, , a, r, e, , y, o, u, , d, o, i, n, g, ?, , , , , ,] fileReader.close();//Always close anything you opened:) ``` #### FileReader Constructors FileReader constructors can accept file(File) or the path to file (String) as argument. ``` FileReader fileReader2 = new FileReader("FileName.txt"); System.out.println(fileReader2.read(temp));//24 System.out.println(Arrays.toString(temp));//output below ``` ### BufferedWriter and BufferedReader - BufferedWriter and BufferedReader provide better buffering in addition to basic file writing and reading operations. For example, instead of reading the entire file, we can read a file line by line. Let's write an example to write and read from a file using FileReader and FileWriter. #### BufferedWriter Class BufferedWriter class helps writing to a class with better buffering than FileWriter. #### BufferedWriter Constructors BufferedWriter Constructors only accept another Writer as argument ``` FileWriter fileWriter3 = new FileWriter("BufferedFileName.txt"); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter3); ``` #### Using BufferedWriter class ``` bufferedWriter.write("How are you doing Buddy?"); bufferedWriter.newLine(); bufferedWriter.write("I'm Doing Fine"); //Always flush before close. Writing to file uses Buffering. bufferedWriter.flush(); bufferedWriter.close(); fileWriter3.close(); ``` #### BufferedReader Class BufferedReader helps to read the file line by line #### BufferedReader Constructors BufferedReader Constructors only accept another Reader as argument. ``` FileReader fileReader3 = new FileReader("BufferedFileName.txt"); BufferedReader bufferedReader = new BufferedReader(fileReader3); ``` #### BufferedReader , Reading a file ``` String line; //readLine returns null when reading the file is completed. while((line=bufferedReader.readLine()) != null){ System.out.println(line); } ``` ### PrintWriter - PrintWriter provides advanced methods to write formatted text to the file. It supports printf function. #### PrintWriter constructors PrintWriter constructors supports varied kinds of arguments , File, String (File Path) and Writer. ``` PrintWriter printWriter = new PrintWriter("PrintWriterFileName.txt"); ``` #### PrintWriter , Write to a file Other than write function you can use format, printf, print, println functions to write to PrintWriter file. ``` //writes "My Name" to the file printWriter.format("%15s", "My Name"); printWriter.println(); //New Line printWriter.println("Some Text"); //writes "Formatted Number: 4.50000" to the file printWriter.printf("Formatted Number: %5.5f", 4.5); printWriter.flush();//Always flush a writer printWriter.close(); ``` #### Reading the file created using BufferedReader ``` FileReader fileReader4 = new FileReader("PrintWriterFileName.txt"); BufferedReader bufferedReader2 = new BufferedReader(fileReader4); String line2; //readLine returns null when reading the file is completed. while((line2=bufferedReader2.readLine()) != null){ System.out.println(line2); } ``` ### Serialization - Serialization helps us to save and retrieve the state of an object. #### Serialization and De-Serialization - Important methods Serialization => Convert object state to some internal object representation. De-Serialization => The reverse. Convert internal representation to object. Two important methods 1.ObjectOutputStream.writeObject() // serialize and write to file 2.ObjectInputStream.readObject() // read from file and deserialize #### Implementing Serializable Interface To serialize an object it should implement Serializable interface. In the example below, Rectangle class implements Serializable interface. Note that Serializable interface does not declare any methods to be implemented. ``` class Rectangle implements Serializable { public Rectangle(int length, int breadth) { this.length = length; this.breadth = breadth; area = length * breadth; } int length; int breadth; int area; } ``` #### Serializing an object - Example Below example shows how an instance of an object can be serialized. We are creating a new Rectangle object and serializing it to a file Rectangle.ser. ``` FileOutputStream fileStream = new FileOutputStream("Rectangle.ser"); ObjectOutputStream objectStream = new ObjectOutputStream(fileStream); objectStream.writeObject(new Rectangle(5, 6)); objectStream.close(); ``` #### De-serializing an object , Example Below example show how a object can be deserialized from a serialized file. A rectangle object is deserialized from the file Rectangle.ser ``` FileInputStream fileInputStream = new FileInputStream("Rectangle.ser"); ObjectInputStream objectInputStream = new ObjectInputStream( fileInputStream); Rectangle rectangle = (Rectangle) objectInputStream.readObject(); objectInputStream.close(); System.out.println(rectangle.length);// 5 System.out.println(rectangle.breadth);// 6 System.out.println(rectangle.area);// 30 ``` #### Serialization , Transient variables Area in the previous example is a calculated value. It is unnecessary to serialize and deserialize. We can calculate it when needed. In this situation, we can make the variable transient. Transient variables are not serialized. (transient int area;) ``` //Modified Rectangle class class Rectangle implements Serializable { public Rectangle(int length, int breadth) { this.length = length; this.breadth = breadth; area = length * breadth; } int length; int breadth; transient int area; } ``` If you run the program again, you would get following output ``` System.out.println(rectangle.length);// 5 System.out.println(rectangle.breadth);// 6 System.out.println(rectangle.area);// 0 ``` Note that the value of rectangle.area is set to 0. Variable area is marked transient. So, it is not stored into the serialized file. And when de-serialization happens area value is set to default value i.e. 0. #### Serialization , readObject method We need to recalculate the area when the rectangle object is deserialized. This can be achieved by adding readObject method to Rectangle class. In addition to whatever java does usually while deserializing, we can add custom code for the object. ``` private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { // Do whatever java does usually when de-serialization is called is.defaultReadObject(); // In addition, calculate area also area = this.length * this.breadth; } ``` When an object of Rectangle class is de-serialized, Java invokes the readObject method. The area is recalculated in this method. If we run the program again, we get the calculated area value back. Remember that area is not part of the serialized file. It is re-calculated in the readObject method. ``` System.out.println(rectangle.length);// 5 System.out.println(rectangle.breadth);// 6 System.out.println(rectangle.area);// 30 ``` #### Serialization , writeObject method We can also write custom code when serializing the object by adding the writeObject method to Rectange class. writeObject method accepts an ObjectOutputStream as input parameter. To the writeObject method we can add the custom code that we want to run during Serialization. ``` private void writeObject(ObjectOutputStream os) throws IOException { //Do whatever java does usually when serialization is called os.defaultWriteObject(); } ``` If you run the above program again, you would get following output ``` System.out.println(rectangle.length);//5 System.out.println(rectangle.breadth);//6 System.out.println(rectangle.area);//30 ``` #### Serializing an Object chain Objects of one class might contain objects of other classes. When serializing and de-serializing, we might need to serialize and de-serialize entire object chain. Look at the class below. An object of class House contains an object of class Wall. ``` class House implements Serializable { public House(int number) { super(); this.number = number; } Wall wall; int number; } class Wall{ int length; int breadth; int color; } ``` House implements Serializable where Wall doesn't. Let's run this example program: ``` public class SerializationExamples2 { public static void main(String[] args) throws IOException { FileOutputStream fileStream = new FileOutputStream( "House.ser"); ObjectOutputStream objectStream = new ObjectOutputStream( fileStream); House house = new House(10); house.wall = new Wall(); //Exception in thread "main" java.io.NotSerializableException: //com.in28minutes.serialization.Wall objectStream.writeObject(house); objectStream.close(); } } //Output: //Exception in thread "main" java.io.NotSerializableException: com.in28minutes.serialization.Wall // at java.io.ObjectOutputStream.writeObject0(Unknown Source) // at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source) ``` This is because Wall is not serializable. Two solutions are possible. Make Wall transient => wall will not be serialized. This causes the wall object state to be lost. Make Wall implement Serializable => wall object will also be serialized and the state of wall object along with the house will be stored. #### Serialization Program 1: Make Wall transient ``` class House implements Serializable { public House(int number) { super(); this.number = number; } transient Wall wall; int number; } ``` #### Serialization Program 2: Make Wall implement Serializable ``` class Wall implements Serializable { int length; int breadth; int color; } ``` With both these programs, earlier main method would run without throwing an exception. If you try de-serializing, In Example2, state of wall object is retained whereas in Example1, state of wall object is lost. #### Serialization and Initialization When a class is Serialized, initialization (constructor's, initializer's) does not take place. The state of the object is retained as it is. #### Serialization and inheritance However in the case of inheritance ( a sub class and super class relationship), interesting things happen. Let's consider the example code below: Hero class extends Actor and Hero class implements Serializable. However, Actor class does not implement Serializable. ``` class Actor { String name; public Actor(String name) { super(); this.name = name; } Actor() { name = "Default"; } } class Hero extends Actor implements Serializable { String danceType; public Hero(String name, String danceType) { super(name); this.danceType = danceType; } Hero() { danceType = "Default"; } } ``` Let's run the code below: ``` FileOutputStream fileStream = new FileOutputStream("Hero.ser"); ObjectOutputStream objectStream = new ObjectOutputStream(fileStream); Hero hero = new Hero("Hero1", "Ganganam"); // Before -> DanceType:Ganganam Name:Hero1 System.out.println("Before -> DanceType:" + hero.danceType + " Name:" + hero.name); objectStream.writeObject(hero); objectStream.close(); FileInputStream fileInputStream = new FileInputStream("Hero.ser"); ObjectInputStream objectInputStream = new ObjectInputStream( fileInputStream); hero = (Hero) objectInputStream.readObject(); objectInputStream.close(); // After -> DanceType:Ganganam Name:Default System.out.println("After -> DanceType:" + hero.danceType + " Name:" + hero.name); ``` Code executes successfully but after de-serialization, the values of super class instance variables are not retained. They are set to their initial values. When subclass is serializable and superclass is not, the state of subclass variables is retained. However, for the super class, initialization (constructors and initializers) happens again. #### Serialization and Static Variables Static Variables are not part of the object. They are not serialized. ### Threads - Threads allow Java code to run in parallel. Let's first understand the need for threading and then look into how to create a thread and what is synchronization? #### Need for Threads We are creating a Cricket Statistics Application. Let's say the steps involved in the application are STEP I: Download and Store Bowling Statistics => 60 Minutes STEP II: Download and Store Batting Statistics => 60 Minutes STEP III: Download and Store Fielding Statistics => 15 Minutes STEP IV: Merge and Analyze => 25 Minutes Steps I, II and III are independent and can be run in parallel to each other. Run individually this program takes 160 minutes. We would want to run this program in lesser time. Threads can be a solution to this problem. Threads allow us to run STEP I, II and III in parallel and run Step IV when all Steps I, II and III are completed. #### Need for Threads Example Below example shows the way we would write code usually , without using Threads. ``` ThreadExamples example = new ThreadExamples(); example.downloadAndStoreBattingStatistics(); example.downloadAndStoreBowlingStatistics(); example.downloadAndStoreFieldingStatistics(); example.mergeAndAnalyze(); ``` downloadAndStoreBowlingStatistics starts only after downloadAndStoreBattingStatistics completes execution. downloadAndStoreFieldingStatistics starts only after downloadAndStoreBowlingStatistics completes execution. What if I want to run them in parallel without waiting for the others to complete? This is where Threads come into picture. #### Creating a Thread Class Creating a Thread class in Java can be done in two ways. Extending Thread class and implementing Runnable interface. Let's create the BattingStatisticsThread extending Thread class and BowlingStatisticsThread implementing Runnable interface. #### Creating a Thread By Extending Thread class Thread class can be created by extending Thread class and implementing the public void run() method. Look at the example below: A dummy implementation for BattingStatistics is provided which counts from 1 to 1000. ``` class BattingStatisticsThread extends Thread { //run method without parameters public void run() { for (int i = 0; i < 1000; i++) System.out .println("Running Batting Statistics Thread " + i); } } ``` #### Creating a Thread by Implementing Runnable interface Thread class can also be created by implementing Runnable interface and implementing the method declared in Runnable interface Òpublic void run()Ó. Example below shows the Batting Statistics Thread implemented by implementing Runnable interface. ``` class BowlingStatisticsThread implements Runnable { //run method without parameters public void run() { for (int i = 0; i < 1000; i++) System.out .println("Running Bowling Statistics Thread " + i); } } ``` #### Running a Thread Running a Thread in Java is slightly different based on the approach used to create the thread. #### Thread created Extending Thread class When using inheritance, An object of the thread needs be created and start() method on the thread needs to be called. Remember that the method that needs to be called is not run() but it is start(). ``` BattingStatisticsThread battingThread1 = new BattingStatisticsThread(); battingThread1.start(); ``` #### Thread created implementing RunnableInterface. Three steps involved. 1. Create an object of the BowlingStatisticsThread(class implementing Runnable). 2. Create a Thread object with the earlier object as constructor argument. 3. Call the start method on the thread. ``` BowlingStatisticsThread battingInterfaceImpl = new BowlingStatisticsThread(); Thread battingThread2 = new Thread( battingInterfaceImpl); battingThread2.start(); ``` #### Thread Example , Complete Program Let's consider the complete example using all the snippets of code created above. ``` public class ThreadExamples { public static void main(String[] args) { class BattingStatisticsThread extends Thread { // run method without parameters public void run() { for (int i = 0; i < 1000; i++) System.out.println("Running Batting Statistics Thread " + i); } } class BowlingStatisticsThread implements Runnable { // run method without parameters public void run() { for (int i = 0; i < 1000; i++) System.out.println("Running Bowling Statistics Thread " + i); } } BattingStatisticsThread battingThread1 = new BattingStatisticsThread(); battingThread1.start(); BowlingStatisticsThread battingInterfaceImpl = new BowlingStatisticsThread(); Thread battingThread2 = new Thread(battingInterfaceImpl); battingThread2.start(); } } ``` Output: ``` Running Batting Statistics Thread 0 Running Batting Statistics Thread 1 .. .. Running Batting Statistics Thread 10 Running Bowling Statistics Thread 0 .. .. Running Bowling Statistics Thread 948 Running Bowling Statistics Thread 949 Running Batting Statistics Thread 11 Running Batting Statistics Thread 12 .. .. Running Batting Statistics Thread 383 Running Batting Statistics Thread 384 Running Bowling Statistics Thread 950 Running Bowling Statistics Thread 951 .. Running Bowling Statistics Thread 998 Running Bowling Statistics Thread 999 Running Batting Statistics Thread 385 .. Running Batting Statistics Thread 998 Running Batting Statistics Thread 999 ``` #### Discussion about Thread Example Above output shows sample execution of the thread. The output will not be the same with every run. We can notice that Batting Statistics Thread and the Bowling Statistics Threads are alternating in execution. Batting Statistics Thread runs upto 10, then Bowling Statistics Thread runs upto 949, Batting Statistics Thread picks up next and runs up to 384 and so on. There is no usual set pattern when Threads run (especially when they have same priority , more about this later..). JVM decides which Thread to run at which time. If a Thread is waiting for user input or a network connection, JVM runs the other waiting Threads. #### Thread Synchronization Since Threads run in parallel, a new problem arises. i.e. What if thread1 modifies data which is being accessed by thread2? How do we ensure that different threads don't leave the system in an inconsistent state? This problem is usually called Thread Synchronization Problem. Let's first look at an example where this problem can occur. #### Example Program: Consider the SpreadSheet class below. It consists of three cells and also a method setAndGetSum which sets the values into the cell and sums them up. ``` class SpreadSheet { int cell1, cell2, cell3; int setandGetSum(int a1, int a2, int a3) { cell1 = a1; sleepForSomeTime(); cell2 = a2; sleepForSomeTime(); cell3 = a3; sleepForSomeTime(); return cell1 + cell2 + cell3; } void sleepForSomeTime() { try { Thread.sleep(10 * (int) (Math.random() * 100)); } catch (InterruptedException e) { e.printStackTrace(); } } } ``` #### Serial Run Let's first run the above example in a serial way and see what the output would be. ``` public static void main(String[] args) { SpreadSheet spreadSheet = new SpreadSheet(); for (int i = 0; i < 4; i++) { System.out.print(spreadSheet.setandGetSum(i, i * 2, i * 3) + " "); } } //Output - 0 6 12 18 ``` Output would contain a multiple of 6 always because we are calling with i, i*2 and i*3 and summing up. So, the result should generally be i*6 with i running from 0 to 3. #### Example Program using Threads Let's now run the SpreadSheet class in a Thread. Example Code below: ``` public class ThreadExampleSynchronized implements Runnable { SpreadSheet spreadSheet = new SpreadSheet(); public void run() { for (int i = 0; i < 4; i++) { System.out.print( spreadSheet.setandGetSum(i,i * 2, i * 3) + " "); } } public static void main(String[] args) { ThreadExampleSynchronized r = new ThreadExampleSynchronized(); Thread one = new Thread(r); Thread two = new Thread(r); one.start(); two.start(); } } ``` We are creating 2 instances of the Thread using the interface , one and two. And start method is invoked to run the thread. Both threads share the instance of SpreadSheet class , spreadsheet. Output ``` FIRST RUN : 0 1 6 9 12 15 18 18 SECOND RUN : 0 3 6 6 12 15 18 18 THIRD RUN : 0 3 6 9 12 15 18 18 ``` Output Discussion What we see is that different runs have different results. That's expected with threads. What is not expected is to see numbers like 1, 9, 15 and 3 in the output. We are expecting to see multiples of 6 in the output(as in the earlier serial run) but we see numbers which are not multiples of 6. Why is this happening? This is a result of having two threads run in parallel without synchronization. Consider the code in the setAndGetSum method. ``` int setandGetSum(int a1, int a2, int a3) { cell1 = a1; sleepForSomeTime(); cell2 = a2; sleepForSomeTime(); cell3 = a3; sleepForSomeTime(); return cell1 + cell2 + cell3; } ``` After setting the value to each cell, there is a call for the Thread to sleep for some time. After Thread 1 sets the value of cell1, it goes to Sleep. So, Thread2 starts executing. If Thread 2 is executing Òreturn cell1 + cell2 + cell3;Ó, it uses cell1 value set by Thread 1 and cell2 and cell3 values set by Thread 2. This results in the unexpected results that we see when the method is run in parallel. What is explained is one possible scenario. There are several such scenarios possible. The way you can prevent multiple threads from executing the same method is by using the synchronized keyword on the method. If a method is marked synchronized, a different thread gets access to the method only when there is no other thread currently executing the method. Let's mark the method as synchronized: ``` synchronized int setandGetSum(int a1, int a2, int a3) { cell1 = a1; sleepForSomeTime(); cell2 = a2; sleepForSomeTime(); cell3 = a3; sleepForSomeTime(); return cell1 + cell2 + cell3; } ``` Output of the program now is Ò0 0 6 6 12 12 18 18Ó. This is expected output , all numbers are multiples of 6. #### Threads & Synchronized Keyword A method or part of the method can be marked as synchronized. JVM will ensure that there is only thread running the synchronized part of code at any time. However, thread synchronization is not without consequences. There would be a performance impact as the rest of threads wait for the current thread executing a synchronized block. So, as little code as possible should be marked as synchronized. #### Synchronized method Example ``` synchronized void synchronizedExample1() { //All code goes here.. } ``` #### Synchronized block Example All code which goes into the block is synchronized on the current object. ``` void synchronizedExample2() { synchronized (this){ //All code goes here.. } } ``` #### Synchronized static method Example ``` synchronized static int getCount(){ return count; } ``` #### Static synchronized block Example Static blocks are synchronized on the class. ``` static int getCount2(){ synchronized (SynchronizedSyntaxExample.class) { return count; } } ``` #### Static and non static synchronized methods and blocks Static methods and block are synchronized on the class. Instance methods and blocks are synchronized on the instance of the class i.e. an object of the class. Static synchronized methods and instance synchronized methods don't affect each other. This is because they are synchronized on two different things. #### States of a Thread Different states that a thread can be in are defined the class State. - NEW; - RUNNABLE; - RUNNING; - BLOCKED/WAITING; - TERMINATED/DEAD; Let's consider the example that we discussed earlier. #### Example Program ``` LINE 1: BattingStatisticsThread battingThread1 = new BattingStatisticsThread(); LINE 2: battingThread1.start(); LINE 3: BowlingStatisticsThread battingInterfaceImpl = new BowlingStatisticsThread(); LINE 4: Thread battingThread2 = new Thread(battingInterfaceImpl); LINE 5:battingThread2.start(); //Output - Running Batting Statistics Thread 0 Running Batting Statistics Thread 1 .. .. Running Batting Statistics Thread 10 Running Bowling Statistics Thread 0 .. .. Running Bowling Statistics Thread 948 Running Bowling Statistics Thread 949 Running Batting Statistics Thread 11 Running Batting Statistics Thread 12 .. .. Running Batting Statistics Thread 383 Running Batting Statistics Thread 384 Running Bowling Statistics Thread 950 Running Bowling Statistics Thread 951 .. Running Bowling Statistics Thread 998 Running Bowling Statistics Thread 999 Running Batting Statistics Thread 385 .. Running Batting Statistics Thread 998 Running Batting Statistics Thread 999 ``` #### States of a Thread - Examples A thread is in NEW state when an object of the thread is created but the start method is not yet called. At the end of line 1, battingThread1 is in NEW state. A thread is in RUNNABLE state when it is eligible to run, but not running yet. (A number of Threads can be in RUNNABLE state. Scheduler selects which Thread to move to RUNNING state). In the above example, sometimes the Batting Statistics thread is running and at other time, the Bowling Statistics Thread is running. When Batting Statistics thread is Running, the Bowling Statistics thread is ready to run. It's just that the scheduler picked Batting Statistics thread to run at that instance and vice-versa. When Batting Statistics thread is Running, the Bowling Statistics Thread is in Runnable state (Note that the Bowling Statistics Thread is not waiting for anything except for the Scheduler to pick it up and run it). A thread is RUNNING state when it's the one that is currently , what else to say, Running. A thread is in BLOCKED/WAITING/SLEEPING state when it is not eligible to be run by the Scheduler. Thread is alive but is waiting for something. An example can be a Synchronized block. If Thread1 enters synchronized block, it blocks all the other threads from entering synchronized code on the same instance or class. All other threads are said to be in Blocked state. A thread is in DEAD/TERMINATED state when it has completed its execution. Once a thread enters dead state, it cannot be made active again. #### Thread Priority Scheduler can be requested to allot more CPU to a thread by increasing the threads priority. Each thread in Java is assigned a default Priority 5. This priority can be increased or decreased (Range 1 to 10). If two threads are waiting, the scheduler picks the thread with highest priority to be run. If all threads have equal priority, the scheduler then picks one of them randomly. Design programs so that they don't depend on priority. #### Thread Priority Example Consider the thread example declared below: ``` class ThreadExample extends Thread { public void run() { for (int i = 0; i < 1000; i++) System.out .println( this.getName() + " Running " + i); } } ``` Priority of thread can be changed by invoking setPriority method on the thread. ``` ThreadExample thread1 = new ThreadExample(); thread1.setPriority(8); ``` Java also provides predefined constants Thread.MAX_PRIORITY(10), Thread.MIN_PRIORITY(1), Thread.NORM_PRIORITY(5) which can be used to assign priority to a thread. #### Thread Join method Join method is an instance method on the Thread class. Let's see a small example to understand what join method does. Let's consider the thread's declared below: thread2, thread3, thread4 ``` ThreadExample thread2 = new ThreadExample(); ThreadExample thread3 = new ThreadExample(); ThreadExample thread4 = new ThreadExample(); ``` Let's say we would want to run thread2 and thread3 in parallel but thread4 can only run when thread3 is finished. This can be achieved using join method. #### Join method example Look at the example code below: ``` thread3.start(); thread2.start(); thread3.join();//wait for thread 3 to complete System.out.println("Thread3 is completed."); thread4.start(); ``` thread3.join() method call force the execution of main method to stop until thread3 completes execution. After that, thread4.start() method is invoked, putting thread4 into a Runnable State. #### Overloaded Join method Join method also has an overloaded method accepting time in milliseconds as a parameter. ``` thread4.join(2000); ``` In above example, main method thread would wait for 2000 ms or the end of execution of thread4, whichever is minimum. #### Thread , Static methods #### Thread yield method Yield is a static method in the Thread class. It is like a thread saying " I have enough time in the limelight. Can some other thread run next?". A call to yield method changes the state of thread from RUNNING to RUNNABLE. However, the scheduler might pick up the same thread to run again, especially if it is the thread with highest priority. Summary is yield method is a request from a thread to go to Runnable state. However, the scheduler can immediately put the thread back to RUNNING state. #### Thread sleep method sleep is a static method in Thread class. sleep method can throw a InterruptedException. sleep method causes the thread in execution to go to sleep for specified number of milliseconds. #### Thread and Deadlocks Let's consider a situation where thread1 is waiting for thread2 ( thread1 needs an object whose synchronized code is being executed by thread1) and thread2 is waiting for thread1. This situation is called a Deadlock. In a Deadlock situation, both these threads would wait for one another for ever. #### Deadlock Example Consider the example classes below: Resource represents any resource that you need access to. A network connection, database connection etc. Operation represents an operation that can be done on these resources. Let's say that Operation need two resources, resource1 and resource2 and offer two operations method1 and method2. Look at the program below: ``` class Resource { } class SomeOperation { Resource resource1 = new Resource(); Resource resource2 = new Resource(); void method1() throws InterruptedException { synchronized (resource1) { Thread.sleep(1000); //code using resource1 synchronized (resource2) { //code using resource2 } } } void method2() throws InterruptedException { System.out.println(Thread.currentThread().getName() + "is in method2"); synchronized (resource2) { //code using resource2 Thread.sleep(1000); synchronized (resource1) { //code using resource1 } } } } ``` Method1 executes some code on resource1 first and then executes some code on resource2. Method2 does the reverse. We use the sleep method call to simulate the fact that these operation could take some time to complete. Let's create two threads sharing the above operation using the code below: Threads one and two now share object operation. The thread code runs both operations method1 and method2. ``` public class ThreadDeadlock implements Runnable { SomeOperation operation = new SomeOperation(); @Override public void run() { try { operation.method1(); operation.method2(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { ThreadDeadlock r = new ThreadDeadlock(); Thread one = new Thread(r); Thread two = new Thread(r); one.start(); two.start(); } } ``` When executed this program just hangs, because of a deadlock. To make what is happening behind the screens more clear, Let's add in a few sysout's in the Operation class. ``` class SomeOperation { Resource resource1 = new Resource(); Resource resource2 = new Resource(); void method1() throws InterruptedException { synchronized (resource1) { System.out.println("Method1 - got resource1"); Thread.sleep(1000); //code using resource1 System.out.println("Method1 - waiting for resource2"); synchronized (resource2) { System.out.println("Method1 - got resource2"); //code using resource2 } } } void method2() throws InterruptedException { synchronized (resource2) { System.out.println("Method2 - got resource2"); //code using resource2 Thread.sleep(1000); System.out.println("Method2 - waiting for resource1"); synchronized (resource1) { System.out.println("Method2 - got resource1"); //code using resource1 } } } } ``` #### Output: ``` Method1 - got resource1 Method1 - waiting for resource2 Method1 - got resource2 Method1 - got resource1 Method2 - got resource2 Method1 - waiting for resource2 Method2 - waiting for resource1 HANGSÉÉÉÉÉÉÉÉ ``` Now we have two threads waiting for resources held by one another. This results in a deadlock. #### Thread - wait, notify and notifyAll methods Consider the example below: Calculator thread calculates two values: Sum upto Million and Sum upto 10 Million. Main program uses the output of sum upto million. #### Example 1 ``` class Calculator extends Thread { long sumUptoMillion; long sumUptoTenMillion; public void run() { calculateSumUptoMillion(); calculateSumUptoTenMillion(); } private void calculateSumUptoMillion() { for (int i = 0; i < 1000000; i++) { sumUptoMillion += i; } } private void calculateSumUptoTenMillion() { for (int i = 0; i < 10000000; i++) { sumUptoTenMillion += i; } } } public class ThreadWaitAndNotify { public static void main(String[] args) { Calculator thread = new Calculator(); thread.start(); System.out.println(thread.sumUptoMillion); } } ``` #### Output ``` 0 ``` Output printed is 0. This is because the thread has not finished calculating the value of sumUptoMillion when the main method prints the value to the output. We have to find a way to stop the main method from running until sumUptoMillion is calculated. One option is to use the join method. But, join method would make the main method wait until both the operations (sumUptoMillion and sumUptoTenMillion) are completed. But, we want main method to wait only for sumUptoMillion. We can achieve this using wait and notify methods. wait and notify methods can only be used in a synchronized context. #### Example with wait and notify methods ``` package com.in28minutes.threads; class Calculator extends Thread { long sumUptoMillion; long sumUptoTenMillion; public void run() { synchronized (this) { calculateSumUptoMillion(); notify(); } calculateSumUptoTenMillion(); } private void calculateSumUptoMillion() { for (int i = 0; i < 1000000; i++) { sumUptoMillion += i; } System.out.println("Million done"); } private void calculateSumUptoTenMillion() { for (int i = 0; i < 10000000; i++) { sumUptoTenMillion += i; } System.out.println("Ten Million done"); } } public class ThreadWaitAndNotify { public static void main(String[] args) throws InterruptedException { Calculator thread = new Calculator(); synchronized(thread){ thread.start(); thread.wait(); } System.out.println(thread.sumUptoMillion); } } ``` #### Output ``` Million done 499999500000 Ten Million done ``` #### Wait method example Below snippet shows how wait is used in earlier program. wait method is defined in the Object class. This causes the thread to wait until it is notified. ``` synchronized(thread){ thread.start(); thread.wait(); } ``` #### Notify method example Below snippet shows how notify is used in earlier program. notify method is defined in the Object class. This causes the object to notify other waiting threads. ``` synchronized (this) { calculateSumUptoMillion(); notify(); } ``` A combination of wait and notify methods make the main method to wait until the sum of million is calculated. However, not the main method does not wait for Sum of Ten Million to be calculated. #### notifyAll method If more than one thread is waiting for an object, we can notify all the threads by using notifyAll method. ``` thread.notifyAll(); ``` ### Assert - Assertions are introduced in Java 1.4. They enable you to validate assumptions. If an assert fails (i.e. returns false), AssertionError is thrown (if assertions are enabled). assert is a keyword in java since 1.4. Before 1.4, assert can be used as identifier. #### Assert Details To compile code using 1.3 you can use the command below javac -source 1.3 OldCode.java => assert can be used as identifier with -source 1.4,1.5,5,1.6,6 => assert cannot be used as identifier Assertions can easily be enabled and disabled. Assertions are disabled by default. #### Enabling Assertions Enable assertions: java -ea com.in28minutes.AssertExamples (OR) java -enableassertions com.in28minutes.AssertExamples #### Disable Assertions Disable assertions: java -da com.in28minutes.AssertExamples (OR) java -disableassertions com.in28minutes.AssertExamples #### Enable Assertions in specific packages Selectively enable assertions in a package only java -ea:com.rithus Selectively enable assertions in a package and its subpackages only java -ea:com.in28minutes... #### Enable assertions including system classes java -ea -esa #### Basic assert condition example Basic assert is shown in the example below ``` private int computerSimpleInterest(int principal,float interest,int years){ assert(principal>0); return 100; } ``` #### Assert with debugging information: Example If needed - debugging information can be added to an assert. Look at the example below. ``` private int computeCompoundInterest(int principal,float interest,int years){ //condition is always boolean //second parameter can be anything that converts to a String. assert(principal>0): "principal is " + principal; return 100; } public static void main(String[] args) { AssertExamples examples = new AssertExamples(); System.out.println(examples.computerSimpleInterest(-1000,1.0f,5)); } ``` #### Asserts - Not for validation Assertions should not be used to validate input data to a public method or command line argument. IllegalArgumentException would be a better option. In public method, only use assertions to check for cases which are never supposed to happen. ### Garbage Collection - Garbage Collection is a name given to automatic memory management in Java. Aim of Garbage Collection is to Keep as much of heap available (free) for the program as possible. JVM removes objects on the heap which no longer have references from the heap. #### Garbage Collection Example Let's say the below method is called from a function. ``` void method(){ Calendar calendar = new GregorianCalendar(2000,10,30); System.out.println(calendar); } ``` An object of the class GregorianCalendar is created on the heap by the first line of the function with one reference variable calendar. After the function ends execution, the reference variable calendar is no longer valid. Hence, there are no references to the object created in the method. JVM recognizes this and removes the object from the heap. This is called Garbage Collection. #### When is Garbage Collection run? Garbage Collection runs at the whims and fancies of the JVM (it isn't as bad as that). Possible situations when Garbage Collection might run are 1.when available memory on the heap is low 2.when cpu is free #### Garbage Collection , Important Points Programmatically, we can request (remember it's just a request - Not an order) JVM to run Garbage Collection by calling System.gc() method. JVM might throw an OutOfMemoryException when memory is full and no objects on the heap are eligible for garbage collection. finalize() method on the objected is run before the object is removed from the heap from the garbage collector. We recommend not to write any code in finalize(); ### Initialization Blocks - Initialization Blocks - Code which runs when an object is created or a class is loaded #### Types of Initialization Blocks There are two types of Initialization Blocks Static Initializer: Code that runs when a class is loaded. Instance Initializer: Code that runs when a new object is created. #### Static Initializer ``` public class InitializerExamples { static int count; int i; static{ //This is a static initializers. Run only when Class is first loaded. //Only static variables can be accessed System.out.println("Static Initializer"); //i = 6;//COMPILER ERROR System.out.println("Count when Static Initializer is run is " + count); } public static void main(String[] args) { InitializerExamples example = new InitializerExamples(); InitializerExamples example2 = new InitializerExamples(); InitializerExamples example3 = new InitializerExamples(); } } ``` Code within static{ and } is called a static initializer. This is run only when class is first loaded. Only static variables can be accessed in a static initializer. #### Example Output ``` Static Initializer Count when Static Initializer is run is 0 ``` Even though three instances are created static initializer is run only once. #### Instance Initializer Block Let's look at an example ``` public class InitializerExamples { static int count; int i; { //This is an instance initializers. Run every time an object is created. //static and instance variables can be accessed System.out.println("Instance Initializer"); i = 6; count = count + 1; System.out.println("Count when Instance Initializer is run is " + count); } public static void main(String[] args) { InitializerExamples example = new InitializerExamples(); InitializerExamples example1 = new InitializerExamples(); InitializerExamples example2 = new InitializerExamples(); } } ``` Code within instance initializer is run every time an instance of the class is created. #### Example Output ``` Instance Initializer Count when Instance Initializer is run is 1 Instance Initializer Count when Instance Initializer is run is 2 Instance Initializer Count when Instance Initializer is run is 3 ``` ### Java Bean Conventions - When is a java class called a bean? Let's find an answer to this question. #### Java Bean Example Consider the code example below: ``` public class JavaBeansStandards { private String name; private boolean good; public String getName() { return name; } public boolean isGood() { return good; } public void setName(String name) { this.name = name; } public void setGood(boolean isGood) { this.good = isGood; } public void addSomeListener(MyListener listener){ } public void removeSomeListener(MyListener listener){ } } ``` #### Private Member Variables Good practice is to have all member variables in a class declared as private. ``` private String name; private boolean good; ``` #### Naming setter and getter methods - To modify and access values of properties we use setter and getter methods. Getters and setters should be public. - Getters should not have any arguments passed. - Setters should take one argument (the property value) with same type as the return value of getter. - Non boolean getter name should be (get + PropertyName) - boolean getter name can be (get + PropertyName) or (is + PropertyName) - All setters should be named (set + PropertyName) #### Examples ``` public String getName() { return name; } public boolean isGood() { return good; } public void setName(String name) { this.name = name; } public void setGood(boolean isGood) { this.good = isGood; } ``` #### Listener naming conventions Methods to register/add a listener should use prefix "add" and suffix "Listener". They should accept 1 parameter - the listener object to be added. #### Example ``` public void addSomeListener(MyListener listener){ } ``` Methods to de-register/remove a listener should use prefix "remove" and suffix "Listener". They should accept 1 parameter - the listener object to be removed #### Example ``` public void removeSomeListener(MyListener listener){ } ``` ### Regular Expressions - Regular Expressions make parsing, scanning and splitting a string very easy. We will first look at how you can evaluate a regular expressions in Java , using Patter, Matcher and Scanner classes. We will then look into how to write a regular expression. #### Regular Expression in Java , Matcher and Pattern Example Code below shows how to execute a regular expression in java. ``` private static void regex(String regex, String string) { Pattern p = Pattern.compile(regex); Matcher m = p.matcher(string); List matches = new ArrayList(); while (m.find()) { matches.add(m.start() + "<" + m.group() + ">"); } System.out.println(matches); } ``` #### Matcher class Matcher class has the following utility methods: find(), start(), group(). find() method returns true until there is a match for the regular expression in the string. start() method gives the starting index of the match. group() method returns the matching part of the string. #### Examples Let's run this method with a regular expression to search for Ò12Ó in the string Ò122345612Ó. ``` regex("12", "122345612"); ``` Output ``` [0<12>, 7<12>] ``` Output shows the matching strings 12, 12. Also, shown in the output is the starting index of each match. First 12 is present starting at index 0. The next 12 in the string starts at index 7. #### Creating Regular Expressions for Java Let's test regular expressions by using the method we created earlier: regex(). #### Simple Regular Expressions Search for 12 in the string ``` regex("12", "122345612");//[0<12>, 7<12>] ``` Certain characters escaped by \ have special meaning in regular expressions. For example, /s matches a whitespace character. Remember that to represent \ in a string, we should prepend \ to it. Let us see a few examples below. ``` System.out.println("\\");//prints \ (only one slash) ``` Space character - \s ``` regex("\\s", "12 1234 123 ");//[2< >, 7< >, 11< >] ``` Digit - \d ``` regex("\\d", "12 12");//[0<1>, 1<2>, 3<1>, 4<2>] ``` Word character (letter, digits or underscore) - \w ``` regex("\\w", "ab 12 _");//[0, 1, 3<1>, 4<2>, 6<_>] ``` Square brackets are used in regular expressions to search for a range of characters. Few examples below. look for a,b,c,d,1,2,3,4 =>Note that this does not look for capital A,B,C,D ``` regex("[a-d1-4]", "azbkdm 15AB");//[0, 2, 4, 7<1>] regex("[a-dA-D]", "abyzCD");//[0, 1, 4, 5] ``` #### Regular Expressions , Multiple Characters + is used in regular expression to look for 1 or more characters. For example a+ looks for 1 or more character a's. ``` regex("a+", "aaabaayza");//[0, 4, 8] ``` Look for one or more characters from a to z (only small case). ``` regex("[a-z]+", "abcZ2xyzN1yza");//[0, 5, 10] //0123456789012 ``` #### Regular Expressions , Look for Repetitions Regular expressions can be joined together to look for a combination. a+b+ looks 1 or more a's and 1 or more b's next to each other. Notice that only a's or only b's do not match. ``` regex("a+b+", "aabcacaabbbcbb");//[0, 6] ``` #### * - 0 or more repetitions. Below expression looks for 1 or more a's followed by 0 or more b's followed by 1 or more c's. abc => match. ac=> match (since we used * for b). ab => does not match. ``` regex("a+b*c+", "abcdacdabdbc");//[0, 4] ``` #### ? - 0 or 1 repetitions. a+b*c? looks for 1 or more a's followed by 0 or more b's followed by 0 or 1 c's. a => matches. ab => matches. abc=>matches. abcc => does not match (only 0 or 1 c's) ``` regex("a+b*c?", "adabdabcdabccd");//[0, 2, 5, 9] ``` ^a looks for anything other than a ``` regex("[^a]+", "bcadefazyx");//[0, 3, 7] ``` [^abcd]+a looks for anything which is not a or b or c or d, repeated 0 or more times, followed by a ``` regex("[^abcd]+a", "efgazyazyzb");//[0, 4] ``` #### . matches any character a.c looks for Ôa' followed by any character followed by Ôc'. abc => match abbc => no match (. matches 1 character only) ``` regex("a.c", "abca ca!cabbc");//[0, 3, 6] ``` #### Greedy Regular Expressions a+ matches a, aa,aaa,aaaa, aaaaa. If you look at the output of the below expression, it matches the biggest only aaaaa. This is called greedy behaviour. similar behavior is shown by *. ``` regex("a+", "aaaaab");//[0] ``` You can make + reluctant (look for smallest match) by appending ? ``` regex("a+?", "aaaaab");//[0, 1, 2, 3, 4] ``` Similarly *? is reluctant match for the greedy * If you want to look for characters . or * in a regular expression, then you should escape them. Example: If I want to look for ...(3 dots), we should use \.\.\. To represent \.\.\. as string we should put two \'s instead of 1. ``` regex("\\.\\.\\.", "...a....b...c");//[0<...>, 4<...>, 9<...>] ``` #### Regular Expression using Scanner class Below code shows how Scanner class can be used to execute regular expression. findInLine method in Scanner returns the match , if a match is found. Otherwise, it returns null. ``` private static void regexUsingScanner(String regex, String string) { Scanner s = new Scanner(string); List matches = new ArrayList(); String token; while ((token = s.findInLine(regex)) != null) { matches.add(token); } ; System.out.println(matches); } ``` #### Example ``` regexUsingScanner("a+?", "aaaaab");//[a, a, a, a, a] ``` ### Tokenizing - Tokenizing means splitting a string into several sub strings based on delimiters. For example, delimiter ; splits the string ac;bd;def;e into four sub strings ac, bd, def and e. Delimiter can in itself be any of the regular expression(s) we looked at earlier. String.split(regex) function takes regex as an argument. #### Example method for Tokenizing ``` private static void tokenize(String string,String regex) { String[] tokens = string.split(regex); System.out.println(Arrays.toString(tokens)); } ``` #### Example: ``` tokenize("ac;bd;def;e",";");//[ac, bd, def, e] ``` #### Tokenizing using Scanner Class ``` private static void tokenizeUsingScanner(String string,String regex) { Scanner scanner = new Scanner(string); scanner.useDelimiter(regex); List matches = new ArrayList(); while(scanner.hasNext()){ matches.add(scanner.next()); } System.out.println(matches); } ``` #### Example: ``` tokenizeUsingScanner("ac;bd;def;e",";");//[ac, bd, def, e] ``` #### Scanner Class: Other Functions ``` private static void lookForDifferentThingsUsingScanner( String string) { Scanner scanner = new Scanner(string); while(scanner.hasNext()){ if(scanner.hasNextBoolean()){ System.out.println("Found Boolean:" + scanner.nextBoolean()); } else if(scanner.hasNextInt()){ System.out.println("Found Integer:" + scanner.nextInt()); } else { System.out.println("Different thing:" + scanner.next()); } } } ``` Scanner has more useful functions other than just looking for a delimiter #### Example: ``` lookForDifferentThingsUsingScanner("true false 12 3 abc true 154"); ``` #### Output ``` //Found Boolean:true //Found Boolean:false //Found Integer:12 //Found Integer:3 //Different thing:abc //Found Boolean:true //Found Integer:154 ``` ### Expressions Where are objects created? Where are strings created? ### TODO - replace ``` with ```java at start of code - //Getters and Setters are eliminated to keep the example short - Java SE vs ME vs EE - Check for long lines which are cut off in pdf - Notes from Venkat's Talk - Designed for a different world - PEnguins - OOPS - Terrible - 1970s - FP - Lambda calculus-1929 - Complexity from problems vs Complexity from solutions - Structured Programming - One Start One Exit???? - Functional Programming - Assignment LEss - Statements vs Expressions - Pure Function - No side effects and Zero dependencies that change - Referential Transparency - Pure Functions - idempotent - referenctial transparency - memorizable - easier to testt - may be lazily evaluated - Higher order function - take/create/return object vs take/create/return function - Java Future - imperative + oops -> functional + oops - Stream - Does not evaluate the function on all the data. It takes a collection of functions (fusing - intermediate operations combined) and executes them on each piece of data.. - Functional Pipeline, Function - "Coolection pipeline pattern" -> Martin Fowler - Lambda - Stateless - Closure has State - Code is Liability not an asset! - Exception Handling - Promise - Reactive Programming - Error, Data and End channels - Error is a first class citizen - Handle errors down stream ### Complete Java Course - https://www.udemy.com/java-programming-tutorial-for-beginners/ ### More Courses and Videos From in28Minutes - https://github.com/in28minutes/learn ================================================ FILE: Java/todo.md ================================================ ## Java Certification Source - https://education.oracle.com/education/pdf/JavaCertificationMap.pdf The Oracle Certification track now consists of levels – Associate (OCA) - Professional (OCP) - Master (OCM) - & a few others - Talk about complexity ### Java 8 - Oracle Certified Associate, Java SE 8 Programmer 1Z0-808 - Oracle Certified Professional, Java SE 8 Programmer II, 1Z0-809 - You have other upgrade options from earlier versions - There is NO Oracle Certified Master for Java SE 8 - The last master certification for Java - Oracle Certified Master, Java SE 6 Developer 1Z0-855 (includes an assignment and an essay) - is discontinued - The Oracle Certified Master, Java SE 6 Developer certification retires on November 30, 2016. - At this time, there is no plan to release a new version of the certification. Through careful job task analysis with the Java SE 8 certification release, it was determined that the OCM Developer role was no longer appropriate to keep as a separate certification and the that skills of that role should be included in the Programmer certifications. ## Upgrade to Java SE 8 OCP ( Java SE 6 and all prior versions) From https://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=5001&get_params=p_exam_id:1Z0-813 #### TOPICS ##### Language Enhancements - Develop code that uses String objects in the switch statement, binary literals, and numeric literals, including underscores in literals - Develop code that uses try-with-resources statements, including using classes that implement the AutoCloseable interface - Develop code that handles multiple Exception types in a single catch block - Use static and default methods of an interface including inheritance rules for a default method ##### Concurrency - Use classes from the java.util.concurrent package including CyclicBarrier and CopyOnWriteArrayList with a focus on the advantages over and differences from the traditional java.util collections - Use Lock, ReadWriteLock, and ReentrantLock classes in the java.util.concurrent.locks and java.util.concurrent.atomic packages to support lock-free thread-safe programming on single variables - Use Executor, ExecutorService, Executors, Callable, and Future to execute tasks using thread pools - Use the parallel Fork/Join Framework ##### Localization - Describe the advantages of localizing an application and developing code that defines, reads, and sets the locale with a Locale object - Build a resource bundle for a locale and call a resource bundle from an application - Create and manage date- and time-based events by using LocalDate, LocalTime, LocalDateTime, Instant, Period, and Duration, including a combination of date and time in a single object - Format dates, numbers, and currency values for localization with the NumberFormat and DateFormat classes, including number and date format patterns - Work with dates and times across time zones and manage changes resulting from daylight savings ##### Java File I/O (NIO.2) - Operate on file and directory paths by using the Paths class Check, delete, copy, or move a file or directory by using the Files class Recursively access a directory tree by using the DirectoryStream and FileVisitor interfaces - Find a file by using the PathMatcher interface, and use Java SE 8 I/O improvements, including Files.find(), Files.walk(), and lines() methods Observe the changes in a directory by using the WatchService interface ##### Lambda - Define and write functional interfaces and describe the interfaces of the java.util.function package - Describe a lambda expression; refactor the code that uses an anonymous inner class to use a lambda expression; describe type inference and target typing - Develop code that uses the built-in interfaces included in the java.util.function package, such as Function, Consumer, Supplier, UnaryOperator, Predicate, and Optional APIs, including the primitive and binary variations of the interfaces - Develop code that uses a method reference, including refactoring a lambda expression to a method reference ##### Java Collections - Develop code that uses diamond with generic declarations - Develop code that iterates a collection, filters a collection, and sorts a collection by using lambda expressions - Search for data by using methods, such as findFirst(), findAny(), anyMatch(), allMatch(), and noneMatch() - Perform calculations on Java Streams by using count, max, min, average, and sum methods and save results to a collection by using the collect method and Collector class, including the averagingDouble, groupingBy, joining, partitioningBy methods - Develop code that uses Java SE 8 collection improvements, including the Collection.removeIf(), List.replaceAll(), Map.computeIfAbsent(), and Map.computeIfPresent() methods - Develop code that uses the merge(), flatMap(), and map() methods on Java Streams ##### Java Streams - Describe the Stream interface and pipelines; create a stream by using the Arrays.stream() and IntStream.range() methods; identify the lambda operations that are lazy - Develop code that uses parallel streams, including decomposition operation and reduction operation in streams ## Java New Features Course Objectives Introducing Lambda Expressions - Describing the purpose of an anonymous inner class - Describing drawbacks to anonymous inner classes - Describing the components of a lambda expression - Defining a functional interface - Creating programs that use lambda expressions A Case for Lambda Expressions - Discussing the reasons for adding lambda expressions to the Java language - Reviewing the standard way of extracting data in Java - Refactoring code to reduce redundancy - Refactoring code to use inner classes - Refactoring code to use lambda expressions - Listing the benefits of lambda expressions Filtering Collections with Lambdas - Iterating though a collection with forEach - Iterating through a collection using lambda syntax - Describing the Stream interface - Filtering a collection using lambda expressions - Calling an existing method using a method reference - Chaining multiple methods together - Comparing function and imperative programming - Defining pipelines in terms of lambdas and collections Using Built in Lambda Types - Listing the built in interfaces included in java.util.function - Determining true or false with a Predicate - Processing an object and return nothing with Consumer - Processing one object and return another with Function - Generating a new object with Supplier - Using primitive versions of the base interfaces - Using binary versions of the base interfaces Collection Operations with Lambda - Extracting data from an object using map - Searching for data using search methods - Describing the types of stream operations - Describing the Optional class - Performing calculations using methods - Describing lazy processing - Sorting a stream - Saving results to a collection using the collect method - Parallel Streams - Reviewing the key characteristics of streams Contrasting old style loop operations with streams - Describing how to make a stream pipeline execute in parallel - Listing the key assumptions needed to use a parallel pipeline - Defining reduction - Describing why reduction requires an associative function - Calculating a value using reduce - Describing the process for decomposing and then merging work Lambda Cookbook - Modifying a list using removeIf - Updating a list using replaceAll - Updating a map using computeIfAbsent, computerIfPresent, and merge - Sending the keys and values from a map to a stream - Reading a file to a stream - Reading a text file into an ArrayList - List, walk, and search a directory structure using a stream - Flattening a stream using flatMap Method Enhancements - Considering the importance of building good libraries - Using static methods in Interfaces - Using default methods - Understanding default method inheritance rules Using the Date/Time API: Working with Local Dates and Times - Listing the goals of the Date/Time API (JSR-310) - Creating and manage date-based events - Creating and manage time-based events - Combining date and time into a single object Using the Date/Time API: Working with Time Zones - Working with dates and times across time-zones and manage changes resulting from daylight savings Using the Date/Time API: Working with Date and Time Amounts - Defining and create timestamps, periods and durations - Applying formatting to local and zoned dates and times JavaScript on Java with Nashorn: Creating and executing shell scripts - Creating and execute shell scripts using JavaScript and Nashorn - JavaScript on Java with Nashorn: Writing JavaScript Applications - Developing JavaScript applications that leverage Java code using Nashorn - JavaScript on Java with Nashorn: Writing JavaFX Applications Using JavaScript - Running JavaScript script from Java applications usingJSR-223 - Prototype JavaFX applications using Nashorn and JavaScript Intro to Mission Control - Describing JMX and Managed Beans with Mission Control - Monitoring CPU utilization with Mission Control - Analyzing JVM characteristics with Mission Control - Analyzing heap memory with Mission Control - Intro to Flight Recorder Describing the Java Flight Recorder - Describing the Java Flight Recorder Architecture - Starting a Java Flight Recording - Managing a Java Flight Recording - Analyzing a Java Flight Recording ## Java SE 6 Programmer Certified Professional Section 1: Declarations, Initialization and Scoping - Develop code that declares classes (including abstract and all forms of nested classes), interfaces, and enums, and includes the appropriate use of package and import statements (including static imports). - Develop code that declares an interface. Develop code that implements or extends one or more interfaces. - Develop code that declares an abstract class. Develop code that extends an abstract class. - Develop code that declares, initializes, and uses primitives, arrays, enums, and objects as static, instance, and local variables. Also, use legal identifiers for variable names. - Given a code example, determine if a method is correctly overriding or overloading another method, and identify legal return values (including covariant returns), for the method. - Given a set of classes and superclasses, develop constructors for one or more of the classes. Given a class declaration, determine if a default constructor will be created, and if so, determine the behavior of that constructor. Given a nested or non-nested class listing, write code to instantiate the class. Section 2: Flow Control - Develop code that implements an if or switch statement; and identify legal argument types for these statements. - Develop code that implements all forms of loops and iterators, including the use of for, the enhanced for loop (for-each), do, while, labels, break, and continue; and explain the values taken by loop counter variables during and after loop execution. - Develop code that makes use of assertions, and distinguish appropriate from inappropriate uses of assertions. - Develop code that makes use of exceptions and exception handling clauses (try, catch, finally), and declares methods and overriding methods that throw exceptions. - Recognize the effect of an exception arising at a specified point in a code fragment. Note that the exception may be a runtime exception, a checked exception, or an error. - Recognize situations that will result in any of the following being thrown: ArrayIndexOutOfBoundsException,ClassCastException, IllegalArgumentException, IllegalStateException, NullPointerException, NumberFormatException, AssertionError, ExceptionInInitializerError, StackOverflowError or NoClassDefFoundError. Understand which of these are thrown by the virtual machine and recognize situations in which others should be thrown programatically. Section 3: API Contents - Develop code that uses the primitive wrapper classes (such as Boolean, Character, Double, Integer, etc.), and/or autoboxing & unboxing. Discuss the differences between the String, StringBuilder, and StringBuffer classes. - Given a scenario involving navigating file systems, reading from files, writing to files, or interacting with the user, develop the correct solution using the following classes (sometimes in combination), from java.io: BufferedReader, BufferedWriter, File, FileReader, FileWriter, PrintWriter, and Console. - Use standard J2SE APIs in the java.text package to correctly format or parse dates, numbers, and currency values for a specific locale; and, given a scenario, determine the appropriate methods to use if you want to use the default locale or a specific locale. Describe the purpose and use of the java.util.Locale class. - Write code that uses standard J2SE APIs in the java.util and java.util.regex packages to format or parse strings or streams. For strings, write code that uses the Pattern and Matcher classes and the String.split method. Recognize and use regular expression patterns for matching (limited to: . (dot), * (star), + (plus), ?, \d, \s, \w, [], ()). The use of *, +, and ? will be limited to greedy quantifiers, and the parenthesis operator will only be used as a grouping mechanism, not for capturing content during matching. For streams, write code using the Formatter and Scanner classes and the PrintWriter.format/printf methods. Recognize and use formatting parameters (limited to: %b, %c, %d, %f, %s) in format strings. Section 4: Concurrency - Write code to define, instantiate, and start new threads using both java.lang.Thread and java.lang.Runnable. - Recognize the states in which a thread can exist, and identify ways in which a thread can transition from one state to another. - Given a scenario, write code that makes appropriate use of object locking to protect static or instance variables from concurrent access problems. Section 5: OO Concepts - Develop code that implements tight encapsulation, loose coupling, and high cohesion in classes, and describe the benefits. - Given a scenario, develop code that demonstrates the use of polymorphism. Further, determine when casting will be necessary and recognize compiler vs. runtime errors related to object reference casting. - Explain the effect of modifiers on inheritance with respect to constructors, instance or static variables, and instance or static methods. - Given a scenario, develop code that declares and/or invokes overridden or overloaded methods and code that declares and/or invokes superclass, or overloaded constructors. - Develop code that implements "is-a" and/or "has-a" relationships. Section 6: Collections / Generics - Given a design scenario, determine which collection classes and/or interfaces should be used to properly implement that design, including the use of the Comparable interface. - Distinguish between correct and incorrect overrides of corresponding hashCode and equals methods, and explain the difference between == and the equals method. - Write code that uses the generic versions of the Collections API, in particular, the Set, List, and Map interfaces and implementation classes. Recognize the limitations of the non-generic Collections API and how to refactor code to use the generic versions. Write code that uses the NavigableSet and NavigableMap interfaces. - Develop code that makes proper use of type parameters in class/interface declarations, instance variables, method arguments, and return types; and write generic methods or methods that make use of wildcard types and understand the similarities and differences between these two approaches. - Use capabilities in the java.util package to write code to manipulate a list by sorting, performing a binary search, or converting the list to an array. Use capabilities in the java.util package to write code to manipulate an array by sorting, performing a binary search, or converting the array to a list. Use the java.util.Comparator and java.lang.Comparable interfaces to affect the sorting of lists and arrays. Furthermore, recognize the effect of the "natural ordering" of primitive wrapper classes and java.lang.String on sorting. Section 7: Fundamentals - Given a code example and a scenario, write code that uses the appropriate access modifiers, package declarations, and import statements to interact with (through access or inheritance) the code in the example. - Given an example of a class and a command-line, determine the expected runtime behavior. - Determine the effect upon object references and primitive values when they are passed into methods that perform assignments or other modifying operations on the parameters. - Given a code example, recognize the point at which an object becomes eligible for garbage collection, determine what is and is not guaranteed by the garbage collection system, and recognize the behaviors of the Object.finalize() method. - Given the fully-qualified name of a class that is deployed inside and/or outside a JAR file, construct the appropriate directory structure for that class. Given a code example and a classpath, determine whether the classpath will allow the code to compile successfully. - Write code that correctly applies the appropriate operators including assignment operators (limited to: =, +=, -=), arithmetic operators (limited to: +, -, *, /, %, ++, --), relational operators (limited to: <, <=, >, >=, ==, !=), the instanceof operator, logical operators (limited to: &, |, ^, !, &&, ||), and the conditional operator ( ? : ), to produce a desired result. Write code that determines the equality of two objects or two primitives. ## Preparation Course For Java Certification 1 Getting Started - Examine Java technology - Analyze a simple Java technology application - Execute a Java technology application Object-Oriented Programming - Define modeling concepts: abstraction, encapsulation, and packages - Discuss Java technology application code reuse - Define class, member, attribute, method, constructor, and package - Use the access modifiers private and public as appropriate for the guidelines of encapsulation Invoke a method on a particular object - Use the Java technology API online documentation Identifiers, Keywords, and Types - Use comments in a source program - Distinguish between valid and invalid identifiers - Use the eight primitive types - Define literal values for numeric and textual types - Define the terms primitive variable and reference variable - Declare variables of class type - Construct an object using new and describe default initialization - Describe the significance of a reference variable Expressions and Flow Control - Distinguish between instance and local variables - Describe how to initialize instance variables - Recognize, describe, and use Java software operators - Distinguish between legal and illegal assignments of primitive types - Identify boolean expressions and their requirements in control constructs - Recognize assignment compatibility and required casts in fundamental types - Use if, switch, for, while, and do constructions and the labeled forms of break and continue as flow control structures in a progra Arrays - Declare and create arrays of primitive, class, or array types Explain why elements of an array are initialized - Explain how to initialize the elements of an array Determine the number of elements in an array - Create a multidimensional array - Write code to copy array values from one array to another Class Design - Define inheritance, polymorphism, overloading, overriding, and virtual method invocation - Use the access modifiers protected and the default (package-friendly) - Describe the concepts of constructor and method overloading - Describe the complete object construction and initialization operation Advanced Class Features - Create static variables, methods, and initializers - Create final classes, methods, and variables Create and use enumerated types - Use the static import statement - Create abstract classes and methods Create and use an interface Exceptions and Assertions - Define exceptions - Use try, catch, and finally statements - Describe exception categories - Identify common exceptions - Develop programs to handle your own exceptions - Use assertions - Distinguish appropriate and inappropriate uses of assertions - Enable assertions at runtime Collections and Generics Framework - Describe the general purpose implementations of the core interfaces in the Collections framework - Examine the Map interface - Examine the legacy collection classes - Create natural and custom ordering by implementing the Comparable and Comparator interfaces - Use generic collections and type parameters in generic classes - Refactor existing non-generic code - Write a program to iterate over a collection - Examine the enhanced for loop I/O Fundamentals - Write a program that uses command-line arguments and system properties - Examine the Properties class - Construct node and processing streams, and use them appropriately - Serialize and deserialize objects - Distinguish readers and writers from streams, and select appropriately between them Console I/ O and File I/O - Read data from the console Write data to the console Describe files and file I/O Threads - Define a thread - Create separate threads in a Java technology program, controlling the code and data that are used by that thread - Control the execution of a thread and write platform-independent code with threads - Describe the difficulties that might arise when multiple threads share data - Use wait and notify to communicate between threads - Use synchronized to protect data from corruption ## Preparation Course For Java Certification 2 Explaining Java Technology - Describe key concepts of the Java programming language - List the three Java technology product groups - Summarize each of the seven stages of the product life cycle Analyzing a Problem and Designing a Solution - Analyze a problem using object-oriented analysis - Design classes from which objects will be created Developing and Testing a Java Technology Program - Identify the four components of a class in the Java programming language - Use the main method in a test class to run a Java technology program from the command line - Compile and execute a Java technology program Declaring, Initializing, and Using Variables - Identify the use the syntax for variables and define the syntax for a variable - List the eight Java programming language primitive data types - Declare, initialize, and use variables and constants according to Java programming language guidelines and coding standards - Modify variable values using operators - Use promotion and type casting Creating and Using Objects - Declare, instantiate, and initialize object reference variables - Compare how object reference variables are stored in relation to primitive variables - Use a class (the String class) included in the Java Software Developer Kit (SDK) - Use the Java 2 Platform, Standard Edition (J2SE) class library specification to learn about other classes in this application programming interface (API) Using Operators and Decision Constructs - Identify relational and conditional operators - Create if and if/else constructs - Use the switch construct Using Loop Constructs - Create while loops - Develop for loops - Create do/while loops Developing and Using Methods - Describe the advantages of methods and define worker and calling methods - Declare and invoke a method - Compare object and static methods - Use overloaded methods Implementing Encapsulation and Constructors - Use encapsulation to protect data - Create constructors to initialize objects Creating and Using Arrays - Code one-dimensional arrays - Set array values using length attribute and a loop - Pass arguments to the main method for use in a program - Create two-dimensional arrays Implementing Inheritance - Define and test your use of inheritance - Explain abstraction - Explicitly identify class libraries used in your code ## Oracle Certified Associate or Java SE 8 Programmer I : 1Z0-808 Java Basics - Define the scope of variables - Define the structure of a Java class - Create executable Java applications with a main method; run a Java program from the command line; including console output. - Import other Java packages to make them accessible in your code - Compare and contrast the features and components of Java such as: platform independence, object orientation, encapsulation, etc. Working With Java Data Types - Declare and initialize variables (including casting of primitive data types) - Differentiate between object reference variables and primitive variables - Know how to read or write to object fields - Explain an Object's Lifecycle (creation, "dereference by reassignment" and garbage collection) - Develop code that uses wrapper classes such as Boolean, Double, and Integer. Using Operators and Decision Constructs - Use Java operators; including parentheses to override operator precedence - Test equality between Strings and other objects using == and equals () - Create if and if/else and ternary constructs - Use a switch statement Creating and Using Arrays - Declare, instantiate, initialize and use a one-dimensional array - Declare, instantiate, initialize and use multi-dimensional array Using Loop Constructs - Create and use while loops - Create and use for loops including the enhanced for loop - Create and use do/while loops - Compare loop constructs - Use break and continue Working with Methods and Encapsulation - Create methods with arguments and return values; including overloaded methods - Apply the static keyword to methods and fields - Create and overload constructors; including impact on default constructors - Apply access modifiers - Apply encapsulation principles to a class - Determine the effect upon object references and primitive values when they are passed into methods that change the values Working with Inheritance - Describe inheritance and its benefits - Develop code that demonstrates the use of polymorphism; including overriding and object type versus reference type - Determine when casting is necessary - Use super and this to access objects and constructors - Use abstract classes and interfaces Handling Exceptions - Differentiate among checked exceptions, unchecked exceptions, and Errors - Create a try-catch block and determine how exceptions alter normal program flow - Describe the advantages of Exception handling - Create and invoke a method that throws an exception - "Recognize common exception classes (such as NullPointerException, ArithmeticExcpetion, ArrayIndexOutOfBoundsException, ClassCastException)" Working with Selected classes from the Java API - Manipulate data using the StringBuilder class and its methods - Creating and manipulating Strings - Create and manipulate calendar data using classes from java.time.LocalDateTime, java.time.LocalDate, java.time.LocalTime, java.time.format.DateTimeFormatter, java.time.Period - Declare and use an ArrayList of a given type - Write a simple Lambda expression that consumes a Lambda Predicate expression ## Oracle Certified Professional or Java SE 8 Programmer II - 1Z0-809 Java Class Design - Implement encapsulation - Implement inheritance including visibility modifiers and composition - Implement polymorphism - Override hashCode, equals, and toString methods from Object class - Create and use singleton classes and immutable classes - Develop code that uses static keyword on initialize blocks, variables, methods, and classes Advanced Java Class Design - Develop code that uses abstract classes and methods - Develop code that uses final keyword - Create inner classes including static inner class, local class, nested class, and anonymous inner class - Use enumerated types including methods, and constructors in an enum type - Develop code that declares, implements and/or extends interfaces and use the atOverride annotation. - Create and use Lambda expressions Generics and Collections - Create and use a generic class - Create and use ArrayList, TreeSet, TreeMap, and ArrayDeque objects - Use java.util.Comparator and java.lang.Comparable interfaces - Collections Streams and Filters - Iterate using forEach methods of Streams and List - Describe Stream interface and Stream pipeline - Filter a collection by using lambda expressions - Use method references with Streams Lambda Built-in Functional Interfaces - Use the built-in interfaces included in the java.util.function package such as Predicate, Consumer, Function, and Supplier - Develop code that uses primitive versions of functional interfaces - Develop code that uses binary versions of functional interfaces - Develop code that uses the UnaryOperator interface Java Stream API - Develop code to extract data from an object using peek() and map() methods including primitive versions of the map() method - Search for data by using search methods of the Stream classes including findFirst, findAny, anyMatch, allMatch, noneMatch - Develop code that uses the Optional class - Develop code that uses Stream data methods and calculation methods - Sort a collection using Stream API - Save results to a collection using the collect method and group/partition data using the Collectors class - Use flatMap() methods in the Stream API Exceptions and Assertions - Use try-catch and throw statements - Use catch, multi-catch, and finally clauses - Use Autoclose resources with a try-with-resources statement - Create custom exceptions and Auto-closeable resources - Test invariants by using assertions Use Java SE 8 Date/Time API - Create and manage date-based and time-based events including a combination of date and time into a single object using LocalDate, LocalTime, LocalDateTime, Instant, Period, and Duration - Work with dates and times across timezones and manage changes resulting from daylight savings including Format date and times values - Define and create and manage date-based and time-based events using Instant, Period, Duration, and TemporalUnit Java I/O Fundamentals - Read and write data from the console - Use BufferedReader, BufferedWriter, File, FileReader, FileWriter, FileInputStream, FileOutputStream, ObjectOutputStream, ObjectInputStream, and PrintWriter in the java.iopackage. Java File I/O (NIO.2) - Use Path interface to operate on file and directory paths - Use Files class to check, read, delete, copy, move, manage metadata of a file or directory - Use Stream API with NIO.2 Java Concurrency - Create worker threads using Runnable, Callable and use an ExecutorService to concurrently execute tasks - Identify potential threading problems among deadlock, starvation, livelock, and race conditions - Use synchronized keyword and java.util.concurrent.atomic package to control the order of thread execution - Use java.util.concurrent collections and classes including CyclicBarrier and CopyOnWriteArrayList - Use parallel Fork/Join Framework - Use parallel Streams including reduction, decomposition, merging processes, pipelines and performance. Building Database Applications with JDBC - Describe the interfaces that make up the core of the JDBC API including the Driver, Connection, Statement, and ResultSet interfaces and their relationship to provider implementations - Identify the components required to connect to a database using the DriverManager class including the JDBC URL - Submit queries and read results from the database including creating statements, returning result sets, iterating through the results, and properly closing result sets, statements, and connections Localization - Read and set the locale by using the Locale object - Create and read a Properties file - Build a resource bundle for each locale and load a resource bundle in an application ================================================ FILE: JavaScript/README.md ================================================ # Modern JavaScript Cheatsheet ![Modern JavaScript cheatsheet](https://i.imgur.com/aexPxMb.png) ## Introduction ### Motivation This document is a cheatsheet for JavaScript you will frequently encounter in modern projects and most contemporary sample code. This guide is not intended to teach you JavaScript from the ground up, but to help developers with basic knowledge who may struggle to get familiar with modern codebases (or let's say to learn React for instance) because of the JavaScript concepts used. Besides, I will sometimes provide personal tips that may be debatable but will take care to mention that it's a personal recommendation when I do so. > **Note:** Most of the concepts introduced here are coming from a JavaScript language update (ES2015, often called ES6). You can find new features added by this update [here](http://es6-features.org); it's very well done. ### Complementary Resources When you struggle to understand a notion, I suggest you look for answers on the following resources: - [MDN (Mozilla Developer Network)](https://developer.mozilla.org/en-US/search?q=) - [You don't know JS (book)](https://github.com/getify/You-Dont-Know-JS) - [ES6 Features with examples](http://es6-features.org) - [WesBos blog (ES6)](http://wesbos.com/category/es6/) - [Javascript Basics for Beginners](https://www.udacity.com/course/javascript-basics--ud804) - a free Udacity course - [Reddit (JavaScript)](https://www.reddit.com/r/javascript/) - [Google](https://www.google.com/) to find specific blog and resources - [StackOverflow](https://stackoverflow.com/questions/tagged/javascript) ## Table of Contents - [Modern JavaScript cheatsheet](#modern-javascript-cheatsheet) * [Introduction](#introduction) + [Motivation](#motivation) + [Complementary resources](#complementary-resources) * [Table of contents](#table-of-contents) * [Notions](#notions) + [Variable declaration: var, const, let](#variable-declaration-var-const-let) - [Short explanation](#short-explanation) - [Sample code](#sample-code) - [Detailed explanation](#detailed-explanation) - [External resource](#external-resource) + [Arrow function](#-arrow-function) - [Sample code](#sample-code-1) - [Detailed explanation](#detailed-explanation-1) * [Concision](#concision) * [*this* reference](#this-reference) - [Useful resources](#useful-resources) + [Function default parameter value](#function-default-parameter-value) - [External resource](#external-resource-1) + [Destructuring objects and arrays](#destructuring-objects-and-arrays) - [Explanation with sample code](#explanation-with-sample-code) - [Useful resources](#useful-resources-1) + [Array methods - map / filter / reduce](#array-methods---map--filter--reduce) - [Sample code](#sample-code-2) - [Explanation](#explanation) * [Array.prototype.map()](#arrayprototypemap) * [Array.prototype.filter()](#arrayprototypefilter) * [Array.prototype.reduce()](#arrayprototypereduce) - [External Resource](#external-resource-2) + [Spread operator "..."](#spread-operator-) - [Sample code](#sample-code-3) - [Explanation](#explanation-1) * [In iterables (like arrays)](#in-iterables-like-arrays) * [Function rest parameter](#function-rest-parameter) * [Object properties spreading](#object-properties-spreading) - [External resources](#external-resources) + [Object property shorthand](#object-property-shorthand) - [Explanation](#explanation-2) - [External resources](#external-resources-1) + [Promises](#promises) - [Sample code](#sample-code-4) - [Explanation](#explanation-3) * [Create the promise](#create-the-promise) * [Promise handlers usage](#promise-handlers-usage) - [External Resources](#external-resources-2) + [Template literals](#template-literals) - [Sample code](#sample-code-5) - [External resources](#external-resources-3) + [Tagged Template Literals](#tagged-template-literals) - [External resources](#external-resources-4) + [Imports / Exports](#imports--exports) - [Explanation with sample code](#explanation-with-sample-code-1) * [Named exports](#named-exports) * [Default import / export](#default-import--export) - [External resources](#external-resources-5) + [JavaScript *this*](#-javascript-this) - [External resources](#external-resources-6) + [Class](#class) - [Samples](#samples) - [External resources](#external-resources-7) + [Extends and super keywords](#extends-and-super-keywords) - [Sample Code](#sample-code-6) - [External Resources](#external-resources-8) + [Async Await](#async-await) - [Sample code](#sample-code-7) - [Explanation with sample code](#explanation-with-sample-code-2) - [Error handling](#error-handling) - [External resources](#external-resources-9) + [Truthy / Falsy](#truthy--falsy) - [External resources](#external-resources-10) + [Anamorphisms / Catamporphisms](#anamorphisms-and-catamorphisms) - [Anamorphisms](#anamorphisms) - [Catamorphisms](#catamorphisms) - [External resources](#external-resources-11) + [Generators](#generators) - [External resources](#external-resources-12) + [Static Methods](#static-methods) - [Short Explanation](#short-explanation-1) - [Sample Code](#sample-code-8) - [Detailed Explanation](#detailed-explanation-2) * [Calling other static methods from a static method](#calling-other-static-methods-from-a-static-method) * [Calling static methods from non-static methods](#calling-static-methods-from-non-static-methods) - [External resources](#external-resources-13) * [Glossary](#glossary) + [Scope](#-scope) + [Variable mutation](#-variable-mutation) ## Notions ### Variable declaration: var, const, let In JavaScript, there are three keywords available to declare a variable, and each has its differences. Those are ```var```, ```let``` and ```const```. #### Short explanation Variables declared with ```const``` keyword can't be reassigned, while ```let``` and ```var``` can. I recommend always declaring your variables with ```const``` by default, and with ```let``` if you need to *mutate* it or reassign it later.
Scope Reassignable Mutable Temporal Dead Zone
const Block No Yes Yes
let Block Yes Yes Yes
var Function Yes Yes No
#### Sample code ```javascript const person = "Nick"; person = "John" // Will raise an error, person can't be reassigned ``` ```javascript let person = "Nick"; person = "John"; console.log(person) // "John", reassignment is allowed with let ``` #### Detailed explanation The [*scope*](#scope_def) of a variable roughly means "where is this variable available in the code". ##### var ```var``` declared variables are *function scoped*, meaning that when a variable is created in a function, everything in that function can access that variable. Besides, a *function scoped* variable created in a function can't be accessed outside this function. I recommend you to picture it as if an *X scoped* variable meant that this variable was a property of X. ```javascript function myFunction() { var myVar = "Nick"; console.log(myVar); // "Nick" - myVar is accessible inside the function } console.log(myVar); // Throws a ReferenceError, myVar is not accessible outside the function. ``` Still focusing on the variable scope, here is a more subtle example: ```javascript function myFunction() { var myVar = "Nick"; if (true) { var myVar = "John"; console.log(myVar); // "John" // actually, myVar being function scoped, we just erased the previous myVar value "Nick" for "John" } console.log(myVar); // "John" - see how the instructions in the if block affected this value } console.log(myVar); // Throws a ReferenceError, myVar is not accessible outside the function. ``` Besides, *var* declared variables are moved to the top of the scope at execution. This is what we call [var hoisting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting). This portion of code: ```js console.log(myVar) // undefined -- no error raised var myVar = 2; ``` is understood at execution like: ```js var myVar; console.log(myVar) // undefined -- no error raised myVar = 2; ``` ##### let ```var``` and ```let ``` are about the same, but ```let``` declared variables - are *block scoped* - are **not** accessible before they are assigned - can't be re-declared in the same scope Let's see the impact of block-scoping taking our previous example: ```javascript function myFunction() { let myVar = "Nick"; if (true) { let myVar = "John"; console.log(myVar); // "John" // actually, myVar being block scoped, we just created a new variable myVar. // this variable is not accessible outside this block and totally independent // from the first myVar created ! } console.log(myVar); // "Nick", see how the instructions in the if block DID NOT affect this value } console.log(myVar); // Throws a ReferenceError, myVar is not accessible outside the function. ```
Now, what it means for *let* (and *const*) variables for not being accessible before being assigned: ```js console.log(myVar) // raises a ReferenceError ! let myVar = 2; ``` By contrast with *var* variables, if you try to read or write on a *let* or *const* variable before they are assigned an error will be raised. This phenomenon is often called [*Temporal dead zone*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let) or *TDZ*. > **Note:** Technically, *let* and *const* variables declarations are being hoisted too, but not their assignation. Since they're made so that they can't be used before assignation, it intuitively feels like there is no hoisting, but there is. Find out more on this [very detailed explanation here](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) if you want to know more. In addition, you can't re-declare a *let* variable: ```js let myVar = 2; let myVar = 3; // Raises a SyntaxError ``` ##### const ```const``` declared variables behave like *let* variables, but also they can't be reassigned. To sum it up, *const* variables: - are *block scoped* - are not accessible before being assigned - can't be re-declared in the same scope - can't be reassigned ```js const myVar = "Nick"; myVar = "John" // raises an error, reassignment is not allowed ``` ```js const myVar = "Nick"; const myVar = "John" // raises an error, re-declaration is not allowed ``` But there is a subtlety : ```const``` variables are not [**immutable**](#mutation_def) ! Concretely, it means that *object* and *array* ```const``` declared variables **can** be mutated. For objects: ```js const person = { name: 'Nick' }; person.name = 'John' // this will work ! person variable is not completely reassigned, but mutated console.log(person.name) // "John" person = "Sandra" // raises an error, because reassignment is not allowed with const declared variables ``` For arrays: ```js const person = []; person.push('John'); // this will work ! person variable is not completely reassigned, but mutated console.log(person[0]) // "John" person = ["Nick"] // raises an error, because reassignment is not allowed with const declared variables ``` #### External resource - [How let and const are scoped in JavaScript - WesBos](http://wesbos.com/javascript-scoping/) - [Temporal Dead Zone (TDZ) Demystified](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) ### Arrow function The ES6 JavaScript update has introduced *arrow functions*, which is another way to declare and use functions. Here are the benefits they bring: - More concise - *this* is picked up from surroundings - implicit return #### Sample code - Concision and implicit return ```js function double(x) { return x * 2; } // Traditional way console.log(double(2)) // 4 ``` ```js const double = x => x * 2; // Same function written as an arrow function with implicit return console.log(double(2)) // 4 ``` - *this* reference In an arrow function, *this* is equal to the *this* value of the enclosing execution context. Basically, with arrow functions, you don't have to do the "that = this" trick before calling a function inside a function anymore. ```js function myFunc() { this.myVar = 0; setTimeout(() => { this.myVar++; console.log(this.myVar) // 1 }, 0); } ``` #### Detailed explanation ##### Concision Arrow functions are more concise than traditional functions in many ways. Let's review all the possible cases: - Implicit VS Explicit return An **explicit return** is a function where the *return* keyword is used in its body. ```js function double(x) { return x * 2; // this function explicitly returns x * 2, *return* keyword is used } ``` In the traditional way of writing functions, the return was always explicit. But with arrow functions, you can do *implicit return* which means that you don't need to use the keyword *return* to return a value. ```js const double = (x) => { return x * 2; // Explicit return here } ``` Since this function only returns something (no instructions before the *return* keyword) we can do an implicit return. ```js const double = (x) => x * 2; // Correct, returns x*2 ``` To do so, we only need to **remove the brackets** and the **return** keyword. That's why it's called an *implicit* return, the *return* keyword is not there, but this function will indeed return ```x * 2```. > **Note:** If your function does not return a value (with *side effects*), it doesn't do an explicit nor an implicit return. Besides, if you want to implicitly return an *object* you **must have parentheses around it** since it will conflict with the block braces: ```js const getPerson = () => ({ name: "Nick", age: 24 }) console.log(getPerson()) // { name: "Nick", age: 24 } -- object implicitly returned by arrow function ``` - Only one argument If your function only takes one parameter, you can omit the parentheses around it. If we take back the above *double* code: ```js const double = (x) => x * 2; // this arrow function only takes one parameter ``` Parentheses around the parameter can be avoided: ```js const double = x => x * 2; // this arrow function only takes one parameter ``` - No arguments When there is no argument provided to an arrow function, you need to provide parentheses, or it won't be valid syntax. ```js () => { // parentheses are provided, everything is fine const x = 2; return x; } ``` ```js => { // No parentheses, this won't work! const x = 2; return x; } ``` ##### *this* reference To understand this subtlety introduced with arrow functions, you must know how [this](#this_def) behaves in JavaScript. In an arrow function, *this* is equal to the *this* value of the enclosing execution context. What it means is that an arrow function doesn't create a new *this*, it grabs it from its surrounding instead. Without arrow function, if you wanted to access a variable from *this* in a function inside a function, you had to use the *that = this* or *self = this* trick. For instance, using setTimeout function inside myFunc: ```js function myFunc() { this.myVar = 0; var that = this; // that = this trick setTimeout( function() { // A new *this* is created in this function scope that.myVar++; console.log(that.myVar) // 1 console.log(this.myVar) // undefined -- see function declaration above }, 0 ); } ``` But with arrow function, *this* is taken from its surrounding: ```js function myFunc() { this.myVar = 0; setTimeout( () => { // this taken from surrounding, meaning myFunc here this.myVar++; console.log(this.myVar) // 1 }, 0 ); } ``` #### Useful resources - [Arrow functions introduction - WesBos](http://wesbos.com/arrow-functions/) - [JavaScript arrow function - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - [Arrow function and lexical *this*](https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4) ### Function default parameter value Starting from ES2015 JavaScript update, you can set default value to your function parameters using the following syntax: ```js function myFunc(x = 10) { return x; } console.log(myFunc()) // 10 -- no value is provided so x default value 10 is assigned to x in myFunc console.log(myFunc(5)) // 5 -- a value is provided so x is equal to 5 in myFunc console.log(myFunc(undefined)) // 10 -- undefined value is provided so default value is assigned to x console.log(myFunc(null)) // null -- a value (null) is provided, see below for more details ``` The default parameter is applied in two and only two situations: - No parameter provided - *undefined* parameter provided In other words, if you pass in *null* the default parameter **won't be applied**. > **Note:** Default value assignment can be used with destructured parameters as well (see next notion to see an example) #### External resource - [Default parameter value - ES6 Features](http://es6-features.org/#DefaultParameterValues) - [Default parameters - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) ### Destructuring objects and arrays *Destructuring* is a convenient way of creating new variables by extracting some values from data stored in objects or arrays. To name a few use cases, *destructuring* can be used to destructure function parameters or *this.props* in React projects for instance. #### Explanation with sample code - Object Let's consider the following object for all the samples: ```js const person = { firstName: "Nick", lastName: "Anderson", age: 35, sex: "M" } ``` Without destructuring ```js const first = person.firstName; const age = person.age; const city = person.city || "Paris"; ``` With destructuring, all in one line: ```js const { firstName: first, age, city = "Paris" } = person; // That's it ! console.log(age) // 35 -- A new variable age is created and is equal to person.age console.log(first) // "Nick" -- A new variable first is created and is equal to person.firstName console.log(firstName) // ReferenceError -- person.firstName exists BUT the new variable created is named first console.log(city) // "Paris" -- A new variable city is created and since person.city is undefined, city is equal to the default value provided "Paris". ``` **Note :** In ```const { age } = person;```, the brackets after *const* keyword are not used to declare an object nor a block but is the *destructuring* syntax. - Function parameters *Destructuring* is often used to destructure objects parameters in functions. Without destructuring ```js function joinFirstLastName(person) { const firstName = person.firstName; const lastName = person.lastName; return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` In destructuring the object parameter *person*, we get a more concise function: ```js function joinFirstLastName({ firstName, lastName }) { // we create firstName and lastName variables by destructuring person parameter return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` Destructuring is even more pleasant to use with [arrow functions](#arrow_func_concept): ```js const joinFirstLastName = ({ firstName, lastName }) => firstName + '-' + lastName; joinFirstLastName(person); // "Nick-Anderson" ``` - Array Let's consider the following array: ```js const myArray = ["a", "b", "c"]; ``` Without destructuring ```js const x = myArray[0]; const y = myArray[1]; ``` With destructuring ```js const [x, y] = myArray; // That's it ! console.log(x) // "a" console.log(y) // "b" ``` #### Useful resources - [ES6 Features - Destructuring Assignment](http://es6-features.org/#ArrayMatching) - [Destructuring Objects - WesBos](http://wesbos.com/destructuring-objects/) - [ExploringJS - Destructuring](http://exploringjs.com/es6/ch_destructuring.html) ### Array methods - map / filter / reduce *Map*, *filter* and *reduce* are array methods that are coming from a programming paradigm named [*functional programming*](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0). To sum it up: - **Array.prototype.map()** takes an array, does something on its elements and returns an array with the transformed elements. - **Array.prototype.filter()** takes an array, decides element by element if it should keep it or not and returns an array with the kept elements only - **Array.prototype.reduce()** takes an array and aggregates the elements into a single value (which is returned) I recommend to use them as much as possible in following the principles of functional programming because they are composable, concise and elegant. With those three methods, you can avoid the use of *for* and *forEach* loops in most situations. When you are tempted to do a *for* loop, try to do it with *map*, *filter* and *reduce* composed. You might struggle to do it at first because it requires you to learn a new way of thinking, but once you've got it things get easier. #### Sample code ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; const doubledNumbers = numbers.map(n => n * 2); // [0, 2, 4, 6, 8, 10, 12] const evenNumbers = numbers.filter(n => n % 2 === 0); // [0, 2, 4, 6] const sum = numbers.reduce((prev, next) => prev + next, 0); // 21 ``` Compute total grade sum for students with grades 10 or above by composing map, filter and reduce: ```js const students = [ { name: "Nick", grade: 10 }, { name: "John", grade: 15 }, { name: "Julia", grade: 19 }, { name: "Nathalie", grade: 9 }, ]; const aboveTenSum = students .map(student => student.grade) // we map the students array to an array of their grades .filter(grade => grade >= 10) // we filter the grades array to keep those 10 or above .reduce((prev, next) => prev + next, 0); // we sum all the grades 10 or above one by one console.log(aboveTenSum) // 44 -- 10 (Nick) + 15 (John) + 19 (Julia), Nathalie below 10 is ignored ``` #### Explanation Let's consider the following array of numbers for our examples: ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; ``` ##### Array.prototype.map() ```js const doubledNumbers = numbers.map(function(n) { return n * 2; }); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` What's happening here? We are using .map on the *numbers* array, the map is iterating on each element of the array and passes it to our function. The goal of the function is to produce and return a new value from the one passed so that map can replace it. Let's extract this function to make it more clear, just for this once: ```js const doubleN = function(n) { return n * 2; }; const doubledNumbers = numbers.map(doubleN); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` **Note** : You will frequently encounter this method used in combination with [arrow functions](#-arrow-function) ```js const doubledNumbers = numbers.map(n => n * 2); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` ```numbers.map(doubleN)``` produces ```[doubleN(0), doubleN(1), doubleN(2), doubleN(3), doubleN(4), doubleN(5), doubleN(6)]``` which is equal to ```[0, 2, 4, 6, 8, 10, 12]```. > **Note:** If you do not need to return a new array and just want to do a loop that has side effects, you might just want to use a for / forEach loop instead of a map. ##### Array.prototype.filter() ```js const evenNumbers = numbers.filter(function(n) { return n % 2 === 0; // true if "n" is par, false if "n" isn't }); console.log(evenNumbers); // [0, 2, 4, 6] ``` **Note** : You will frequently encounter this method used in combination with [arrow functions](#-arrow-function) ```js const evenNumbers = numbers.filter(n => n % 2 === 0); console.log(evenNumbers); // [0, 2, 4, 6] ``` We are using .filter on the *numbers* array, filter is iterating on each element of the array and passes it to our function. The goal of the function is to return a boolean that will determine whether the current value will be kept or not. Filter then returns the array with only the kept values. ##### Array.prototype.reduce() The reduce method goal is to *reduce* all elements of the array it iterates on into a single value. How it aggregates those elements is up to you. ```js const sum = numbers.reduce( function(acc, n) { return acc + n; }, 0 // accumulator variable value at first iteration step ); console.log(sum) // 21 ``` **Note** : You will frequently encounter this method used in combination with [arrow functions](#-arrow-function) ```js const sum = numbers.reduce((acc, n) => acc + n, 0); console.log(sum) // 21 ``` Just like for .map and .filter methods, .reduce is applied on an array and takes a function as the first parameter. This time though, there are changes: - .reduce takes two parameters The first parameter is a function that will be called at each iteration step. The second parameter is the value of the accumulator variable (*acc* here) at the first iteration step (read next point to understand). - Function parameters The function you pass as the first parameter of .reduce takes two parameters. The first one (*acc* here) is the accumulator variable, whereas the second parameter (*n*) is the current element. The accumulator variable is equal to the return value of your function at the **previous** iteration step. At the first step of the iteration, *acc* is equal to the value you passed as .reduce second parameter. ###### At first iteration step ```acc = 0``` because we passed in 0 as the second parameter for reduce ```n = 0``` first element of the *number* array Function returns *acc* + *n* --> 0 + 0 --> 0 ###### At second iteration step ```acc = 0``` because it's the value the function returned at the previous iteration step ```n = 1``` second element of the *number* array Function returns *acc* + *n* --> 0 + 1 --> 1 ###### At third iteration step ```acc = 1``` because it's the value the function returned at the previous iteration step ```n = 2``` third element of the *number* array Function returns *acc* + *n* --> 1 + 2 --> 3 ###### At fourth iteration step ```acc = 3``` because it's the value the function returned at the previous iteration step ```n = 3``` fourth element of the *number* array Function returns *acc* + *n* --> 3 + 3 --> 6 ###### [...] At last iteration step ```acc = 15``` because it's the value the function returned at the previous iteration step ```n = 6``` last element of the *number* array Function returns *acc* + *n* --> 15 + 6 --> 21 As it is the last iteration step, **.reduce** returns 21. #### External Resource - [Understanding map / filter / reduce in JS](https://hackernoon.com/understanding-map-filter-and-reduce-in-javascript-5df1c7eee464) ### Spread operator "..." The spread operator ```...``` has been introduced with ES2015 and is used to expand elements of an iterable (like an array) into places where multiple elements can fit. #### Sample code ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ```js function myFunc(x, y, ...params) { console.log(x); console.log(y); console.log(params) } myFunc("a", "b", "c", "d", "e", "f") // "a" // "b" // ["c", "d", "e", "f"] ``` ```js const { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } ``` #### Explanation ##### In iterables (like arrays) If we have the two following arrays: ```js const arr1 = ["a", "b", "c"]; const arr2 = [arr1, "d", "e", "f"]; // [["a", "b", "c"], "d", "e", "f"] ``` *arr2* the first element is an array because *arr1* is injected as is into *arr2*. But what we want is *arr2* to be an array of letters. To do so, we can *spread* the elements of *arr1* into *arr2*. With spread operator ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ##### Function rest parameter In function parameters, we can use the rest operator to inject parameters into an array we can loop in. There is already an **arguments** object bound to every function that is equal to an array of all the parameters passed into the function. ```js function myFunc() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } myFunc("Nick", "Anderson", 10, 12, 6); // "Nick" // "Anderson" // 10 // 12 // 6 ``` But let's say that we want this function to create a new student with its grades and with its average grade. Wouldn't it be more convenient to extract the first two parameters into two separate variables, and then have all the grades in an array we can iterate over? That's exactly what the rest operator allows us to do! ```js function createStudent(firstName, lastName, ...grades) { // firstName = "Nick" // lastName = "Anderson" // [10, 12, 6] -- "..." takes all other parameters passed and creates a "grades" array variable that contains them const avgGrade = grades.reduce((acc, curr) => acc + curr, 0) / grades.length; // computes average grade from grades return { firstName: firstName, lastName: lastName, grades: grades, avgGrade: avgGrade } } const student = createStudent("Nick", "Anderson", 10, 12, 6); console.log(student); // { // firstName: "Nick", // lastName: "Anderson", // grades: [10, 12, 6], // avgGrade: 9,33 // } ``` > **Note:** createStudent function is bad because we don't check if grades.length exists or is different from 0. But it's easier to read this way, so I didn't handle this case. ##### Object properties spreading For this one, I recommend you read previous explanations about the rest operator on iterables and function parameters. ```js const myObj = { x: 1, y: 2, a: 3, b: 4 }; const { x, y, ...z } = myObj; // object destructuring here console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } // z is the rest of the object destructured: myObj object minus x and y properties destructured const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } // Here z object properties are spread into n ``` #### External resources - [TC39 - Object rest/spread](https://github.com/tc39/proposal-object-rest-spread) - [Spread operator introduction - WesBos](https://github.com/wesbos/es6-articles/blob/master/28%20-%20Spread%20Operator%20Introduction.md) - [JavaScript & the spread operator](https://codeburst.io/javascript-the-spread-operator-a867a71668ca) - [6 Great uses of the spread operator](https://davidwalsh.name/spread-operator) ### Object property shorthand When assigning a variable to an object property, if the variable name is equal to the property name, you can do the following: ```js const x = 10; const myObj = { x }; console.log(myObj.x) // 10 ``` #### Explanation Usually (pre-ES2015) when you declare a new *object literal* and want to use variables as object properties values, you would write this kind of code: ```js const x = 10; const y = 20; const myObj = { x: x, // assigning x variable value to myObj.x y: y // assigning y variable value to myObj.y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` As you can see, this is quite repetitive because the properties name of myObj are the same as the variable names you want to assign to those properties. With ES2015, when the variable name is the same as the property name, you can do this shorthand: ```js const x = 10; const y = 20; const myObj = { x, y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` #### External resources - [Property shorthand - ES6 Features](http://es6-features.org/#PropertyShorthand) ### Promises A promise is an object which can be returned synchronously from an asynchronous function ([ref](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#3cd0)). Promises can be used to avoid [callback hell](http://callbackhell.com/), and they are more and more frequently encountered in modern JavaScript projects. #### Sample code ```js const fetchingPosts = new Promise((res, rej) => { $.get("/posts") .done(posts => res(posts)) .fail(err => rej(err)); }); fetchingPosts .then(posts => console.log(posts)) .catch(err => console.log(err)); ``` #### Explanation When you do an *Ajax request* the response is not synchronous because you want a resource that takes some time to come. It even may never come if the resource you have requested is unavailable for some reason (404). To handle that kind of situation, ES2015 has given us *promises*. Promises can have three different states: - Pending - Fulfilled - Rejected Let's say we want to use promises to handle an Ajax request to fetch the resource X. ##### Create the promise We firstly are going to create a promise. We will use the jQuery get method to do our Ajax request to X. ```js const xFetcherPromise = new Promise( // Create promise using "new" keyword and store it into a variable function(resolve, reject) { // Promise constructor takes a function parameter which has resolve and reject parameters itself $.get("X") // Launch the Ajax request .done(function(X) { // Once the request is done... resolve(X); // ... resolve the promise with the X value as parameter }) .fail(function(error) { // If the request has failed... reject(error); // ... reject the promise with the error as parameter }); } ) ``` As seen in the above sample, the Promise object takes an *executor* function which takes two parameters **resolve** and **reject**. Those parameters are functions which when called are going to move the promise *pending* state to respectively a *fulfilled* and *rejected* state. The promise is in pending state after instance creation and its *executor* function is executed immediately. Once one of the function *resolve* or *reject* is called in the *executor* function, the promise will call its associated handlers. ##### Promise handlers usage To get the promise result (or error), we must attach to it handlers by doing the following: ```js xFetcherPromise .then(function(X) { console.log(X); }) .catch(function(err) { console.log(err) }) ``` If the promise succeeds, *resolve* is executed and the function passed as ```.then``` parameter is executed. If it fails, *reject* is executed and the function passed as ```.catch``` parameter is executed. > **Note :** If the promise has already been fulfilled or rejected when a corresponding handler is attached, the handler will be called, so there is no race condition between an asynchronous operation completing and its handlers being attached. [(Ref: MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#Description) #### External Resources - [JavaScript Promises for dummies - Jecelyn Yeen](https://scotch.io/tutorials/javascript-promises-for-dummies) - [JavaScript Promise API - David Walsh](https://davidwalsh.name/promises) - [Using promises - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) - [What is a promise - Eric Elliott](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261) - [JavaScript Promises: an Introduction - Jake Archibald](https://developers.google.com/web/fundamentals/getting-started/primers/promises) - [Promise documentation - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) ### Template literals Template literals is an [*expression interpolation*](https://en.wikipedia.org/wiki/String_interpolation) for single and multiple-line strings. In other words, it is a new string syntax in which you can conveniently use any JavaScript expressions (variables for instance). #### Sample code ```js const name = "Nick"; `Hello ${name}, the following expression is equal to four : ${2+2}`; // Hello Nick, the following expression is equal to four: 4 ``` #### External resources - [String interpolation - ES6 Features](http://es6-features.org/#StringInterpolation) - [ES6 Template Strings - Addy Osmani](https://developers.google.com/web/updates/2015/01/ES6-Template-Strings) ### Tagged template literals Template tags are *functions that can be prefixed to a [template literal](#template-literals)*. When a function is called this way, the first parameter is an array of the *strings* that appear between the template's interpolated variables, and the subsequent parameters are the interpolated values. Use a spread operator `...` to capture all of them. [(Ref: MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals). > **Note :** A famous library named [styled-components](https://www.styled-components.com/) heavily relies on this feature. Below is a toy example on how they work. ```js function highlight(strings, ...values) { const interpolation = strings.reduce((prev, current) => { return prev + current + (values.length ? "" + values.shift() + "" : ""); }, ""); return interpolation; } const condiment = "jam"; const meal = "toast"; highlight`I like ${condiment} on ${meal}.`; // "I like jam on toast." ``` A more interesting example: ```js function comma(strings, ...values) { return strings.reduce((prev, next) => { let value = values.shift() || []; value = value.join(", "); return prev + next + value; }, ""); } const snacks = ['apples', 'bananas', 'cherries']; comma`I like ${snacks} to snack on.`; // "I like apples, bananas, cherries to snack on." ``` #### External resources - [Wes Bos on Tagged Template Literals](http://wesbos.com/tagged-template-literals/) - [Library of common template tags](https://github.com/declandewet/common-tags) ### Imports / Exports ES6 modules are used to access variables or functions in a module explicitly exported by the modules it imports. I highly recommend to take a look at MDN resources on import/export (see external resources below), it is both straightforward and complete. #### Explanation with sample code ##### Named exports Named exports are used to export several values from a module. > **Note :** You can only name-export [first-class citizens](https://en.wikipedia.org/wiki/First-class_citizen) that have a name. ```js // mathConstants.js export const pi = 3.14; export const exp = 2.7; export const alpha = 0.35; // ------------- // myFile.js import { pi, exp } from './mathConstants.js'; // Named import -- destructuring-like syntax console.log(pi) // 3.14 console.log(exp) // 2.7 // ------------- // mySecondFile.js import * as constants from './mathConstants.js'; // Inject all exported values into constants variable console.log(constants.pi) // 3.14 console.log(constants.exp) // 2.7 ``` While named imports looks like *destructuring*, they have a different syntax and are not the same. They don't support default values nor *deep* destructuring. Besides, you can do aliases but the syntax is different from the one used in destructuring: ```js import { foo as bar } from 'myFile.js'; // foo is imported and injected into a new bar variable ``` ##### Default import / export Concerning the default export, there is only a single default export per module. A default export can be a function, a class, an object or anything else. This value is considered the "main" exported value since it will be the simplest to import. [Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Description) ```js // coolNumber.js const ultimateNumber = 42; export default ultimateNumber; // ------------ // myFile.js import number from './coolNumber.js'; // Default export, independently from its name, is automatically injected into number variable; console.log(number) // 42 ``` Function exporting: ```js // sum.js export default function sum(x, y) { return x + y; } // ------------- // myFile.js import sum from './sum.js'; const result = sum(1, 2); console.log(result) // 3 ``` #### External resources - [ES6 Modules in bulletpoints](https://ponyfoo.com/articles/es6#modules) - [Export - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) - [Import - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) - [Understanding ES6 Modules](https://www.sitepoint.com/understanding-es6-modules/) - [Destructuring special case - import statements](https://ponyfoo.com/articles/es6-destructuring-in-depth#special-case-import-statements) - [Misunderstanding ES6 Modules - Kent C. Dodds](https://medium.com/@kentcdodds/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution-ad2d5ab93ce0) - [Modules in JavaScript](http://exploringjs.com/es6/ch_modules.html#sec_modules-in-javascript) ### JavaScript *this* *this* operator behaves differently than in other languages and is in most cases determined by how a function is called. ([Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)). This notion is having many subtleties and being quite hard, I highly suggest you to deep dive in the external resources below. Thus, I will provide what I personally have in mind to determine what *this* is equal to. I have learned this tip from [this article written by Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/). ```js function myFunc() { ... } // After each statement, you find the value of *this* in myFunc myFunc.call("myString", "hello") // "myString" -- first .call parameter value is injected into *this* // In non-strict-mode myFunc("hello") // window -- myFunc() is syntax sugar for myFunc.call(window, "hello") // In strict-mode myFunc("hello") // undefined -- myFunc() is syntax sugar for myFunc.call(undefined, "hello") ``` ```js var person = { myFunc: function() { ... } } person.myFunc.call(person, "test") // person Object -- first call parameter is injected into *this* person.myFunc("test") // person Object -- person.myFunc() is syntax sugar for person.myFunc.call(person, "test") var myBoundFunc = person.myFunc.bind("hello") // Creates a new function in which we inject "hello" in *this* value person.myFunc("test") // person Object -- The bind method has no effect on the original method myBoundFunc("test") // "hello" -- myBoundFunc is person.myFunc with "hello" bound to *this* ``` #### External resources - [Understanding JavaScript Function Invocation and "this" - Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/) - [JavaScript this - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) ### Class JavaScript is a [prototype-based](https://en.wikipedia.org/wiki/Prototype-based_programming) language (whereas Java is [class-based](https://en.wikipedia.org/wiki/Class-based_programming) language, for instance). ES6 has introduced JavaScript classes which are meant to be a syntactic sugar for prototype-based inheritance and **not** a new class-based inheritance model ([ref](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)). The word *class* is indeed error prone if you are familiar with classes in other languages. If you do, avoid assuming how JavaScript classes work on this basis and consider it an entirely different notion. Since this document is not an attempt to teach you the language from the ground up, I will believe you know what prototypes are and how they behave. If you do not, see the external resouces listed below the sample code. #### Samples Before ES6, prototype syntax: ```js var Person = function(name, age) { this.name = name; this.age = age; } Person.prototype.stringSentence = function() { return "Hello, my name is " + this.name + " and I'm " + this.age; } ``` With ES6 class syntax: ```js class Person { constructor(name, age) { this.name = name; this.age = age; } stringSentence() { return `Hello, my name is ${this.name} and I am ${this.age}`; } } const myPerson = new Person("Manu", 23); console.log(myPerson.age) // 23 console.log(myPerson.stringSentence()) // "Hello, my name is Manu and I'm 23 ``` #### External resources For prototype understanding: - [Understanding Prototypes in JS - Yehuda Katz](http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/) - [A plain English guide to JS prototypes - Sebastian Porto](http://sporto.github.io/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/) - [Inheritance and the prototype chain - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) For classes understanding: - [ES6 Classes in Depth - Nicolas Bevacqua](https://ponyfoo.com/articles/es6-classes-in-depth) - [ES6 Features - Classes](http://es6-features.org/#ClassDefinition) - [JavaScript Classes - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) ### `Extends` and `super` keywords The `extends` keyword is used in class declarations or class expressions to create a class which is a child of another class ([Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends)). The subclass inherits all the properties of the superclass and additionally can add new properties or modify the inherited ones. The `super` keyword is used to call functions on an object's parent, including its constructor. - `super` keyword must be used before the `this` keyword is used in constructor - Invoking `super()` calls the parent class constructor. If you want to pass some arguments in a class's constructor to its parent's constructor, you call it with `super(arguments)`. - If the parent class have a method (even static) called `X`, you can use `super.X()` to call it in a child class. #### Sample Code ```js class Polygon { constructor(height, width) { this.name = 'Polygon'; this.height = height; this.width = width; } getHelloPhrase() { return `Hi, I am a ${this.name}`; } } class Square extends Polygon { constructor(length) { // Here, it calls the parent class' constructor with lengths // provided for the Polygon's width and height super(length, length); // Note: In derived classes, super() must be called before you // can use 'this'. Leaving this out will cause a reference error. this.name = 'Square'; this.length = length; } getCustomHelloPhrase() { const polygonPhrase = super.getHelloPhrase(); // accessing parent method with super.X() syntax return `${polygonPhrase} with a length of ${this.length}`; } get area() { return this.height * this.width; } } const mySquare = new Square(10); console.log(mySquare.area) // 100 console.log(mySquare.getHelloPhrase()) // 'Hi, I am a Square' -- Square inherits from Polygon and has access to its methods console.log(mySquare.getCustomHelloPhrase()) // 'Hi, I am a Square with a length of 10' ``` **Note :** If we had tried to use `this` before calling `super()` in Square class, a ReferenceError would have been raised: ```js class Square extends Polygon { constructor(length) { this.height; // ReferenceError, super needs to be called first! // Here, it calls the parent class' constructor with lengths // provided for the Polygon's width and height super(length, length); // Note: In derived classes, super() must be called before you // can use 'this'. Leaving this out will cause a reference error. this.name = 'Square'; } } ``` #### External Resources - [Extends - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) - [Super operator - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) - [Inheritance - MDN](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance) ### Async Await In addition to [Promises](#promises), there is a new syntax you might encounter to handle asynchronous code named *async / await*. The purpose of async/await functions is to simplify the behavior of using promises synchronously and to perform some behavior on a group of Promises. Just as Promises are similar to structured callbacks, async/await is similar to combining generators and promises. Async functions *always* return a Promise. ([Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)) > **Note :** You must understand what promises are and how they work before trying to understand async / await since they rely on it. > **Note 2:** [*await* must be used in an *async* function](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9#f3f0), which means that you can't use await in the top level of our code since that is not inside an async function. #### Sample code ```js async function getGithubUser(username) { // async keyword allows usage of await in the function and means function returns a promise const response = await fetch(`https://api.github.com/users/${username}`); // Execution is paused here until the Promise returned by fetch is resolved return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) // logging user response - cannot use await syntax since this code isn't in async function .catch(err => console.log(err)); // if an error is thrown in our async function, we will catch it here ``` #### Explanation with sample code *Async / Await* is built on promises but they allow a more imperative style of code. The *async* operator marks a function as asynchronous and will always return a *Promise*. You can use the *await* operator in an *async* function to pause execution on that line until the returned Promise from the expression either resolves or rejects. ```js async function myFunc() { // we can use await operator because this function is async return "hello world"; } myFunc().then(msg => console.log(msg)) // "hello world" -- myFunc's return value is turned into a promise because of async operator ``` When the *return* statement of an async function is reached, the Promise is fulfilled with the value returned. If an error is thrown inside an async function, the Promise state will turn to *rejected*. If no value is returned from an async function, a Promise is still returned and resolves with no value when execution of the async function is complete. *await* operator is used to wait for a *Promise* to be fulfilled and can only be used inside an *async* function body. When encountered, the code execution is paused until the promise is fulfilled. > **Note :** *fetch* is a function that returns a Promise that allows to do an AJAX request Let's see how we could fetch a github user with promises first: ```js function getGithubUser(username) { return fetch(`https://api.github.com/users/${username}`).then(response => response.json()); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` Here's the *async / await* equivalent: ```js async function getGithubUser(username) { // promise + await keyword usage allowed const response = await fetch(`https://api.github.com/users/${username}`); // Execution stops here until fetch promise is fulfilled return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` *async / await* syntax is particularly convenient when you need to chain promises that are interdependent. For instance, if you need to get a token in order to be able to fetch a blog post on a database and then the author informations: > **Note :** *await* expressions needs to be wrapped in parentheses to call its resolved value's methods and properties on the same line. ```js async function fetchPostById(postId) { const token = (await fetch('token_url')).json().token; const post = (await fetch(`/posts/${postId}?token=${token}`)).json(); const author = (await fetch(`/users/${post.authorId}`)).json(); post.author = author; return post; } fetchPostById('gzIrzeo64') .then(post => console.log(post)) .catch(err => console.log(err)); ``` ##### Error handling Unless we add *try / catch* blocks around *await* expressions, uncaught exceptions – regardless of whether they were thrown in the body of your *async* function or while it’s suspended during *await* – will reject the promise returned by the *async* function. Using the `throw` statement in an async function is the same as returning a Promise that rejects. [(Ref: PonyFoo)](https://ponyfoo.com/articles/understanding-javascript-async-await#error-handling). > **Note :** Promises behave the same! With promises, here is how you would handle the error chain: ```js function getUser() { // This promise will be rejected! return new Promise((res, rej) => rej("User not found !")); } function getAvatarByUsername(userId) { return getUser(userId).then(user => user.avatar); } function getUserAvatar(username) { return getAvatarByUsername(username).then(avatar => ({ username, avatar })); } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "User not found !" ``` The equivalent with *async / await*: ```js async function getUser() { // The returned promise will be rejected! throw "User not found !"; } async function getAvatarByUsername(userId) => { const user = await getUser(userId); return user.avatar; } async function getUserAvatar(username) { var avatar = await getAvatarByUsername(username); return { username, avatar }; } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "User not found !" ``` #### External resources - [Async/Await - JavaScript.Info](https://javascript.info/async-await) - [ES7 Async/Await](http://rossboucher.com/await/#/) - [6 Reasons Why JavaScript’s Async/Await Blows Promises Away](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9) - [JavaScript awaits](https://dev.to/kayis/javascript-awaits) - [Using Async Await in Express with Node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) - [Async Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) - [Await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) - [Using async / await in express with node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) ### Truthy / Falsy In JavaScript, a truthy or falsy value is a value that is being casted into a boolean when evaluated in a boolean context. An example of boolean context would be the evaluation of an ```if``` condition: Every value will be casted to ```true``` unless they are equal to: - ```false``` - ```0``` - ```""``` (empty string) - ```null``` - ```undefined``` - ```NaN``` Here are examples of *boolean context*: - ```if``` condition evaluation ```js if (myVar) {} ``` ```myVar``` can be any [first-class citizen](https://en.wikipedia.org/wiki/First-class_citizen) (variable, function, boolean) but it will be casted into a boolean because it's evaluated in a boolean context. - After logical **NOT** ```!``` operator This operator returns false if its single operand can be converted to true; otherwise, returns true. ```js !0 // true -- 0 is falsy so it returns true !!0 // false -- 0 is falsy so !0 returns true so !(!0) returns false !!"" // false -- empty string is falsy so NOT (NOT false) equals false ``` - With the *Boolean* object constructor ```js new Boolean(0) // false new Boolean(1) // true ``` - In a ternary evaluation ```js myVar ? "truthy" : "falsy" ``` myVar is evaluated in a boolean context. Be careful when comparing 2 values. The object values (that should be cast to true) is **not** being casted to Boolean but it forced to convert into a primitive value one using [ToPrimitives specification](http://javascript.info/object-toprimitive). Internally, when an object is compared to Boolean value like `[] == true`, it does `[].toString() == true` so... ```js let a = [] == true // a is false since [].toString() give "" back. let b = [1] == true // b is true since [1].toString() give "1" back. let c = [2] == true // c is false since [2].toString() give "2" back. ``` #### External resources - [Truthy (MDN)](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) - [Falsy (MDN)](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) - [Truthy and Falsy values in JS - Josh Clanton](http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html) ### Anamorphisms and Catamorphisms #### Anamorphisms Anamorphisms are functions that map from some object to a more complex structure containing the type of the object. It is the process of *unfolding* a simple structure into a more complex one. Consider unfolding an integer to a list of integers. The integer is our initial object and the list of integers is the more complex structure. **Sample code** ```js function downToOne(n) { const list = []; for (let i = n; i > 0; --i) { list.push(i); } return list; } downToOne(5) //=> [ 5, 4, 3, 2, 1 ] ``` #### Catamorphisms Catamorphisms are the opposite of Anamorphisms, in that they take objects of more complex structure and *fold* them into simpler structures. Take the following example `product` which take a list of integers and returns a single integer. **Sample code** ```js function product(list) { let product = 1; for (const n of list) { product = product * n; } return product; } product(downToOne(5)) // 120 ``` #### External resources * [Anamorphisms in JavaScript](http://raganwald.com/2016/11/30/anamorphisms-in-javascript.html) * [Anamorphism](https://en.wikipedia.org/wiki/Anamorphism) * [Catamorphism](https://en.wikipedia.org/wiki/Catamorphism) ### Generators Another way to write the `downToOne` function is to use a Generator. To instantiate a `Generator` object, one must use the `function *` declaration. Generators are functions that can be exited and later re-entered with its context (variable bindings) saved across re-entrances. For example, the `downToOne` function above can be rewritten as: ```js function * downToOne(n) { for (let i = n; i > 0; --i) { yield i; } } [...downToOne(5)] // [ 5, 4, 3, 2, 1 ] ``` Generators return an iterable object. When the iterator's `next()` function is called, it is executed until the first `yield` expression, which specifies the value to be returned from the iterator or with `yield*`, which delegates to another generator function. When a `return` expression is called in the generator, it will mark the generator as done and pass back as the return value. Further calls to `next()` will not return any new values. **Sample code** ```js // Yield Example function * idMaker() { var index = 0; while (index < 2) { yield index; index = index + 1; } } var gen = idMaker(); gen.next().value; // 0 gen.next().value; // 1 gen.next().value; // undefined ``` The `yield*` expression enables a generator to call another generator function during iteration. ```js // Yield * Example function * genB(i) { yield i + 1; yield i + 2; yield i + 3; } function * genA(i) { yield i; yield* genB(i); yield i + 10; } var gen = genA(10); gen.next().value; // 10 gen.next().value; // 11 gen.next().value; // 12 gen.next().value; // 13 gen.next().value; // 20 ``` ```js // Generator Return Example function* yieldAndReturn() { yield "Y"; return "R"; yield "unreachable"; } var gen = yieldAndReturn() gen.next(); // { value: "Y", done: false } gen.next(); // { value: "R", done: true } gen.next(); // { value: undefined, done: true } ``` #### External resources * [Mozilla MDN Web Docs, Iterators and Generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Generators) ### Static Methods #### Short explanation The `static` keyword is used in classes to declare static methods. Static methods are functions in a class that belongs to the class object and are not available to any instance of that class. #### Sample code ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } } // Note that we did not have to create an instance of the Repo class console.log(Repo.getName()) // Repo name is modern-js-cheatsheet let r = new Repo(); console.log(r.getName()) // Uncaught TypeError: r.getName is not a function ``` #### Detailed explanation Static methods can be called within another static method by using the `this` keyword, this doesn't work for non-static methods though. Non-static methods cannot directly access static methods using the `this` keyword. ##### Calling other static methods from a static method. To call a static method from another static method, the `this` keyword can be used like so; ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } static modifyName(){ return this.getName() + '-added-this' } } console.log(Repo.modifyName()) // Repo name is modern-js-cheatsheet-added-this ``` ##### Calling static methods from non-static methods. Non-static methods can call static methods in 2 ways; 1. ###### Using the class name. To get access to a static method from a non-static method we use the class name and call the static method like a property. e.g `ClassName.StaticMethodName` ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ return Repo.getName() + ' and it contains some really important stuff' } } // we need to instantiate the class to use non-static methods let r = new Repo() console.log(r.useName()) // Repo name is modern-js-cheatsheet and it contains some really important stuff ``` 2. ###### Using the constructor Static methods can be called as properties on the constructor object. ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ // Calls the static method as a property of the constructor return this.constructor.getName() + ' and it contains some really important stuff' } } // we need to instantiate the class to use non-static methods let r = new Repo() console.log(r.useName()) // Repo name is modern-js-cheatsheet and it contains some really important stuff ``` #### External resources - [static keyword- MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) - [Static Methods- Javascript.info](https://javascript.info/class#static-methods) - [Static Members in ES6- OdeToCode](http://odetocode.com/blogs/scott/archive/2015/02/02/static-members-in-es6.aspx) ## Glossary ### Scope The context in which values and expressions are "visible," or can be referenced. If a variable or other expression is not "in the current scope," then it is unavailable for use. Source: [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Scope) ### Variable mutation A variable is said to have been mutated when its initial value has changed afterward. ```js var myArray = []; myArray.push("firstEl") // myArray is being mutated ``` A variable is said to be *immutable* if it can't be mutated. [Check MDN Mutable article](https://developer.mozilla.org/en-US/docs/Glossary/Mutable) for more details. ================================================ FILE: JavaScript/_config.yml ================================================ theme: jekyll-theme-cayman title: Modern JS Cheatsheet ================================================ FILE: JavaScript/translations/fr-FR.md ================================================ # Modern JavaScript Cheatsheet ![Modern JavaScript cheatsheet](https://i.imgur.com/aexPxMb.png) Crédits de l’image: [Ahmad Awais ⚡️](https://github.com/ahmadawais) ## Introduction ### Motivation Ce document est un condensé de tout ce que vous devriez savoir sur le JavaScript que vous allez rencontrer dans des projets modernes. Ce guide n’a pas été conçu pour vous apprendre JavaScript à partir de rien, mais pour aider les développeurs ayant des connaissances basiques qui ont des problèmes avec les codebases modernes (ou pour apprendre React, par exemple) à cause des concepts JavaScript utilisés. De plus, je vous donnerai parfois des conseils personnels qui pourraient porter à débat, mais je prendrai le soin de le mentionner lorsque je le ferai. > **Note :** La plupart des concepts introduits ici viennent d’une mise à jour du langage JavaScript (ES2015, souvent appelé ES6. Vous pouvez trouver les nouvelles fonctionnalités. ajoutées par cette mise à jour [ici](http://es6-features.org) (ce site est vraiment bien fait !). ### Ressources complémentaires Lorsque vous avez de la peine à comprendre une notion, je vous suggère de chercher des réponses dans les ressources suivantes : - [MDN (Mozilla Developer Network)](https://developer.mozilla.org/en-US/search?q=) - [You don't know JS (livre)](https://github.com/getify/You-Dont-Know-JS) - [ES6 Features with examples](http://es6-features.org) - [WesBos blog (ES6)](http://wesbos.com/category/es6/) - [Javascript Basics for Beginners](https://www.udacity.com/course/javascript-basics--ud804) - a free Udacity course - [Reddit (JavaScript)](https://www.reddit.com/r/javascript/) - [Google](https://www.google.com/) pour trouver des blogs et des ressources spécifiques - [StackOverflow](https://stackoverflow.com/questions/tagged/javascript) > **Note :** Presque toutes les ressources externes listées dans ce document sont en anglais, à l’exception des liens menant vers le Mozilla Developer Network (MDN) qui lui est traduit en français. ## Table des matières * [Modern JavaScript Cheatsheet](#modern-javascript-cheatsheet) * [Introduction](#introduction) * [Motivation](#motivation) * [Ressources complémentaires](#ressources-complémentaires) * [Table des matières](#table-des-matières) * [Notions](#notions) * [Déclaration des variables : var, const, let](#déclaration-des-variables--var-const-let) * [Explication brève](#explication-brève) * [Code d’exemple](#code-dexemple) * [Explication détaillée](#explication-détaillée) * [var](#var) * [let](#let) * [const](#const) * [Ressources externes](#ressources-externes) * [ Fonction fléchée](#-fonction-fléchée) * [Code d'exemple](#code-dexemple-1) * [Explication détaillée](#explication-détaillée-1) * [Concision](#concision) * [Référence de this](#référence-de-this) * [Ressources utiles](#ressources-utiles) * [Valeur par défaut d'un paramètre dans une fonction](#valeur-par-défaut-dun-paramètre-dans-une-fonction) * [External resource](#external-resource) * [Déstructurer des objets et des tableaux](#déstructurer-des-objets-et-des-tableaux) * [Explication avec du code](#explication-avec-du-code) * [Ressources utiles](#ressources-utiles-1) * [Méthodes de tableau : map / filter / reduce](#méthodes-de-tableau--map--filter--reduce) * [Code d'exemple](#code-dexemple-2) * [Explication](#explication) * [Array.prototype.map()](#arrayprototypemap) * [Array.prototype.filter()](#arrayprototypefilter) * [Array.prototype.reduce()](#arrayprototypereduce) * [À la première étape d'itération](#À-la-première-étape-ditération) * [À la deuxième étape d'itération](#À-la-deuxième-étape-ditération) * [À la troisième étape d'itération](#À-la-troisième-étape-ditération) * [À la quatrième étape d'itération](#À-la-quatrième-étape-ditération) * [[...] À la dernière étape d'itération](#-À-la-dernière-étape-ditération) * [Ressource externe](#ressource-externe) * [Opérateur de décomposition "..."](#opérateur-de-décomposition-) * [Code d'exemple](#code-dexemple-3) * [Explication](#explication-1) * [Dans des tableaux (comme des tableaux)](#dans-des-tableaux-comme-des-tableaux) * [Paramètre de reste d'une fonction](#paramètre-de-reste-dune-fonction) * [Décomposition des propriétés d'un objet](#décomposition-des-propriétés-dun-objet) * [Ressources externes](#ressources-externes-1) * [Raccourci pour les propriétés d'objet](#raccourci-pour-les-propriétés-dobjet) * [Explication](#explication-2) * [Ressources externes](#ressources-externes-2) * [Promesses](#promesses) * [Code d'exemple](#code-dexemple-4) * [Explication](#explication-3) * [Créer la promesse](#créer-la-promesse) * [Utilisation des déclencheurs de promesse](#utilisation-des-déclencheurs-de-promesse) * [Ressources externes](#ressources-externes-3) * [Littéraux de modèle](#littéraux-de-modèle) * [Code d'exemple](#code-dexemple-5) * [Ressources externes](#ressources-externes-4) * [Littéraux de modèle étiquetés](#littéraux-de-modèle-étiquetés) * [Ressources externes](#ressources-externes-5) * [Imports / exports](#imports--exports) * [Explication avec un code d'exemple](#explication-avec-un-code-dexemple) * [Exports nommés](#exports-nommés) * [Import/export par défaut](#importexport-par-défaut) * [Ressources externes](#ressources-externes-6) * [this en JavaScript](#-this-en-javascript) * [Ressources externes](#ressources-externes-7) * [Classe](#classe) * [Exemples](#exemples) * [Ressources externes](#ressources-externes-8) * [Mots clés extends et super](#mots-clés-extends-et-super) * [Code d’exemple](#code-dexemple-6) * [Ressources](#ressources) * [Async Await](#async-await) * [Code d’exemple](#code-dexemple-7) * [Explication avec un code d’exemple](#explication-avec-un-code-dexemple-1) * [Gestion d’erreur](#gestion-derreur) * [Ressources externes](#ressources-externes-9) * [Vérité / fausseté](#vérité--fausseté) * [Ressources externes](#ressources-externes-10) * [Méthodes statiques](#méthodes-statiques) * [Explication courte](#explication-courte) * [Code d’exemple](#code-dexemple-8) * [Explication détaillée](#explication-détaillée-2) * [Appeler d’autres méthodes statiques depuis une méthode statique](#appeler-dautres-méthodes-statiques-depuis-une-méthode-statique) * [Appeler des méthodes statiques depuis des méthodes non statiques](#appeler-des-méthodes-statiques-depuis-des-méthodes-non-statiques) * [En utilisant le nom de la classe](#en-utilisant-le-nom-de-la-classe) * [Avec le constructeur](#avec-le-constructeur) * [Ressources externes](#ressources-externes-11) * [Glossaire](#glossaire) * [Portée (scope)](#-portée-scope) * [Mutation de variable](#-mutation-de-variable) ## Notions ### Déclaration des variables : var, const, let En JavaScript, il y a trois mots-clés disponibles pour déclarer une variable, et chacun a ses différences. Ces mots-clés sont ```var```, ```let``` et ```const```. #### Explication brève Les variables déclarées avec le mot-clé ```const``` ne peuvent pas être réassignées, alors que celles déclarées avec ```let``` et ```var``` le peuvent. Je vous recommande de toujours déclarer vos variables avec ```const``` par défaut, et avec ```let``` si vous avez besoin de la *muter* ou de la réassigner plus tard.
Portée Réassignable Mutable Temporal Dead Zone
const Bloc Non Oui Oui
let Bloc Oui Oui Oui
var Fonction Oui Oui Non
#### Code d’exemple ```javascript const person = "Nick"; person = "John" // Déclenchera une erreur, person ne pouvant pas être réassigné ``` ```javascript let person = "Nick"; person = "John"; console.log(person) // "John", le réassignement est permis avec let ``` #### Explication détaillée La [*portée*](#scope_def) d’une variable définit "où la variable est disponible dans le code". ##### var La portée des variables déclarées avec ```var``` s’étend à la fonction qui la contient, ce qui signifie que lorsqu‘une variable est créée dans une fonction, tout dans cette fonction peut y accéder. De plus, on ne pourra pas accéder à cette variable de l’extérieur de cette fonction. ```javascript function myFunction() { var myVar = "Nick"; console.log(myVar); // "Nick" - myVar est accessible à l'intérieur de la fonction } console.log(myVar); // Émet une ReferenceError, myVar n'est pas accessible en dehors de la fonction ``` Voici un exemple plus subtil, toujours sur la portée des variables : ```javascript function myFunction() { var myVar = "Nick"; if (true) { var myVar = "John"; console.log(myVar); // "John" // La portée de myVar s'étendant à toute la fonction, nous venons d'écraser la valeur précédente de myVar ("Nick"), qui est devenue "John" } console.log(myVar); // "John" - les instructions dans le bloc if ont affecté cette valeur } console.log(myVar); // Produit une ReferenceError, myVar n'étant pas disponible en dehors de la fonction ``` De plus, les variables déclarées avec *var* sont déplacées tout en haut de leur portée à l'exécution. Ce comportement est appelé [var hoisting](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Instructions/var#La_remontée_de_variables_(hoisting)). Ce bout de code : ```js console.log(myVar) // undefined -- aucune erreur produite var myVar = 2; ``` est compris à l'exécution comme : ```js var myVar; console.log(myVar) // undefined -- aucune erreur produite myVar = 2; ``` ##### let ```var``` et ```let ``` sont presque identiques, mais les variables déclarées avec ```let``` - ont leur portée qui est limitée au bloc qui les entoure - ne sont **pas** accessibles avant d'être assignées - ne peuvent pas être redéclarées dans la même portée Observons l'impact de la nouvelle portée dans l'exemple précédent : ```javascript function myFunction() { let myVar = "Nick"; if (true) { let myVar = "John"; console.log(myVar); // "John" // la portée de myVar étant limitée au bloc if, nous venons de crééer une nouvelle variable myVar. // cette variable n'est pas accessible en dehors du bloc if // et est totalement indépendante du premier myVar créé. } console.log(myVar); // "Nick" - les instructions dans le bloc if n'ont PAS affecté cette valeur } console.log(myVar); // Produit une ReferenceError, myVar n'étant pas disponible en dehors de la fonction ``` Maintenant, observons ce que signifie pour les variables créées avec *let* (et *const*) de ne pas être accessibles avant d'avoir été assignées : ```js console.log(myVar) // déclenche une ReferenceError ! let myVar = 2; ``` Contrairement aux variables *var*, si vous essayez de lire ou d'écrire dans une variable *let* ou *const* avant d'être assignées une erreur se produira. Ce phénomène est souvent appelé [*Temporal dead zone*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let) ou *TDZ*. > **Note :** Techniquement, les déclarations de variables *let* and *const*sont aussi affectées par le *var hoisting*, mais pas leur assignation. Vu qu'elles sont faite pour ne pas pouvoir être utilisées avant l'assignation, on a l'impression qu'il n'y a pas de *hoisting*, mais il y en a un. Si vous voulez en savoir plus, vous pouvez lire cette [explication très détaillée](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified). Par ailleurs, vous ne pouvez pas re-déclarer une variable *let* : ```js let myVar = 2; let myVar = 3; // Produit une SyntaxError ``` ##### const Les variables déclarées avec```const``` se comportent comme des variables *let*, mais elles ne peuvent pas être réassignées. Pour résumer, les variables *const* : - ont leur portée qui est limitée au bloc qui les entoure - ne sont pas accessibles avant leur assignation - ne peuvent pas être redéclarées dans la même portée - ne peuvent pas être réassignées ```js const myVar = "Nick"; myVar = "John" // cause une erreur, le réassignement n'est pas permis ``` ```js const myVar = "Nick"; const myVar = "John" // cause une erreur, la redéclaration n'est pas permise ``` Mais il y a une subtilité : les variables ```const``` ne sont pas [**immutables**](#mutation_def) ! Concrètement, cela signifie que les *objets* et *tableaux* ```const``` **peuvent** être mutées. Pour les objets : ```js const person = { name: 'Nick' }; person.name = 'John' // ceci fonctionnera ! la variable person n'est pas complètement réassignée, mais mutée console.log(person.name) // "John" person = "Sandra" // cause une erreur, car le réassignement n'est pas autorisé avec les variables déclarées avec const ``` Pour les tableaux : ```js const person = []; person.push('John'); // ceci fonctionnera ! la variable person n'est pas complètement réassignée, mais mutée console.log(person[0]) // "John" person = ["Nick"] // cause une erreur, car le réassignement n'est pas autorisé avec les variables déclarées avec const ``` #### Ressources externes - [How let and const are scoped in JavaScript - WesBos](http://wesbos.com/javascript-scoping/) - [Temporal Dead Zone (TDZ) Demystified](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) ### Fonction fléchée Avec la mise à jour ES6 de JavaScript, nous pouvons utiliser des *fonctions fléchées*, qui sont un autre moyen de déclarer et d'utiliser des fonctions. Voici les bénéfices qu'elles apportent : - Plus concis - *this* se réfère à l'extérieur de la fonction fléchée - ```return``` implicite #### Code d'exemple - Concision et retour implicite ```js function double(x) { return x * 2; } // Manière traditionnelle console.log(double(2)) // 4 ``` ```js const double = x => x * 2; // Même fonction écrite sous forme de fonction fléchée avec un retour implicite console.log(double(2)) // 4 ``` - Référence de *this* Dans une fonction fléchée, *this* est égal à la valeur de *this* dans le contexte d'exécution alentour. Basiquement, avec les fonctions fléchées, vous n'êtes plus obligé d'utiliser l'astuce "that = this" avant d'appeler une fonction à l'intérieur d'une fonction. ```js function myFunc() { this.myVar = 0; setTimeout(() => { this.myVar++; console.log(this.myVar) // 1 }, 0); } ``` #### Explication détaillée ##### Concision Les fonctions fléchées sont plus concises que les fonctions traditionnelles par plusieurs aspects. Voyons tous les cas possibles : - Retour implicite VS explicite Un **retour explicite** est une fonction où le mot-clé ```return``` est utilisé dans son corps. ```js function double(x) { return x * 2; // cette fonction retourne explicitement x * 2, le mot-clé return est utilisé } ``` Dans l'écriture de foncitons traditionnelle, le retour était toujours explicite. Mais avec les fonctions fléchées, vous pouvez faire un *retour implicite* ce qui signifie que vous n'êtes pas obligés d'utiliser le mot-clé *return* pour retourner une valeur. Pour faire un retour implicite, le code doit être écrit en une ligne. ```js const double = (x) => { return x * 2; // Ce retour est explicite } ``` Comme il n'y a qu'un retour de valeur ici, nous pouvons utiliser un retour implicite. ```js const double = (x) => x * 2; ``` Pour ce faire, il nous suffit de **supprimer les accolades** et le mot-clé **return**. C'est pour cette raison qu'on qualifie ce retour d'*implicite* : le mot-clé *return* n'est pas là. mais la fonction va bien retourner ```x * 2```. > **Note :** Si votre fonction ne retourne aucune valeur (avec des *effets secondaires*), elle ne fait ni retour implicite ni explicite. De plus, si vous voulez retourner un *objet* vous **devez mettre des parenthèses autour** pour éviter un conflit avec les accolades de bloc : ```js const getPerson = () => ({ name: "Nick", age: 24 }) console.log(getPerson()) // { name: "Nick", age: 24 } -- l'objet est implicitement retourné par la fonction fléchée ``` - Uniquement un argument Si votre fonction ne prend qu'un paramètre, vous pouvez omettre les parenthèses autour. En reprenant un exemple au dessus : ```js const double = (x) => x * 2; // cette fonction fléchée ne prend qu'un paramètre ``` Les parenthèses autour du paramètre peuvent être évitées : ```js const double = x => x * 2; // cette fonction fléchée ne prend qu'un paramètre ``` - Pas de paramètres Lorsqu'une fonction fléchée ne prend aucun paramètre, vous devez obligatoirement mettre des parenthèses pour que la syntaxe soit valide : ```js () => { // avec des parenthèses, tout fonctionne const x = 2; return x; } ``` ```js => { // pas de parenthèses, ceci ne fonctionnera pas ! const x = 2; return x; } ``` ##### Référence de *this* Pour comprendre cette subtilité des fonctions fléchées, vous devez savoir comment [this](#this_def) fonctionne en JavaScript. Dans une fonction fléchée, *this* est égal à la valeur de *this* dans le contexte d'exécution alentour. Cela signifie qu'une fonction fléchée ne créée pas de nouveau *this*, mais le prend autour à la place. Sans une fonction fléchée, pour accéder à une variable présente dans *this* dans une fonction à l'intérieur d'une fonction, vous deviez utiliser l'astuce de *that = this* ou *self = this*. Par exemple, voici comment utiliser setTimeout à l'intérieur de myFunc : ```js function myFunc() { this.myVar = 0; var that = this; // astuce that = this setTimeout( function() { // Un nouveau *this* est créé dans la portée de cette fonction that.myVar++; console.log(that.myVar) // 1 console.log(this.myVar) // undefined -- voir la déclaration de fonction au-dessus }, 0 ); } ``` Mais avec une fonction fléchée, *this* est pris de l'extérieur : ```js function myFunc() { this.myVar = 0; setTimeout( () => { // this pris de l'extérieur, signifiant myFunc ici this.myVar++; console.log(this.myVar) // 1 }, 0 ); } ``` #### Ressources utiles - [Arrow functions introduction - WesBos](http://wesbos.com/arrow-functions/) - [Fonction fléchées - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Fonctions/Fonctions_fl%C3%A9ch%C3%A9es) - [Arrow function and lexical *this*](https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4) ### Valeur par défaut d'un paramètre dans une fonction À partir de la mise à jour de JavaScript ES2015, vous pouvez assigner une valeur par défaut à un paramètre de fonction en utilisant la syntaxe suivante ```js function myFunc(x = 10) { return x; } console.log(myFunc()) // 10 -- aucune valeur n'étant donnée, la valeur par défaut est utilisée console.log(myFunc(5)) // 5 -- une valeur est donnée donc x est égal à 5 dans myFunc console.log(myFunc(undefined)) // 10 -- la valeur undefined est donnée, donc x est assigné à la valeur par défaut console.log(myFunc(null)) // null -- une valeur (null) étant donnée, voir plus bas pour plus de détails ``` Le paramètre par défaut est utilisé dans deux et uniquement deux situations : - Aucun paramètre n'est fourni - Le paramèter *undefined* est fourni Autrement dit, si vous passez *null* le paramètre par défaut **ne sera pas appliqué**. > **Note :** Un assignement de valeur par défaut peut être utilisé avec des paramètres déstructurés également (voyez la notion suivante pour avoir un exemple). #### External resource - [Default parameter value - ES6 Features](http://es6-features.org/#DefaultParameterValues) - [Valeurs par défaut des arguments - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Fonctions/Valeurs_par_d%C3%A9faut_des_arguments) ### Déstructurer des objets et des tableaux La *déstructuration* un moyen pratique de créer de nouvelles variables en extrayant des valeurs des données enregistrées dans des objets ou des tableaux. Pour nommer quelque cas d'utilisation, la *déstructuration* peut être utilisée pour déstructurer des paramètres de fonction ou *this.props* dans des projets React par exemple. #### Explication avec du code - Objet Prenons l'objet suivant pour tous les exemples ```js const person = { firstName: "Nick", lastName: "Anderson", age: 35, sex: "M" } ``` Sans déstructuration : ```js const first = person.firstName; const age = person.age; const city = person.city || "Paris"; ``` Avec la déstructuration, tout en une ligne : ```js const { firstName: first, age, city = "Paris" } = person; // Et voilà ! console.log(age) // 35 -- Une nouvelle variable age est créée et est égale à person.age console.log(first) // "Nick" -- Une nouvelle variable first est créée et est égale à person.firstName console.log(firstName) // ReferenceError -- person.firstName existe MAIS la nouvelle variable créée est nommée first console.log(city) // "Paris" -- Une nouvelle variable city est créée et comme person.city n'est pas défini, city est égal à la valeur par défaut donnée, à savoir "Paris" ``` **Note :** Dans ```const { age } = person;```, les accolades après le mot-clé *const* ne sont pas utilisées pour déclarer un objet ou un bloc, mais font partie de la syntaxe de *déstructuration*. - Paramètres de fonction La *destructuring* est souvent utilisée pour déstructurer les paramètres de fonction sous la forme d'objets. Sans déstructuration : ```js function joinFirstLastName(person) { const firstName = person.firstName; const lastName = person.lastName; return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` En déstructurant le paramètre objet *person*, nous obtenons une fonction plus concise : ```js function joinFirstLastName({ firstName, lastName }) { // nous crééons les variables firstName et lastName en déstructurant le paramètre person return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` La déstructuration est encore plus agréable à utiliser avec les [fonctions fléchées](#arrow_func_concept) : ```js const joinFirstLastName = ({ firstName, lastName }) => firstName + '-' + lastName; joinFirstLastName(person); // "Nick-Anderson" ``` - Tableau Utilisons le tableau suivant : ```js const myArray = ["a", "b", "c"]; ``` Sans la destructuration : ```js const x = myArray[0]; const y = myArray[1]; ``` Avec : ```js const [x, y] = myArray; // Et voilà ! console.log(x) // "a" console.log(y) // "b" ``` #### Ressources utiles - [ES6 Features - Destructuring Assignment](http://es6-features.org/#ArrayMatching) - [Destructuring Objects - WesBos](http://wesbos.com/destructuring-objects/) - [ExploringJS - Destructuring](http://exploringjs.com/es6/ch_destructuring.html) ### Méthodes de tableau : map / filter / reduce *Map*, *filter* et *reduce* sont des méthodes de tableau qui viennent avec un paradigme de programmation appelé la [*programmation fonctionnelle*](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0). Pour résumer : - **Array.prototype.map()** prend un tableau, fait quelque chose sur ses éléments et retourne un tableau contenant les éléments transformés. - **Array.prototype.filter()** prend un tableau, décide élément par élément s'il faut le garder ou non et retourne un tableau contenant uniquement les éléments conservés. - **Array.prototype.reduce()** prend un tableau et agrège ses éléments en une seule valeur (qui est retournée). Je recommande de les utiliser autant que possibles pour suivre les principes de la programmation fonctionelle car ils sont composables, concis et élégants. Avec toutes ces méthodes, vous pouvez éviter l'utilisation des boucles *for* et *forEach* dans la plupart des situations. Vous pouvez avoir de la peine au début à les utiliser car ils vous obligent à apprendre une nouvelle façon de penser, mais une fois que vous avez compris comment cela fonctionne tout devient plus facile. #### Code d'exemple ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; const doubledNumbers = numbers.map(n => n * 2); // [0, 2, 4, 6, 8, 10, 12] const evenNumbers = numbers.filter(n => n % 2 === 0); // [0, 2, 4, 6] const sum = numbers.reduce((prev, next) => prev + next, 0); // 21 ``` Calculer la somme des notes (```grades```) des étudiants ayant eu plus que 10 en utilisant map, filter et reduce : ```js const students = [ { name: "Nick", grade: 10 }, { name: "John", grade: 15 }, { name: "Julia", grade: 19 }, { name: "Nathalie", grade: 9 }, ]; const aboveTenSum = students .map(student => student.grade) // nous transformons le tableau students en un tableau contenant leurs notes .filter(grade => grade >= 10) // nous filtrons le tableau des notes pour ne conserver que celles supérieures ou égales à 10 .reduce((prev, next) => prev + next, 0); // nous additionnons toutes les notes au dessus de 10 une par une console.log(aboveTenSum) // 44 -- 10 (Nick) + 15 (John) + 19 (Julia), Nathalie étant ignorée car sa note est inférieure à 10 ``` #### Explication Prenons le tableau de nombres pour nos exemples : ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; ``` ##### Array.prototype.map() ```js const doubledNumbers = numbers.map(function(n) { return n * 2; }); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` Que se passe-t-il ici ? Nous utilisons .map sur le tableau *numbers*, le map itère sur chaque élément du tableau et le passe à notre fonction. Le but de la fonction est de produire et de retourner une nouvelle valeur pour chaque valeur donnée pour que le map puisse la remplacer. Extrayons cette fonction pour la rendre plus claire, juste pour cette fois-ci : ```js const doubleN = function(n) { return n * 2; }; const doubledNumbers = numbers.map(doubleN); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` ```numbers.map(doubleN)``` produit ```[doubleN(0), doubleN(1), doubleN(2), doubleN(3), doubleN(4), doubleN(5), doubleN(6)]``` ce qui est égal à ```[0, 2, 4, 6, 8, 10, 12]```. > **Note :** Si vous n'avez pas besoin d'un nouveau tableau et que vous voulant juste avoir une boucle ayant des effets secondaires, vous pourriez juste avoir besoin d'une boucle for / forEach à la place d'un map. ##### Array.prototype.filter() ```js const evenNumbers = numbers.filter(function(n) { return n % 2 === 0; // true si "n" est pair, false si "n" est impair }); console.log(evenNumbers); // [0, 2, 4, 6] ``` Nous utilisons .filter sur le tableau *numbers* : filter itère sur chaque élément du tableau et le passe à notre fonction. Le but de la fonction est de retourner un booléen qui déterminera si la valeur actuelle sera conservée. Filter retourne ensuite le tableau avec uniquement les valeurs conservées. ##### Array.prototype.reduce() Le but de la méthode reduce est de réduire tous les éléments du tableau sur lequel elle itère à une seule valeur. Vous décidez de la manière dont les éléments sont agrégés. ```js const sum = numbers.reduce( function(acc, n) { return acc + n; }, 0 // valeur de l'accumulateur à la première itération ); console.log(sum) //21 ``` Tout comme pour les méthodes .map et .filter, .reduce est appliqué sur un tableau et prend une fonction en premier paramètre. Cette fois cependant, il y a des changements : - .reduce prend deux paramètres Le premier paramètre est une fonction qui sera appelée à chaque étape d'itéraiton. Le second paramètre est la valeur de la variable d'accumulation (*acc* ici) à la première étape d'itération (lisez le point suivant pour comprendre). - Paramèters de fonction La fonction que vous passez comme premier paramètre de .reduce prend deux paramètres. Le premier (*acc* ici) est la variable d'accumulateur, tandis que le second paramètre (*n*) est l'élément actuel. La variable d'accumulateur est égale à la valeur retournée par votre fonction à l'étape d'itération **précédente**. À la première étape de l'itération, *acc* est égale à la valeur que vous avez passé au second paramètre de .reduce. ###### À la première étape d'itération ```acc = 0``` car nous avons passé 0 comme second paramètre à reduce. ```n = 0``` premier élément du tableau *number* La fonction retourne *acc* + *n* --> 0 + 0 --> 0 ###### À la deuxième étape d'itération ```acc = 0``` car c'est la valeur retournée par la fonction à l'étape d'itération précédente ```n = 1``` deuxième élément du tableau *number* La fonction retourne *acc* + *n* --> 0 + 1 --> 1 ###### À la troisième étape d'itération ```acc = 1``` car c'est la valeur retournée par la fonction à l'étape d'itération précédente ```n = 2``` troisième élément du tableau *number* La fonction retourne *acc* + *n* --> 1 + 2 --> 3 ###### À la quatrième étape d'itération ```acc = 3``` car c'est la valeur retournée par la fonction à l'étape d'itération précédente ```n = 3``` quatrième élément du tableau *number* La fonction retourne *acc* + *n* --> 3 + 3 --> 6 ###### [...] À la dernière étape d'itération ```acc = 15``` car c'est la valeur retournée par la fonction à l'étape d'itération précédente ```n = 6``` dernier élément du tableau *number* La fonction retourne *acc* + *n* --> 15 + 6 --> 21 Comme c'est la dernière étape d'itération, **.reduce** retourne 21. #### Ressource externe - [Understanding map / filter / reduce in JS](https://hackernoon.com/understanding-map-filter-and-reduce-in-javascript-5df1c7eee464) ### Opérateur de décomposition "..." L'opérateur de décomposition ```...``` existe depuis ES2015 et est utilisé pour décomposer les éléments d'un itérable (comme un tableau) dans des emplacements qui peuvent contenir plusieurs éléments. #### Code d'exemple ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ```js function myFunc(x, y, ...params) { console.log(x); console.log(y); console.log(params) } myFunc("a", "b", "c", "d", "e", "f") // "a" // "b" // ["c", "d", "e", "f"] ``` ```js const { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } ``` #### Explication ##### Dans des tableaux (comme des tableaux) Si nous avons les deux tableaux suivants : ```js const arr1 = ["a", "b", "c"]; const arr2 = [arr1, "d", "e", "f"]; // [["a", "b", "c"], "d", "e", "f"] ``` Le premier élément d'*arr2* est un tableau, car *arr1* est injecté tel quel dans *arr2*. Cependant, nous voulons que *arr2* soit un tableau de lettres. Pour ce faire, nous pouvons *décomposer* les éléments d'*arr1* dans *arr2*. Avec l'opérateur de décomposition : ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ##### Paramètre de reste d'une fonction Dans les paramètres d'une fonction, nous pouvons utiliser l'opérateur de reste pour injecter les paramètres dans un tableau dans lequel nous pouvons faire une bocle. Il existe déjà un objet **arguments** lié à chaque fonction, qui est un tableau contenant tous les paramètres passés à la fonction. ```js function myFunc() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } myFunc("Nick", "Anderson", 10, 12, 6); // "Nick" // "Anderson" // 10 // 12 // 6 ``` Mais imaginons que nous voulons que cette fonction créée un nouvel édudiant avec ses notes et sa note moyenne. Ne serait-il pas plus pratique d'extraire les deux premiers paramètres dans deux variables séparées, et d'avoir les notes dans un tableau sur lequel nous pourrions effectuer une boucle ? C'est exactement ce que l'opérateur de reste nous permet de faire ! ```js function createStudent(firstName, lastName, ...grades) { // firstName = "Nick" // lastName = "Anderson" // [10, 12, 6] -- "..." prend tous les autres paramètres passés, créée une variable grades qui contient un tableau contenant les paramètres const avgGrade = grades.reduce((acc, curr) => acc + curr, 0) / grades.length; // calculer la note moyenne à partir des notes return { firstName: firstName, lastName: lastName, grades: grades, avgGrade: avgGrade } } const student = createStudent("Nick", "Anderson", 10, 12, 6); console.log(student); // { // firstName: "Nick", // lastName: "Anderson", // grades: [10, 12, 6], // avgGrade: 9,33 // } ``` > **Note :** la fonction createStudent est mauvaise car nous ne vérifions pas si grades.length existe ou est différent de 0. Cependant, je n'ai pas prévu ce cas pour rendre l'exemple plus facile à lire. ##### Décomposition des propriétés d'un objet Pour celui-ci, je vous recommande de lire les explications précédentes concernant l'opérateur de reste sur les itérables et les paramètres de fonction auparavant. ```js const myObj = { x: 1, y: 2, a: 3, b: 4 }; const { x, y, ...z } = myObj; // l'objet est déstructuré ici console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } // z est le reste de l'objet déstructuré : c'est myObj sans les propriétés x et y qui ont été déstructurées const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } // Ici, les propriétés de l'objet z sont étendues dans n ``` #### Ressources externes - [TC39 - Object rest/spread](https://github.com/tc39/proposal-object-rest-spread) - [Spread operator introduction - WesBos](https://github.com/wesbos/es6-articles/blob/master/28%20-%20Spread%20Operator%20Introduction.md) - [JavaScript & the spread operator](https://codeburst.io/javascript-the-spread-operator-a867a71668ca) - [6 Great uses of the spread operator](https://davidwalsh.name/spread-operator) ### Raccourci pour les propriétés d'objet Lorsque l'on assigne une variable à la propriété d'un objet, si le nom de la variable est le même que le nom de la propriété, vous pouvez faire la chose suivante : ```js const x = 10; const myObj = { x }; console.log(myObj.x) // 10 ``` #### Explication D'habitude (avant ES2015), lorsque l'on déclare un *litéral d'objet* et que l'on veut utiliser des variables comme propriétés de l'objet, on écrit ce genre de code : ```js const x = 10; const y = 20; const myObj = { x: x, // on assigne le contenu de la variable x à myObj.x y: y // on assigne le contenu de la variable y à myObj.y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` Comme vous pouvez le voir, c'est assez répétitif car les noms des propriétés de myObj sont identiques aux noms des variables que vous voulez assigner à ces propriétés. Avec ES2015, quand le nom de la variable est identique au nom de la propriété, vous pouvez utiliser ce raccourci : ```js const x = 10; const y = 20; const myObj = { x, y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` #### Ressources externes - [Property shorthand - ES6 Features](http://es6-features.org/#PropertyShorthand) ### Promesses Une promesse est un objet qui peut être retourné de manière synchrone depuis une fonction asynchrone ([ref](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#3cd0)). Les promesses peuvent être utilisées pour éviter un [enfer de callbacks](http://callbackhell.com/), et elles sont rencontrées de plus en plus fréquemment dans les projets JavaScript modernes. #### Code d'exemple ```js const fetchingPosts = new Promise((res, rej) => { $.get("/posts") .done(posts => res(posts)) .fail(err => rej(err)); }); fetchingPosts .then(posts => console.log(posts)) .catch(err => console.log(err)); ``` #### Explication Quand vous faites une *requête AJAX*, la réponse n'est pas synchrone car vous voulez une ressource qui prend du temps à venir. Elle ne pourriat même jamais arriver si la ressource que vous avez demandée est indisponible pour une raison quelconque (404). Pour gérer ce type de situations, ES2015 nous a offert les *promesses*. Les promesses peuvent avoir trois états différents : - En attente - Complété - Rejeté Imagions que nous voulions utiliser les promesses pour gérer une requête AJAX pour récupérer la ressource *X*. ##### Créer la promesse Nous allons commencer par crééer une promesse. Nous allons utiliser la méthode ```$.get()``` de jQuery pour faire notre requête AJAX vers *X*. ```js const xFetcherPromise = new Promise( // Créer une promesse avec le mot-clé new et la stocker dans une variable function(resolve, reject) { // Le constructeur de Promise prend une fonction comme paramètre qui a elle-même deux paramètres, resolve et reject $.get("X") // Démarrer la requête AJAX .done(function(X) { // Quand la requête est terminée... resolve(X); // ...résoudre la promesse avec la valeur X comme paramètre }) .fail(function(error) { // Si la requête a échoué... reject(error); // ...rejeter la promesse avec l'erreur comme paramètre }); } ) ``` Comme vu dans l'exemple ci-dessus, l'objet Promise prend une fonction *exécuteur* qui prend les deux paramètres **resolve** et **reject**. Ces paramètres sont des fonctions qui lorsqu'elles sont appelées, vont modifier l'état de la promesse d'*en attente* à respectivement l'état *complété* et *résolu*. La promesse est dans l'état *en attente* à sa création et sa fonction *éxécuteur* est appelée immédiatement. Quand une des deux fonctions *resolve* ou *reject* est appelée depuis la fonction *éxécuteur*, la promesse appelera les déclencheurs associés. ##### Utilisation des déclencheurs de promesse Pour obtenir le résultat (ou l'erreur) de la promesse, nous devons y attacher des déclencheurs en faisant la chose suivante : ```js xFetcherPromise .then(function(X) { console.log(X); }) .catch(function(err) { console.log(err) }) ``` Si la promesse réussit, ```resolve()``` sera exécuté et la fonction passée à ```.then``` est appelée. Si elle échoue, ```reject()``` sera exécuté et la fonction passée à ```.catch``` est appelée. > **Note : ** Si la promesse a déjà été accomplie ou rejetée lorsqu'un déclencheur y est attaché, le déclencheur sera appelé, afin de ne pas avoir une course entre une opération asynchrone se complétant et ses déclencheurs s'y faisant attacher [(référence: MDN)](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Promise#Description). #### Ressources externes - [JavaScript Promises for dummies - Jecelyn Yeen](https://scotch.io/tutorials/javascript-promises-for-dummies) - [JavaScript Promise API - David Walsh](https://davidwalsh.name/promises) - [Utiliser les promesses - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Utiliser_les_promesses) - [What is a promise - Eric Elliott](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261) - [JavaScript Promises: an Introduction - Jake Archibald](https://developers.google.com/web/fundamentals/getting-started/primers/promises) - [Documentation sur l'objet Promise - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Promise) ### Littéraux de modèle Les littéraux de modèle (*template literals*) sont une [*interpolation d'expression*](https://en.wikipedia.org/wiki/String_interpolation) pour les chaînes de caractère d'une ligne ou multilignes. Autrement dit, c'est une nouvelle syntaxe de chaîne de caractère qui est particulièrement pratique pour y utiliser des expressions JavaScript (des variables, par exemple). #### Code d'exemple ```js const name = "Nick"; `Bonjour ${name}, l'expression suivante vaut 4 : ${2+2}`; // Bonjour Nick, l'expression suivante vaut 4 : 4 ``` #### Ressources externes - [String interpolation - ES6 Features](http://es6-features.org/#StringInterpolation) - [ES6 Template Strings - Addy Osmani](https://developers.google.com/web/updates/2015/01/ES6-Template-Strings) ### Littéraux de modèle étiquetés Les étiquettes de modèle sont des *fonctions qui peuvent être préfixées à un [littéral de modèle](#litteraux-de-modele)*. Quand une fonction est appelée ainsi, le premier paramètre est un tableau des *chaînes de caractère* qui apparaissent entre les variables interpolées du modèle, et les paramètres suivants sont les valeurs interpolées. Vous pouuvez utiliser l'opérateur de décomposition `...` pour les récupérer. [(Références: MDN)](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Litt%C3%A9raux_gabarits#Les_littéraux_de_modèle_étiquetés). > **Note :** Certaines librairies, comme [styled-components](https://www.styled-components.com/), se basent entièrement sur cette fonctionnalité. Voici un petit exemple de leur fonctionnement : ```js function highlight(strings, ...values) { const interpolation = strings.reduce((prev, current) => { return prev + current + (values.length ? "" + values.shift() + "" : ""); }, ""); return interpolation; } const condiment = "confiture"; const meal = "toast"; highlight`J'aime mettre de la ${condiment} sur mon ${meal}.`; // "J'aime mettre de la confiture sur mon toast." ``` Un autre exemple plus intéressant : ```js function comma(strings, ...values) { return strings.reduce((prev, next) => { let value = values.shift() || []; value = value.join(", "); return prev + next + value; }, ""); } const snacks = ['pommes', 'bananes', 'cerises']; comma`J'aime grignoter des ${snacks}.`; // "J'aime grignoter des pommes, bananes, cerises." ``` #### Ressources externes - [Wes Bos on Tagged Template Literals](http://wesbos.com/tagged-template-literals/) - [Library of common template tags](https://github.com/declandewet/common-tags) ### Imports / exports Les modules ES6 sont utilisés pour accéder à des variables et à des fonctions explicitement exportées depuis les modules importés. Je vous recommande de regardes la documentation sur MDN concernant import/export (voir les ressources externes plus bas), elles sont à la fois simples et complètes. #### Explication avec un code d'exemple ##### Exports nommés Les exports nommés sont utilisés pour exporter plusieurs valeurs d'un module. > **Note :** Vous ne pouvez exporter avec un nom que des [objets de première classe](https://fr.wikipedia.org/wiki/Objet_de_premi%C3%A8re_classe) qui ont un nom. ```js // mathConstants.js export const pi = 3.14; export const exp = 2.7; export const alpha = 0.35; // ------------- // myFile.js import { pi, exp } from './mathConstants.js'; // Import nommé -- syntaxe ressemblant à la destructuration console.log(pi) // 3.14 console.log(exp) // 2.7 // ------------- // mySecondFile.js import * as constants from './mathConstants.js'; // Injecter toutes les valeurs exportées dans la variable constants console.log(constants.pi) // 3.14 console.log(constants.exp) // 2.7 ``` Bien que les imports nommés ressemblent à une *destructuration*, ils ont une syntaxe différente et ne sont pas identiques. Ils ne supportent ni les valeurs par défaut ni la destructuration *profonde*. De plus, vous pouvez créer des alias mais la syntaxe est différente de celle utilisée avec la destructuration : ```js import { foo as bar } from 'myFile.js'; // foo est importé et injecté dans une nouvelle variable bar ``` ##### Import/export par défaut Concernant l'export par défaut, il ne peut y en avoir qu'un seul par module. Un export par défaut peut être une fonction, une classe, un objet, ou quoi que ce soit d'autre. Cette valeur est considérée comme étant la valeur exportée "principale" car elle sera la plus simple à importer. Concerning the default export, there is only a single default export per module. A default export can be a function, a class, an object or anything else. This value is considered the "main" exported value since it will be the simplest to import. [Référence: MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Instructions/export#Description) ```js // coolNumber.js const ultimateNumber = 42; export default ultimateNumber; // ------------ // myFile.js import number from './coolNumber.js'; // L'export par défaut, peu importe son nom, est automatiquement injecté dans la variable number console.log(number) // 42 ``` Exporter une fonction : ```js // sum.js export default function sum(x, y) { return x + y; } // ------------- // myFile.js import sum from './sum.js'; const result = sum(1, 2); console.log(result) // 3 ``` #### Ressources externes - [ES6 Modules in bulletpoints](https://ponyfoo.com/articles/es6#modules) - [Export - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) - [Import - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) - [Understanding ES6 Modules](https://www.sitepoint.com/understanding-es6-modules/) - [Destructuring special case - import statements](https://ponyfoo.com/articles/es6-destructuring-in-depth#special-case-import-statements) - [Misunderstanding ES6 Modules - Kent C. Dodds](https://medium.com/@kentcdodds/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution-ad2d5ab93ce0) - [Modules in JavaScript](http://exploringjs.com/es6/ch_modules.html#sec_modules-in-javascript) ### *this* en JavaScript L'opérateur *this* se comporte différemment que dans d'autres langages et est dans la plupart des cas déterminé par la manière dont une fonction est appelée. ([Ref: MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Op%C3%A9rateurs/L_op%C3%A9rateur_this)). Cette notion a beaucoup de subtilités et comme elle est assez complexe, je vous recommande donc fortement de lire avec attention les ressources externes ci-dessous. Par conséquent, je vais utiliser l’idée personnelle que j’ai en tête pour déterminer ce qu’est *this*. J’ai appris cette astuce de [cet article écrit par Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/). ```js function myFunc() { ... } // Après chaque ligne, vous trouverez la valeur de *this* dans myFunc myFunc.call("myString", "hello") // "myString" -- la valeur du premier paramètre de .call est injectée dans *this* // En mode non-strict myFunc("hello") // window -- myFunc() est un sucre syntaxique pour myFunc.call(window, "hello") // En mode strict myFunc("hello") // undefined -- myFunc() est un sucre syntaxique pour myFunc.call(undefined, "hello") ``` ```js var person = { myFunc: function() { ... } } person.myFunc.call(person, "test") // objet person -- le premier paramètre de call est injecté dans *this* person.myFunc("test") // objet person -- person.myFunc() est un sucre syntaxique pour person.myFunc.call(person, "test") var myBoundFunc = person.myFunc.bind("hello") // Créée une nouvelle fonction dans laquelle nous injectons “hello” comme valeur de *this* person.myFunc("test") // objet Person -- La méthode bind n’a aucun effet sur la méthode originale myBoundFunc("test") // "hello" -- myBoundFunc est person.myFunc avec “hello” comme valeur de *this* ``` #### Ressources externes - [Understanding JavaScript Function Invocation and "this" - Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/) - [L’opérateur this - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Opérateurs/L_opérateur_this) ### Classe JavaScript est un language [basé sur les prototypes](https://fr.wikipedia.org/wiki/Programmation_orientée_prototype) (alors que Java, par exemple, est [basé sur les classes]((https://en.wikipedia.org/wiki/Prototype-based_programming))). ES6 a introduit les classes JavaScript qui sont un sucre syntaxique pour de l’héritage et **non** un nouveau modèle d’héritage basé sur des classes JavaScript is a [prototype-based](https://en.wikipedia.org/wiki/Prototype-based_programming) language (whereas Java is [class-based](https://en.wikipedia.org/wiki/Class-based_programming) language, for instance). ES6 has introduced JavaScript classes which are meant to be a syntactic sugar for prototype-based inheritance and **not** a new class-based inheritance model ([référence : MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Classes)). Le mot *classe* est évidemment source de confusion si vous êtes habitué aux classes dans d’autres langages. Dans ce cas, évitez de penser que les classes JavaScript fonctionnent de la même manière et considérez-les comme une notion totalement différente. Comme ce document n’est pas fait pour vous apprendre le langage à partir de zéro, je vais partir du fait que vous savez déjà ce que sont les prototypes et comment ils se comportement. Dans le cas contraire, voyez les ressources externes listées en dessous des exemples. #### Exemples Avant ES6, la syntaxe de prototype : ```js var Person = function(name, age) { this.name = name; this.age = age; } Person.prototype.stringSentence = function() { return "Hello, my name is " + this.name + " and I'm " + this.age; } ``` Avec la syntaxe ES6 de classe : ```js class Person { constructor(name, age) { this.name = name; this.age = age; } stringSentence() { return "Hello, my name is " + this.name + " and I'm " + this.age; } } const myPerson = new Person("Manu", 23); console.log(myPerson.age) // 23 console.log(myPerson.stringSentence()) // "Hello, my name is Manu and I'm 23 ``` #### Ressources externes Pour comprendre les prototypes : - [Understanding Prototypes in JS - Yehuda Katz](http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/) - [A plain English guide to JS prototypes - Sebastian Porto](http://sporto.github.io/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/) - [Héritage et chaîne de prototypes - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Héritage_et_chaîne_de_prototypes) Pour comprendre les classes - [ES6 Classes in Depth - Nicolas Bevacqua](https://ponyfoo.com/articles/es6-classes-in-depth) - [ES6 Features - Classes](http://es6-features.org/#ClassDefinition) - [Classes - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Classes) ### Mots clés `extends` et `super` Le mot-clé `extends` est utilisé dans les déclarations de classe ou les expressions de classe pour créer une classe qui est une fille d’une autre classe ([référence: MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Classes/extends)). La sous-classe hérite de toutes les propriétés de la classe supérieure et peut aussi ajouter de nouvelles propriétés ou modifier celles héritées. Le mot-clé `super` est utilisé pour appeler des fonctions sur le parent d’un objet, y compris son constructeur. - Le mot-clé `super` doit être utilisé avant que le mot-clé `this` soit utilisé dans le constructeur - Invoquer `super()` appelle le constructeur de la classe parente. Si vous voulez passer des arguments au constructeur de la classe parente, vous pouvez l’appeler avec `super(arguments)`. - Si la classe parente a une méthode (même statique) appelée `X`, vous pouvez utiliser `super.X()` pour l’appeler depuis la classe fille. #### Code d’exemple ```js class Polygon { constructor(height, width) { this.name = 'Polygon'; this.height = height; this.width = width; } getHelloPhrase() { return `Hi, I am a ${this.name}`; } } class Square extends Polygon { constructor(length) { // Ici, le constructeur de la classe parente est appelé avec // les longueurs données pour la hauteur et largeur du Polygon super(length, length); // Note : dans les classes dérivées, super() doit être appelé avant que vous ne // puissiez utiliser 'this'. Ne pas respecter cette règle causera une ReferenceError. this.name = 'Square'; this.length = length; } getCustomHelloPhrase() { const polygonPhrase = super.getHelloPhrase(); // accéder à une méthode de la classe parente avec la syntaxe super.X() return `${polygonPhrase} with a length of ${this.length}`; } get area() { return this.height * this.width; } } const mySquare = new Square(10); console.log(mySquare.area) // 100 console.log(mySquare.getHelloPhrase()) // 'Hi, I am a Square' -- Square hérite de Polygon et a accès à ses méthodes console.log(mySquare.getCustomHelloPhrase()) // 'Hi, I am a Square with a length of 10' ``` **Note :** Si nous avions essayé d’utiliser `this`avant d’appeler `super()` dans la classe Square, une ReferenceError aurait été déclenchée : ```js class Square extends Polygon { constructor(length) { this.height; // ReferenceError, super doit être appelé d’abord ! // Ici, le constructeur de la classe parente est appelé avec // les longueurs données pour la hauteur et largeur du Polygon super(length, length); // Note : dans les classes dérivées, super() doit être appelé avant que vous ne // puissiez utiliser 'this'. Ne pas respecter cette règle causera une ReferenceError. this.name = 'Square'; } } ``` #### Ressources - [extends - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Classes/extends) - [super - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Opérateurs/super) - [L’héritage au sein de JavaScript - MDN](https://developer.mozilla.org/fr/docs/Learn/JavaScript/Objects/Heritage) ### Async Await En plus des [Promises](#promesses), il y a une nouvelle syntaxe que vous pourriez rencontrer pour gérer le code asynchrone nommée *async / await*. Le but des fonctions async/await est de simplifier le comportement de l’utilisation des promesses de manière synchrone et d’exécuter un comportemnet sur un groupe de promesses. Tout comme les promesses sont similaires aux callbacks structurés, asnyc/await est similaire à la combinaison de générateurs et de promesses. Les fonctions asynchrones renvoient *toujours* une Promise. ([référence: MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Instructions/async_function)) > **Note :** Vous devez comprendre ce que sont les promesses et comment elles fonctionnent avant d’essayer de comprendre async/await car elles dépendent dessus. > **Note 2:** [*await* doit être utilisé dans une fonction *async*](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9#f3f0), ce qui signifie que vous ne pouvez pas utiliser await dans le premier niveau de votre code car ce n’est pas une fonction async. #### Code d’exemple ```js async function getGithubUser(username) { // le mot-clé async autorise l’utilisation de await dans la fonction et signifie que la fonction retourne une promesse const response = await fetch(`https://api.github.com/users/${username}`); // L’exécution est mise en pause ici jusqu’à ce que la Promise retournée par fetch soit résolue return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) // afficher dans la console la réponse - on ne peut pas utiliser la syntaxe await car ce code n’est pas une fonction async .catch(err => console.log(err)); // si notre fonction async lève une erreur, nous la récupérons ici ``` #### Explication avec un code d’exemple *Async / Await* fonctionnent avec les promises mais ils permettent d’utiliser un style de code plus impératif. L’opérateur *async* marque une fonction comme étant asynchrone et retournera toujours une *Promise*. Vous pouvez utiliser l’opérateur *await* dans une fonction *async* pour mettre en pause l’exécution sur cette ligne jusqu’à ce que la promise retournée par l’expression se fasse résoudre ou rejeter. ```js async function myFunc() { // nous pouvons utiliser l’opérateur await car cette fonction est asynchrone return "hello world"; } myFunc().then(msg => console.log(msg)) // "hello world" -- la valeur de retour de myFunc se fait transformer en promesse à cause de l’opérateur async ``` Lorsque l’expression *return* d’une fonction async est atteint, la Promise est remplie avec la valeur retournée. Si une erreur est levée à l’intérieur de la fonction async, la l’état de la promesse passera à *rejeté*. Si aucune valeur n’est retournée par une fonction async, une promesse est quand même retournée et sera résolue sans valeur lorsque l’exécution de la fonction async est terminée. L’opérateur *await* est utilisé pour attendre qu’une primesse se fasse résoudre et ne peut être utilisé qu’à l’intérieur du corps d’une fonction async. Lorsqu’il est rencontré, l’exécution du code est mise en pause jusqu’à ce que la promise se fasse résoudre. > **Note :** *fetch* est une fonction qui retourne une Promise qui nous permet de faire une requête AJAX Voyons d’abord comment nous pourrions récupérer un utilisateur sur GitHub avec des promesses. ```js function getGithubUser(username) { return fetch(`https://api.github.com/users/${username}`).then(response => response.json()); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` Voici l’équivalent avec async/await ```js async function getGithubUser(username) { // utilisation d’une promesse + du mot-clé await autorisé const response = await fetch(`https://api.github.com/users/${username}`); // L’exécution s’arrête ici jusqu’à ce que la promesse fetch soit résolue return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` La syntaxe *async/await* est particulièrement utile lorsque vous avez besoin d’enchaîner des promesses qui sont mutuellement dépendantes. Par exemple, si vous avez besoin d’obtenir un jeton d’accps pour pouvoir récupérer un post de blog sur une base de données puis les informations sur l’auteur : > **Note :** les expressions *await* ont besoin d’êtres entourées de parenthèses pour appeler leur valeur résolue et leurs propriétés sur la même ligne. ```js async function fetchPostById(postId) { const token = (await fetch('token_url')).json().token; const post = (await fetch(`/posts/${postId}?token=${token}`)).json(); const author = (await fetch(`/users/${post.authorId}`)).json(); post.author = author; return post; } fetchPostById('gzIrzeo64') .then(post => console.log(post)) .catch(err => console.log(err)); ``` ##### Gestion d’erreur À moins d’ajouter des blocs *try / catch* autour des expressions *await*, les exceptions non gérées – peu importe de si elles ont été levées dans le corps de votre fonction *async* ou lorsque le code est en pause pendant *await* – vont rejeter la promesse retournée par la fonction *async*. Utiliser l’expression `thrown` dans une fonction asynchrone donne le même résultat que retourner une promesse qui se fait rejeter [(référence : PonyFoo)](https://ponyfoo.com/articles/understanding-javascript-async-await#error-handling). > **Note :** Les promesses se comportent de la même manière ! Avec les promesses, voici comment on gérerait la chaîne d’erreur : ```js function getUser() { // Cette promesse se fera rejeter ! return new Promise((res, rej) => rej("Utilisateur non trouvé !")); } function getAvatarByUsername(userId) { return getUser(userId).then(user => user.avatar); } function getUserAvatar(username) { return getAvatarByUsername(username).then(avatar => ({ username, avatar })); } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "Utilisateur non trouvé !" ``` Équivalent avec *async / await*: ```js async function getUser() { // La promesse retournée se fera rejeter throw "Utilisateur non trouvé !"; } async function getAvatarByUsername(userId) => { const user = await getUser(userId); return user.avatar; } async function getUserAvatar(username) { var avatar = await getAvatarByUsername(username); return { username, avatar }; } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "Utilisateur non trouvé !" ``` #### Ressources externes - [Async/Await - JavaScript.Info](https://javascript.info/async-await) - [ES7 Async/Await](http://rossboucher.com/await/#/) - [6 Reasons Why JavaScript’s Async/Await Blows Promises Away](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9) - [JavaScript awaits](https://dev.to/kayis/javascript-awaits) - [Using Async Await in Express with Node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) - [Async Function](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Statements/async_function) - [Await](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Operators/await) - [Using async / await in express with node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) ### Vérité / fausseté En JavaScript, une valeur `truthy` ou `falsy` est une valeur qui se fait caster en un booléen lorsqu’elle est évaluée dans un contexte booléen. Un exemple de contexte booléen serait l’évaluation d’une condition ```if```. Chaque valeur sera transformée en ```true```, à part si elles sont égales à : - ```false``` - ```0``` - ```""``` (chaîne de caractères vide) - ```null``` - ```undefined``` - ```NaN``` Voici des exemples de *contexte booléen* : - Évaluation de condition ```if``` ```js if (myVar) {} ``` ```myVar``` peut être n’importe quel [objets de première classe](https://fr.wikipedia.org/wiki/Objet_de_premi%C3%A8re_classe) (variable, fonction, booléen) mais il sera transformé en booléen car il est évalué dans un contexte booléen. - Après l’opérateur logique **NOT** ```!``` Cet opérateur retourne ```false``` si son opérande peut être converti à ```true``` ; dans le cas contraire, il retourne ```true``` ```js !0 // true -- 0 est falsy, donc retourne true !!0 // false -- 0 est falsy, donc !0 retourne true, et donc !(!0) retourne false !!"" // false -- une chaîne vide est falsy donc NOT (NOT false) est égal à false ``` - Avec le constructeur d’objet *Boolean* ```js new Boolean(0) // false new Boolean(1) // true ``` - Dans une expression ternaire ```js myVar ? "truthy" : "falsy" ``` myVar se fait évaluer dans un contexte booléen. #### Ressources externes - [Truthy (MDN)](https://developer.mozilla.org/fr/docs/Glossary/Truthy) - [Falsy (MDN)](https://developer.mozilla.org/fr/docs/Glossary/Falsy) - [Truthy and Falsy values in JS - Josh Clanton](http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html) ### Méthodes statiques #### Explication courte Le mot-clé `static` est utilisé dans les classes pour déclarer des méthodes statiques. Les méthodes statiques sont des fonctions dans une classe qui appartiennent à l’objet classe et ne sont pas disponible dans les instances de la classe. #### Code d’exemple ```js class Repo { static getName() { return "Le nom du repo est modern-js-cheatsheet" } } // Notez que nous n’avons pas créé d’instance de la classe Repo console.log(Repo.getName()) // "Le nom du repo est modern-js-cheatsheet" let r = new Repo(); console.log(r.getName()) // Uncaught TypeError: repo.getName is not a function ``` #### Explication détaillée Les méthodes statiques peuvent être appelées à l’intérieur d’une autre méthode statique en utilisant le mot-clé `this`. Ceci ne fonctionne pas avec les méthodes non statiques, qui ne peuvent pas y accéder directement en utilisant le mot-clé `this`. ##### Appeler d’autres méthodes statiques depuis une méthode statique Pour appeler une méthode statique depuis une autre méthode statique, le mot-clé `this` peut être utilisé comme ceci : ```js class Repo { static getName() { return "Le nom du repo est modern-js-cheatsheet" } static modifyName(){ return this.getName() + '-ajout' } } console.log(Repo.modifyName()) // Le nom du repo est modern-js-cheatsheet-ajout ``` ##### Appeler des méthodes statiques depuis des méthodes non statiques Les méthodes non statiques peuvent appeler des méthodes statiques de deux façons : 1. ###### En utilisant le nom de la classe Pour accéder à une méthode statique depuis une méthode non statique, nous pouvons utiliser le nom de la classe et appeler la méthode statique comme une propriété, par exemple `NomClasse.NomMethodeStatique()` ```js class Repo { static getName() { return "Le nom du repo est modern-js-cheatsheet" } useName() { return Repo.getName() + ' et il contient des trucs vraiment importants' } } // Nous devons instancier la classe pour utiliser les méthodes non statiques let r = new Repo() console.log(r.useName()) // Le nom du repo est modern-js-cheatsheet et il contient des trucs vraiment importants ``` 2. ###### Avec le constructeur Les méthodes statiques peuvent être appelées en tant que propriétés sur l’objet constructor ```js class Repo { static getName() { return "Repo name is modern-js-cheatsheet" } useName() { // Appelle la méthode statique comme une propriété du constructeur return this.constructor.getName() + ' et il contient des trucs vraiment importants' } } // Nous devons instancier la classe pour utiliser les méthodes non statiques let r = new Repo() console.log(r.useName()) // Le nom du repo est modern-js-cheatsheet et il contient des trucs vraiment importants ``` #### Ressources externes - [static - MDN](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Classes/static) - [Static Methods - Javascript.info](https://javascript.info/class#static-methods) - [Static Members in ES6 - OdeToCode](http://odetocode.com/blogs/scott/archive/2015/02/02/static-members-in-es6.aspx) ## Glossaire ### Portée (*scope*) Le contexte dans lequel les valeurs et expressions sont “visibles”, ou peuvent être référencées. Si une variable ou une autre expression n’est pas “dans la portée actuelle”, alors son utilisation ne sera pas possible. Source : [MDN](https://developer.mozilla.org/fr/docs/Glossaire/Portée) ### Mutation de variable On dit d’une variable qu’elle a été *mutée* lorsque sa valeur initiale a été changée après coup. ```js var myArray = []; myArray.push("firstEl") // myArray s’est fait muter ``` Une variable est dite *immutable* si elle ne peut être mutée. Vous pouvez lire [l’article Mutable de MDN](https://developer.mozilla.org/fr/docs/Glossary/Mutable) pour plus de détails. ================================================ FILE: JavaScript/translations/ja-JP.md ================================================ # モダン JavaScript チートシート ![モダン JavaScript チートシート](https://i.imgur.com/aexPxMb.png) 画像クレジット: [Ahmad Awais ⚡️](https://github.com/ahmadawais) ## イントロダクション ### 動機 このドキュメントはモダンなプロジェクトでよく見られる JavaScript のチートシートと最新のサンプルコードです。 このガイドは読者に JavaScript をゼロから教えるものではありません。 基礎知識は持っていて、モダンなコードベースに慣れる(例えば React を学ぶ)のに苦労している開発者を助けるためのものです。 説明の中で JavaScript の諸概念が使われています。 また、議論の余地のあるポイントについてときどき個人的な tips を載せますが、その際はあくまでも個人的なおすすめであることを述べるように気をつけます。 > **メモ:** ここで紹介されている概念のほとんどは JavaScript 言語のアップデート( ES2015 、しばしば ES6 と呼ばれるもの)によるものです。そのアップデートで追加された新しい機能の説明は[こちらのページ](http://es6-features.org)で見つけることができます。このページはとてもわかりやすく書かれています。 ### 補完的なリソース 概念がうまく理解できない場合は、以下のリソースで答えを探すことをおすすめします: - [MDN (Mozilla Developer Network)](https://developer.mozilla.org/en-US/search?q=) - [You don't know JS (book)](https://github.com/getify/You-Dont-Know-JS) - [ES6 Features with examples](http://es6-features.org) - [WesBos blog (ES6)](http://wesbos.com/category/es6/) - [Javascript Basics for Beginners](https://www.udacity.com/course/javascript-basics--ud804) - Udacity の無料コース - [Reddit (JavaScript)](https://www.reddit.com/r/javascript/) - [Google](https://www.google.com/) (ブログとリソースを見つけるために) - [StackOverflow](https://stackoverflow.com/questions/tagged/javascript) ## 目次 - [モダン JavaScript チートシート](#modern-javascript-cheatsheet) * [イントロダクション](#introduction) + [動機](#motivation) + [補完的なリソース](#complementary-resources) * [目次](#table-of-contents) * [各種概念](#notions) + [変数宣言: `var` / `const` / `let`](#variable-declaration-var-const-let) - [短い説明](#short-explanation) - [サンプルコード](#sample-code) - [詳細な説明](#detailed-explanation) - [外部のリソース](#external-resource) + [アロー関数](#-arrow-function) - [サンプルコード](#sample-code-1) - [詳細な説明](#detailed-explanation-1) * [簡潔さ](#concision) * [*`this`* 参照](#this-reference) - [有用なリソース](#useful-resources) + [関数の引数のデフォルト値](#function-default-parameter-value) - [外部のリソース](#external-resource-1) + [オブジェクトや配列の分割](#destructuring-objects-and-arrays) - [サンプルコード付きの説明](#explanation-with-sample-code) - [有用なリソース](#useful-resources-1) + [配列のメソッド - `map` / `filter` / `reduce`](#array-methods---map--filter--reduce) - [サンプルコード](#sample-code-2) - [説明](#explanation) * [`Array.prototype.map()`](#arrayprototypemap) * [`Array.prototype.filter()`](#arrayprototypefilter) * [`Array.prototype.reduce()`](#arrayprototypereduce) - [外部のリソース](#external-resource-2) + [スプレッド演算子「 `...` 」](#spread-operator-) - [サンプルコード](#sample-code-3) - [説明](#explanation-1) * [イテラブル(配列など)の中での使用](#in-iterables-like-arrays) * [関数のレスト引数](#function-rest-parameter) * [オブジェクトプロパティのスプレッディング](#object-properties-spreading) - [外部のリソース](#external-resources) + [オブジェクトプロパティの省略形](#object-property-shorthand) - [説明](#explanation-2) - [外部のリソース](#external-resources-1) + [プロミス](#promises) - [サンプルコード](#sample-code-4) - [説明](#explanation-3) * [プロミスの作成](#create-the-promise) * [プロミスハンドラーの使用](#promise-handlers-usage) - [外部のリソース](#external-resources-2) + [テンプレートリテラル](#template-literals) - [サンプルコード](#sample-code-5) - [外部のリソース](#external-resources-3) + [タグ付きテンプレートリテラル](#tagged-template-literals) - [外部のリソース](#external-resources-4) + [インポート / エクスポート](#imports--exports) - [サンプルコード付きの説明](#explanation-with-sample-code-1) * [名前付きエクスポート](#named-exports) * [デフォルトインポート / エクスポート](#default-import--export) - [外部のリソース](#external-resources-5) + [JavaScript の *`this`*](#-javascript-this) - [外部のリソース](#external-resources-6) + [クラス](#class) - [サンプルコード](#samples) - [外部のリソース](#external-resources-7) + [`extends` キーワードと `super` キーワード](#extends-and-super-keywords) - [サンプルコード](#sample-code-6) - [外部のリソース](#external-resources-8) + [Async Await](#async-await) - [サンプルコード](#sample-code-7) - [サンプルコード付きの説明](#explanation-with-sample-code-2) - [エラーハンドリング](#error-handling) - [外部のリソース](#external-resources-9) + [True になるもの / False になるもの](#truthy--falsy) - [外部のリソース](#external-resources-10) + [アナモルフィズム / カタモルフィズム](#anamorphisms-and-catamorphisms) - [アナモルフィズム](#anamorphisms) - [カタモルフィズム](#catamorphisms) - [外部のリソース](#external-resources-11) + [ジェネレーター](#generators) - [外部のリソース](#external-resources-12) + [スタティックメソッド](#static-methods) - [短い説明](#short-explanation-1) - [サンプルコード](#sample-code-8) - [詳細な説明](#detailed-explanation-2) * [スタティックメソッドから別のスタティックメソッドを呼ぶ](#calling-other-static-methods-from-a-static-method) * [スタティックでないメソッドからスタティックメソッドを呼ぶ](#calling-static-methods-from-non-static-methods) - [外部のリソース](#external-resources-13) * [用語集](#glossary) + [スコープ](#-scope) + [変数ミューテーション](#-variable-mutation) ## 各種概念 ### 変数宣言: `var` / `const` / `let` JavaScript には、変数の宣言に利用できるキーワードが 3 つあり、それぞれ違いがあります。 その 3 つのキーワードとは、 ```var``` と ```let``` と ```const``` です。 #### 短い説明 ```const``` キーワードで宣言された変数は再代入ができません。 ```let``` と ```var``` は再代入ができます。 基本的に、変数はいつも ```const``` で宣言するようにして、変数を *変更* したり(訳注: 原文では「 mutate 」です)後から再代入したりする必要がある場合に ```let``` を使うことをおすすめします。
スコープ 再代入可能 ミュータブル テンポラルデッドゾーン
`const` ブロック ×
`let` ブロック
`var` 関数 ×
#### サンプルコード ```javascript const person = "Nick"; person = "John" // Will raise an error, person can't be reassigned ``` ```javascript let person = "Nick"; person = "John"; console.log(person) // "John", reassignment is allowed with let ``` #### 詳細な説明 変数の [*スコープ*](#scope_def) とは、ざっくり言うと、「コードの中でその変数が利用できる範囲」のことです。 ##### `var` ```var``` で宣言された変数のスコープは *関数スコープ* になります。 これは、ある変数が関数の中で作成されているとき、その関数の中のすべてのパーツがその変数にアクセスできることを意味します。 加えて、ある関数の中で作成された *関数スコープ* の変数はその関数の外側ではアクセスすることができません。 *X スコープ* 変数ということばの意味は、その変数が X のプロパティであるような感じでイメージすることをおすすめします。 ```javascript function myFunction() { var myVar = "Nick"; console.log(myVar); // "Nick" - myVar is accessible inside the function } console.log(myVar); // Throws a ReferenceError, myVar is not accessible outside the function. ``` 変数のスコープに引き続き着目し、もう少しわかりづらい例を見てみましょう: ```javascript function myFunction() { var myVar = "Nick"; if (true) { var myVar = "John"; console.log(myVar); // "John" // actually, myVar being function scoped, we just erased the previous myVar value "Nick" for "John" } console.log(myVar); // "John" - see how the instructions in the if block affected this value } console.log(myVar); // Throws a ReferenceError, myVar is not accessible outside the function. ``` 加えて、 *`var`* で宣言された変数は実行時にスコープの一番上に移動されます。 この処理のことを [`var` ホイスティング](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting) と呼びます。 次のコードは ```js console.log(myVar) // undefined -- no error raised var myVar = 2; ``` 実行時に次のように解釈されます。 ```js var myVar; console.log(myVar) // undefined -- no error raised myVar = 2; ``` ##### `let` ```var``` と ```let``` は大体同じですが、 ```let``` で宣言された変数には次の特徴があります。 - *ブロックスコープ* である - 代入の前にアクセスすることが *できない* - 同じスコープの中で再宣言できない 上の例を使ってブロックスコープのインパクトを見てみましょう: ```javascript function myFunction() { let myVar = "Nick"; if (true) { let myVar = "John"; console.log(myVar); // "John" // actually, myVar being block scoped, we just created a new variable myVar. // this variable is not accessible outside this block and totally independent // from the first myVar created ! } console.log(myVar); // "Nick", see how the instructions in the if block DID NOT affect this value } console.log(myVar); // Throws a ReferenceError, myVar is not accessible outside the function. ``` ここで、 *`let`* (と *`const`* )で宣言された変数に関して、代入前にアクセスできないというのは次のコードに示すとおりの意味です: ```js console.log(myVar) // raises a ReferenceError ! let myVar = 2; ``` *`var`* とは対照的に、 *`let`* や *`const`* の変数では代入前に読み込みあるいは書き込みをしようとするとエラーが上がります。 この現象はしばしば [*テンポラルデッドゾーン*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let) あるいは *TDZ* と呼ばれます。 > **メモ:** 技術的には、 *`let`* と *`const`* の変数宣言もホイストされています。 これらは代入前に使用されないように作られているため、直感的にはホスティングが起こっていないように感じられますが、実際には起こっています。 詳しく知りたい場合は[こちらの非常に詳しい説明](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified)をご覧ください。 加えて、 *`let`* 変数は再宣言することができません: ```js let myVar = 2; let myVar = 3; // Raises a SyntaxError ``` ##### `const` ```const``` で宣言された変数は *`let`* 変数のように振る舞いますが、再代入ができません。 まとめると、 *`const`* 変数には次の特徴があります: - *ブロックスコープ* である - 代入前にアクセスすることができない - 同じスコープの中で再宣言できない - 再代入できない ```js const myVar = "Nick"; myVar = "John" // raises an error, reassignment is not allowed ``` ```js const myVar = "Nick"; const myVar = "John" // raises an error, re-declaration is not allowed ``` しかし、微妙なポイントがあります: ```const``` 変数は [**イミュータブル**](#mutation_def) ではありません! 具体的に言うと、 ```const``` で宣言された *オブジェクト* と *配列* は変更することが **できます** 。 オブジェクトの場合: ```js const person = { name: 'Nick' }; person.name = 'John' // this will work ! person variable is not completely reassigned, but mutated console.log(person.name) // "John" person = "Sandra" // raises an error, because reassignment is not allowed with const declared variables ``` 配列の場合: ```js const person = []; person.push('John'); // this will work ! person variable is not completely reassigned, but mutated console.log(person[0]) // "John" person = ["Nick"] // raises an error, because reassignment is not allowed with const declared variables ``` #### 外部のリソース - [How let and const are scoped in JavaScript - WesBos](http://wesbos.com/javascript-scoping/) - [Temporal Dead Zone (TDZ) Demystified](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) ### アロー関数 ES6 JavaScript のアップデートで *アロー関数* が導入されました。 これは、変数を宣言し利用するもうひとつの方法です。 アロー関数がもたらすメリットは次のとおりです: - より簡潔である - *`this`* が周辺のスコープからピックアップされる - 暗黙的な `return` #### サンプルコード - 簡潔さと暗黙的な `return` ```js function double(x) { return x * 2; } // Traditional way console.log(double(2)) // 4 ``` ```js const double = x => x * 2; // Same function written as an arrow function with implicit return console.log(double(2)) // 4 ``` - *`this`* 参照 アロー関数の中では、 *`this`* はその周りにある実行コンテキストの *`this`* と同じものになります。 アロー関数を使えば、基本的に、関数の中で関数を呼び出す前に `that = this` とするトリックを使う必要がありません。 ```js function myFunc() { this.myVar = 0; setTimeout(() => { this.myVar++; console.log(this.myVar) // 1 }, 0); } ``` #### 詳細な説明 ##### 簡潔さ アロー関数は、従来の関数よりも多くの点において簡潔です。 すべての起こりうるケースを見てみましょう: - 暗黙的な `return` vs. 明示的な `return` **明示的な `return`** は、 *`return`* キーワードがボディの中で使われている関数のことです。 ```js function double(x) { return x * 2; // this function explicitly returns x * 2, *return* keyword is used } ``` 関数を書く従来の方法では、 `return` は常に明示的に書く形になります。 しかし、アロー関数では、 *暗黙的な `return`* を使うことができます。 これは、値を返すのに *`return`* キーワードを使う必要がないという意味です。 ```js const double = (x) => { return x * 2; // Explicit return here } ``` この関数は何かを返すだけのものなので( *`return`* キーワードの前に他の処理が無いので)、暗黙的な `return` を使うことができます。 ```js const double = (x) => x * 2; // Correct, returns x*2 ``` こうするためには、 **かっこと `return` キーワードを削除** しさえすれば OK です。 そのため、これは *暗黙的な* `return` と呼ばれています。 *`return`* キーワードは書かれていませんが、この関数は実際には ```x * 2``` を返します。 > **メモ:** もしある関数が値を返さなければ、それは暗黙的な `return` も明示的な `return` も行っていません。 加えて、 *オブジェクト* を暗黙的に返したい場合は、ブロックのかっことの衝突を防ぐために **その周りにかっこを付ける必要があります**: ```js const getPerson = () => ({ name: "Nick", age: 24 }) console.log(getPerson()) // { name: "Nick", age: 24 } -- object implicitly returned by arrow function ``` - 引数が 1 つだけの場合 引数を 1 つだけ受け取る関数の場合は、引数の周りのかっこを省略することができます 上の *`double`* のコードをもう一度取り上げましょう: ```js const double = (x) => x * 2; // this arrow function only takes one parameter ``` 引数のかっこは省略できます: ```js const double = x => x * 2; // this arrow function only takes one parameter ``` - 引数が無い場合 アロー関数が引数を取らない場合、かっこを付ける必要があります。 かっこをつけないと正しいシンタックスではなくなります。 ```js () => { // parentheses are provided, everything is fine const x = 2; return x; } ``` ```js => { // No parentheses, this won't work! const x = 2; return x; } ``` ##### *`this`* 参照 アロー関数といっしょに導入されたこの微妙なポイントを理解するためには、 JavaScript における [`this`](#this_def) の振る舞いを知っておく必要があります。 アロー関数では、 *`this`* はひとつ外側にある実行コンテキストの *`this`* の値に等しくなります。 これはつまり、アロー関数は新しい *`this`* を作成せず代わりに周囲の環境から *`this`* を取得します。 アロー関数がなかった頃は、関数内の関数で *`this`* の値にアクセスしたい場合は、 *`that = this`* または *`self = this`* のトリックを使う必要がありました。 例えば、 `setTimeout` 関数を `myFunc` の中で利用する場合は次のようにする必要がありました: ```js function myFunc() { this.myVar = 0; var that = this; // that = this trick setTimeout( function() { // A new *this* is created in this function scope that.myVar++; console.log(that.myVar) // 1 console.log(this.myVar) // undefined -- see function declaration above }, 0 ); } ``` アロー関数があれば、 *`this`* はその外部の環境から取得されます: ```js function myFunc() { this.myVar = 0; setTimeout( () => { // this taken from surrounding, meaning myFunc here this.myVar++; console.log(this.myVar) // 1 }, 0 ); } ``` #### 有用なリソース - [Arrow functions introduction - WesBos](http://wesbos.com/arrow-functions/) - [JavaScript arrow function - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - [Arrow function and lexical *this*](https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4) ### 関数の引数のデフォルト値 ES2015 の JavaScript アップデート以降、関数の引数のデフォルト値を次のシンタックスでセットできます: ```js function myFunc(x = 10) { return x; } console.log(myFunc()) // 10 -- no value is provided so x default value 10 is assigned to x in myFunc console.log(myFunc(5)) // 5 -- a value is provided so x is equal to 5 in myFunc console.log(myFunc(undefined)) // 10 -- undefined value is provided so default value is assigned to x console.log(myFunc(null)) // null -- a value (null) is provided, see below for more details ``` デフォルト引数は次の 2 つの状況でのみ適用されます: - 引数が渡されなかった - *`undefined`* 引数が渡された 言い換えると、 *`null`* を渡した場合はデフォルト引数は **適用されません** 。 > **メモ:** デフォルト値の代入は、分割引数(訳注: 原文では「 destructured parameters 」です)でも使用することができます(例は、次の概念をご覧ください) #### 外部のリソース - [Default parameter value - ES6 Features](http://es6-features.org/#DefaultParameterValues) - [Default parameters - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) ### オブジェクトや配列の分割 *分割* (訳注: 原文では「 destructuring 」です)はオブジェクトまたは配列に格納されたデータから値を抽出して新しい変数を作成する便利な方法です。 いくつかユースケースをあげるなら、 *分割* は関数の引数を分割するために使用することもできますし、 React プロジェクトの *`this.props`* で使用することもできます。 #### サンプルコード付きの説明 - オブジェクト 以下すべてのサンプルに対して次のオブジェクトについて考えてみましょう: ```js const person = { firstName: "Nick", lastName: "Anderson", age: 35, sex: "M" } ``` 分割がない場合、次のようになります。 ```js const first = person.firstName; const age = person.age; const city = person.city || "Paris"; ``` 分割がある場合は、ワンラインで書くことができます: ```js const { firstName: first, age, city = "Paris" } = person; // That's it ! console.log(age) // 35 -- A new variable age is created and is equal to person.age console.log(first) // "Nick" -- A new variable first is created and is equal to person.firstName console.log(firstName) // ReferenceError -- person.firstName exists BUT the new variable created is named first console.log(city) // "Paris" -- A new variable city is created and since person.city is undefined, city is equal to the default value provided "Paris". ``` **メモ:** ```const { age } = person;``` において、 *`const`* キーワードの後のかっこは、オブジェクトやブロックの宣言として使用されるのではなく、 *分割* のシンタックスとなります。 - 関数の引数 *分割* は関数のオブジェクト引数を分割するためにしばしば使用されます。 分割を使わない場合、次のようになります。 ```js function joinFirstLastName(person) { const firstName = person.firstName; const lastName = person.lastName; return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` オブジェクト引数 *`person`* を分割すれば、より簡潔な関数を書くことができます: ```js function joinFirstLastName({ firstName, lastName }) { // we create firstName and lastName variables by destructuring person parameter return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` 分割は[アロー関数](#arrow_func_concept)といっしょに使うとぐっといい感じになります: ```js const joinFirstLastName = ({ firstName, lastName }) => firstName + '-' + lastName; joinFirstLastName(person); // "Nick-Anderson" ``` - 配列 次の配列について考えてみましょう: ```js const myArray = ["a", "b", "c"]; ``` 分割を使わない場合、次のようになります。 ```js const x = myArray[0]; const y = myArray[1]; ``` 分割を使うと、次のように書けます。 ```js const [x, y] = myArray; // That's it ! console.log(x) // "a" console.log(y) // "b" ``` #### 有用なリソース - [ES6 Features - Destructuring Assignment](http://es6-features.org/#ArrayMatching) - [Destructuring Objects - WesBos](http://wesbos.com/destructuring-objects/) - [ExploringJS - Destructuring](http://exploringjs.com/es6/ch_destructuring.html) ### 配列のメソッド - `map` / `filter` / `reduce` *`map`* 、 *`filter`* 、 *`reduce`* は [*関数プログラミング*](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0) という名前のプログラミングパラダイムに由来する配列のメソッドです。 まとめ: - **Array.prototype.map()** 配列を受け取り、各要素に対して何かをして、変更された要素を持つ配列を返す。 - **Array.prototype.filter()** 配列を受け取り、要素ごとに保持するかどうかを決めて、保持する要素のみからなる配列を返す。 - **Array.prototype.reduce()** 配列を受け取り、要素を 1 つの値に集約する(その値が返される)。 これらは組み合わせ可能で、簡潔でエレガントなので、関数プログラミングは原則に則ってできるかぎりこれらを使用することをおすすめします。 これら 3 つのメソッドを使えば、ほとんどの状況で *`for`* ループと *`forEach`* ループを使用しなくてよくなります。 *`for`* ループが使いたい場合は、 *`map`* と *`filter`* と *`reduce`* を組み合わせて処理を実現することを試みてください。 新しい考え方を身につける必要があるので最初は苦労するかもしれませんが、一度馴れればものごとはよりかんたんになります。 #### サンプルコード ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; const doubledNumbers = numbers.map(n => n * 2); // [0, 2, 4, 6, 8, 10, 12] const evenNumbers = numbers.filter(n => n % 2 === 0); // [0, 2, 4, 6] const sum = numbers.reduce((prev, next) => prev + next, 0); // 21 ``` `map` 、 `filter` 、 `reduce` を使って、グレードが 10 以上の学生のグレードの合計値を計算してみます: ```js const students = [ { name: "Nick", grade: 10 }, { name: "John", grade: 15 }, { name: "Julia", grade: 19 }, { name: "Nathalie", grade: 9 }, ]; const aboveTenSum = students .map(student => student.grade) // we map the students array to an array of their grades .filter(grade => grade >= 10) // we filter the grades array to keep those 10 or above .reduce((prev, next) => prev + next, 0); // we sum all the grades 10 or above one by one console.log(aboveTenSum) // 44 -- 10 (Nick) + 15 (John) + 19 (Julia), Nathalie below 10 is ignored ``` #### 説明 例として、数値からなる次の配列について考えてみましょう: ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; ``` ##### `Array.prototype.map()` ```js const doubledNumbers = numbers.map(function(n) { return n * 2; }); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` ここでは何が起こっているのでしょうか。 `.map` を配列 *`numbers`* に対して使用しています。 `map` は渡された関数を配列の各要素に適用します。 この関数のゴールは、 `map` が利用できるように、渡された値から新しい値を生成して返すことです。 わかりやすくするために、今回は特別にこの関数を抽出しましょう: ```js const doubleN = function(n) { return n * 2; }; const doubledNumbers = numbers.map(doubleN); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` ```numbers.map(doubleN)``` は ```[doubleN(0), doubleN(1), doubleN(2), doubleN(3), doubleN(4), doubleN(5), doubleN(6)]``` を生成します。 そしてこれは ```[0, 2, 4, 6, 8, 10, 12]``` になります。 > **メモ:** 新しい配列を返すのではなく副作用のあるループを回したいだけの場合は、 `map` の代わりの `for` / `forEach` ループを使いたくなるかもしれません。 ##### `Array.prototype.filter()` ```js const evenNumbers = numbers.filter(function(n) { return n % 2 === 0; // true if "n" is par, false if "n" isn't }); console.log(evenNumbers); // [0, 2, 4, 6] ``` 配列 *`numbers`* に対して `.filter()` を使用しています。 `filter` は指定された関数に配列の各要素を渡します。 この関数のゴールは、現在の値を保持すべきかどうかを決める真偽値を返すことです。 `filter` は保持すべき値のみを格納した配列を返します。 ##### `Array.prototype.reduce()` `reduce` メソッドのゴールは、配列のすべての要素を走査してひとつの値に *縮減* することです。 どのように集約するかのロジックはあなた次第です。 ```js const sum = numbers.reduce( function(acc, n) { return acc + n; }, 0 // accumulator variable value at first iteration step ); console.log(sum) //21 ``` `.map` メソッドと `.filter` メソッドのように、 `.reduce` は配列に対して適用されるもので、第 1 引数に関数を受け取ります。 ただしこの場合は違いがあります: - `.reduce` は 2 つの引数を受け取ります 第 1 引数は、ループの各ステップで呼び出される関数です。 第 2 引数は、ループの最初のステップにおける蓄積用の変数(訳注: 原文では「 accumulator variable 」です)の値です(これを理解するには次のポイントを読んでください)。 - 関数引数 `.reduce` の第 1 引数として渡す関数は、 2 つの引数を受け取ります。 1 つめの引数(ここでは *`acc`* )は、蓄積用の変数で、 2 つめの引数( *`n`* )は現在の要素です。 蓄積用の変数は、 **ひとつ前の** ループのステップにおける関数の戻り値と等しいものです。 ループの最初のステップでは *`acc`* は `.reduce` の第 2 引数に渡された値に等しくなります。 ###### ループの最初のステップ `reduce` の第 2 引数に `0` を渡しているので、 ```acc = 0``` となります。 *`numbers`* 配列の最初の要素を取るので、 ```n = 0``` となります。 関数は *`acc + n`* を返すので、これは `0 + 0` で `0` になります。 ###### ループの第 2 ステップ ひとつ前のループのステップで関数が返した値が使われるので、 ```acc = 0``` となります。 *`numbers`* 配列の 2 番目の要素を取るので、 ```n = 1``` となります。 関数は *`acc + n`* を返すので、これは `0 + 1` で `1` になります。 ###### ループの第 3 ステップ ひとつ前のループのステップで関数が返した値が使われるので、 ```acc = 1``` となります。 *`numbers`* 配列の 2 番目の要素を取るので、 ```n = 2``` となります。 関数は *`acc + n`* を返すので、これは `1 + 2` で `3` になります。 ###### ループの第 4 ステップ ひとつ前のループのステップで関数が返した値が使われるので、 ```acc = 3``` となります。 *`numbers`* 配列の 2 番目の要素を取るので、 ```n = 3``` となります。 関数は *`acc + n`* を返すので、これは `3 + 3` で `6` になります。 ###### ループの最後のステップ ひとつ前のループのステップで関数が返した値が使われるので、 ```acc = 15``` となります。 *`numbers`* 配列の最後の要素を取るので、 ```n = 6``` となります。 関数は *`acc + n`* を返すので、これは `15 + 6` で `21` になります。 これがループの最後のステップなので、 **`.reduce`** は `21` を返します。 #### 外部のリソース - [Understanding map / filter / reduce in JS](https://hackernoon.com/understanding-map-filter-and-reduce-in-javascript-5df1c7eee464) ### スプレッド演算子「 `...` 」 スプレッド演算子(訳注: 原文では「 spread operator 」です)は ES2015 で導入されました。 イテラブルなオブジェクト(訳注: 原文では「 iterable 」です)(配列など)の要素を、複数の要素が来るべきところに展開するために使用されます。 #### サンプルコード ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ```js function myFunc(x, y, ...params) { console.log(x); console.log(y); console.log(params) } myFunc("a", "b", "c", "d", "e", "f") // "a" // "b" // ["c", "d", "e", "f"] ``` ```js const { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } ``` #### 説明 ##### イテラブル(配列など)の中での使用 次の 2 つの配列があるものとします: ```js const arr1 = ["a", "b", "c"]; const arr2 = [arr1, "d", "e", "f"]; // [["a", "b", "c"], "d", "e", "f"] ``` *`arr1`* がそのまま *`arr2`* にインジェクトされたので、 *`arr2`* の第 1 要素は配列です。 しかし、実際は *`arr2`* をすべて文字からなる配列にしたいものとしましょう。 そうしたい場合は、 *`arr1`* の要素を *スプレッド* して *`arr2`* に入れることができます。 スプレッド演算子を使うと、次のように書けます。 ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ##### 関数のレスト引数 関数の引数において、レスト演算子(訳注: 原文では「 rest operator 」です)を使って引数をまとめて、ループ可能なひとつの配列に入れ込むことができます。 すでに、関数に渡されたすべての引数を格納した配列に等しい **`arguments`** オブジェクトが関数にはバインドされています。 ```js function myFunc() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } myFunc("Nick", "Anderson", 10, 12, 6); // "Nick" // "Anderson" // 10 // 12 // 6 ``` しかし、仮に、この関数に、グレードと平均グレードを持つ新しい学生のオブジェクトを作成させたい場合を考えましょう。 最初の 2 つの引数を個別の 2 つの変数に抽出しておいて、すべてのグレードを格納したループ可能な配列が取得できるなら、便利ですよね。 まさにこれがレスト演算子でできることなのです! ```js function createStudent(firstName, lastName, ...grades) { // firstName = "Nick" // lastName = "Anderson" // [10, 12, 6] -- "..." takes all other parameters passed and creates a "grades" array variable that contains them const avgGrade = grades.reduce((acc, curr) => acc + curr, 0) / grades.length; // computes average grade from grades return { firstName: firstName, lastName: lastName, grades: grades, avgGrade: avgGrade } } const student = createStudent("Nick", "Anderson", 10, 12, 6); console.log(student); // { // firstName: "Nick", // lastName: "Anderson", // grades: [10, 12, 6], // avgGrade: 9,33 // } ``` > **メモ:** `grades.length` が存在するかどうか、あるいは `0` と異なるかどうかをチェックしていないので、 `createStudent` 関数はよくありません。 しかし、この形だと読みやすいので、そのケースは処理していません。 ##### オブジェクトプロパティのスプレッディング ここを読む場合は、イテラブルオブジェクトに対するレスト演算子と関数の引数に関するひとつ前の説明を先に読むことをおすすめします。 ```js const myObj = { x: 1, y: 2, a: 3, b: 4 }; const { x, y, ...z } = myObj; // object destructuring here console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } // z is the rest of the object destructured: myObj object minus x and y properties destructured const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } // Here z object properties are spread into n ``` #### 外部のリソース - [TC39 - Object rest/spread](https://github.com/tc39/proposal-object-rest-spread) - [Spread operator introduction - WesBos](https://github.com/wesbos/es6-articles/blob/master/28%20-%20Spread%20Operator%20Introduction.md) - [JavaScript & the spread operator](https://codeburst.io/javascript-the-spread-operator-a867a71668ca) - [6 Great uses of the spread operator](https://davidwalsh.name/spread-operator) ### オブジェクトプロパティの省略形 変数をオブジェクトのプロパティに代入するとき、変数名がプロパティ名と同じ場合は、次の形で書くことができます: ```js const x = 10; const myObj = { x }; console.log(myObj.x) // 10 ``` #### 説明 新しい *オブジェクトリテラル* を宣言して、プロパティの値として変数を使用したい場合は、( ES2015 以前は)たいてい次のようなコードを書いたことでしょう: ```js const x = 10; const y = 20; const myObj = { x: x, // assigning x variable value to myObj.x y: y // assigning y variable value to myObj.y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` ご覧のとおり、 `myObj` のプロパティ名はそこに値を割り当てたい変数の名前と同じなので、非常にくどい感じになります。 ES2015 では、変数名がプロパティ名と同じ場合は、次の省略形を使うことができます: ```js const x = 10; const y = 20; const myObj = { x, y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` #### 外部のリソース - [Property shorthand - ES6 Features](http://es6-features.org/#PropertyShorthand) ### プロミス プロミスとは、非同期的な関数(訳注: 原文では「 asynchronous function 」です)から同期的に(訳注: 原文では「 synchronously 」です)返すことができるオブジェクトです([参考](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#3cd0)))。 プロミスは[コールバック地獄](http://callbackhell.com/)(訳注: 原文では「 callback hell 」です)を避けるために使用することができます。 モダンな JavaScript プロジェクトで出会うますます頻繁に使われるようになっています。 #### サンプルコード ```js const fetchingPosts = new Promise((res, rej) => { $.get("/posts") .done(posts => res(posts)) .fail(err => rej(err)); }); fetchingPosts .then(posts => console.log(posts)) .catch(err => console.log(err)); ``` #### 説明 *Ajax リクエスト* を行う場合は、時間のかかるリソースが求められることもあるので、レスポンスは同期的ではありません。 リクエストされたリソースが何らかの理由で利用不可の場合( 404 の場合)、レスポンスが戻ってこないこともあります。 このような状況を扱うために、 ES2015 は *プロミス* を提供しました。 プロミスは異なる 3 つの状態を持つことができます: - ペンディング(訳注: 原文では「 Pending 」です) - フルフィルド(訳注: 原文では「 Fulfilled 」です) - リジェクテッド(訳注: 原文では「 Rejected 」です) プロミスを使って、リソース X をフェッチするために Ajax リクエストを扱う場合を考えてみましょう。 ##### プロミスの作成 最初にプロミスを作成します。 X への Ajax リクエストを行うために jQuery の `get` メソッドを使います。 ```js const xFetcherPromise = new Promise( // Create promise using "new" keyword and store it into a variable function(resolve, reject) { // Promise constructor takes a function parameter which has resolve and reject parameters itself $.get("X") // Launch the Ajax request .done(function(X) { // Once the request is done... resolve(X); // ... resolve the promise with the X value as parameter }) .fail(function(error) { // If the request has failed... reject(error); // ... reject the promise with the error as parameter }); } ) ``` 上の例のとおり、プロミスオブジェクトは、 2 つの引数 **`resolve`** と **`reject`** を受け取る *エクセキューター* 関数(訳注: 原文では「 executor function 」です)を受け取ります。 これらの引数は、プロミスの *ペンディング* ステートを *フルフィルド* ステートと *リジェクテッド* ステートのそれぞれに移行させるときに呼び出されます。 プロミスはインスタンスが作成された後はペンディングステートになっており、 *エクセキューター* 関数が即座に実行されます。 *エクセキューター* 関数の中で *`resolve`* か *`reject`* の一方が呼び出されたら、プロミスは関連づけられたハンドラーを呼び出します。 ##### プロミスハンドラーの使用 プロミスの結果(もしくはエラー)を取得するには、次のようにしてハンドラーをアタッチする必要があります: ```js xFetcherPromise .then(function(X) { console.log(X); }) .catch(function(err) { console.log(err) }) ``` プロミスが成功すれば、 *`resolve`* が実行され ```.then``` の引数として渡された関数が実行されます。 プロミスが失敗すれば、 *`reject`* が実行され、 ```.catch``` の引数として渡された関数が実行されます。 > **メモ:** もし、対応するハンドラーがアタッチされたときにプロミスがすでにフルフィルドやリジェクテッドの状態になっていれば、そのハンドラーは呼び出されます。非同期の操作の完了とアタッチされるハンドラの間で競合状態は発生しません。([参考: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#Description)) #### 外部のリソース - [JavaScript Promises for dummies - Jecelyn Yeen](https://scotch.io/tutorials/javascript-promises-for-dummies) - [JavaScript Promise API - David Walsh](https://davidwalsh.name/promises) - [Using promises - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) - [What is a promise - Eric Elliott](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261) - [JavaScript Promises: an Introduction - Jake Archibald](https://developers.google.com/web/fundamentals/getting-started/primers/promises) - [Promise documentation - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) ### テンプレートリテラル テンプレートリテラルとは、単一行・複数行の文字列に対する [*式補完*](https://en.wikipedia.org/wiki/String_interpolation) (訳注: 原文は「 expression interpolation 」です)です。 言い換えると、テンプレートリテラルは、 JavaScript の式(例えば変数)をその中で使える新しい文字列シンタックスです。 #### サンプルコード ```js const name = "Nick"; `Hello ${name}, the following expression is equal to four : ${2+2}`; // Hello Nick, the following expression is equal to four: 4 ``` #### 外部のリソース - [String interpolation - ES6 Features](http://es6-features.org/#StringInterpolation) - [ES6 Template Strings - Addy Osmani](https://developers.google.com/web/updates/2015/01/ES6-Template-Strings) ### タグ付きテンプレートリテラル テンプレートタグは *[テンプレートリテラル](#template-literals)にプリフィックスされる関数* です。 関数がこの形で呼び出されたとき、第 1 引数はテンプレートの補完を行う変数と変数の間に現れる *文字列* からなる配列で、その後の引数は補完に使われる値です。 これをすべて捉えるにはスプレッド演算子を使用します。 ([参考: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals)) > **メモ:** [styled-components](https://www.styled-components.com/) という有名なライブラリはこの機能を多用しています。 次のコードは、タグ付きテンプレートリテラルがどのように動作するかを示す遊びのサンプルです。 ```js function highlight(strings, ...values) { const interpolation = strings.reduce((prev, current) => { return prev + current + (values.length ? "" + values.shift() + "" : ""); }, ""); return interpolation; } const condiment = "jam"; const meal = "toast"; highlight`I like ${condiment} on ${meal}.`; // "I like jam on toast." ``` 次はもっとおもしろいサンプルです: ```js function comma(strings, ...values) { return strings.reduce((prev, next) => { let value = values.shift() || []; value = value.join(", "); return prev + next + value; }, ""); } const snacks = ['apples', 'bananas', 'cherries']; comma`I like ${snacks} to snack on.`; // "I like apples, bananas, cherries to snack on." ``` #### 外部のリソース - [Wes Bos on Tagged Template Literals](http://wesbos.com/tagged-template-literals/) - [Library of common template tags](https://github.com/declandewet/common-tags) ### インポート / エクスポート ES6 モジュールは、他のモジュールが明示的にエクスポートした変数や関数にモジュールがアクセスするために使用するための方法です。 インポート / エクスポートに関する MDN のリソース(下の外部のリソースのところをご覧ください)を見ることを強くおすすめします。 そのリソースはわかりやすいと同時に、ポイントが網羅されています。 #### サンプルコード付きの説明 ##### 名前付きエクスポート 名前付きエクスポート(訳注: 原文では「 named exports 」です)は、モジュールから複数の値をエクスポートするための方法です。 > **メモ:** 名前付きエクスポートは、名前の付いた[第一級オブジェクト](https://en.wikipedia.org/wiki/First-class_citizen)に対してのみ可能です。 ```js // mathConstants.js export const pi = 3.14; export const exp = 2.7; export const alpha = 0.35; // ------------- // myFile.js import { pi, exp } from './mathConstants.js'; // Named import -- destructuring-like syntax console.log(pi) // 3.14 console.log(exp) // 2.7 // ------------- // mySecondFile.js import * as constants from './mathConstants.js'; // Inject all exported values into constants variable console.log(constants.pi) // 3.14 console.log(constants.exp) // 2.7 ``` 名前付きインポートは *分割* に似ていますが、シンタックスが異なり、分割と同じものではありません。 名前付きインポートは、デフォルト値や *深い* (訳注: 原文では「 deep 」です)分割をサポートしていません。 加えて、エイリアスを使うことができますが、そのシンタックスは分割のものとは異なります: ```js import { foo as bar } from 'myFile.js'; // foo is imported and injected into a new bar variable ``` ##### デフォルトインポート / エクスポート デフォルトエクスポートに関しては、モジュールごとにひとつだけデフォルトエクスポートがあります。 デフォルトエクスポートは、関数、クラス、オブジェクトその他どんなものにもすることができます。 デフォルトエクスポートはインポートするときの最もシンプルな形なので、その値は「メイン」のエクスポート値とみなされます。 ([参考: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Description)) ```js // coolNumber.js const ultimateNumber = 42; export default ultimateNumber; // ------------ // myFile.js import number from './coolNumber.js'; // Default export, independently from its name, is automatically injected into number variable; console.log(number) // 42 ``` 関数のエクスポート: ```js // sum.js export default function sum(x, y) { return x + y; } // ------------- // myFile.js import sum from './sum.js'; const result = sum(1, 2); console.log(result) // 3 ``` #### 外部のリソース - [ES6 Modules in bulletpoints](https://ponyfoo.com/articles/es6#modules) - [Export - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) - [Import - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) - [Understanding ES6 Modules](https://www.sitepoint.com/understanding-es6-modules/) - [Destructuring special case - import statements](https://ponyfoo.com/articles/es6-destructuring-in-depth#special-case-import-statements) - [Misunderstanding ES6 Modules - Kent C. Dodds](https://medium.com/@kentcdodds/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution-ad2d5ab93ce0) - [Modules in JavaScript](http://exploringjs.com/es6/ch_modules.html#sec_modules-in-javascript) ### JavaScript の *`this`* *`this`* 演算子の振る舞いは他の言語とは異なり、ほとんどの場合、関数の呼び出し方によって決まります。 ([参考: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)) この概念にはややこしいポイントがたくさんあり非常に難しいので、以下にあげる外部のリソースを深く読むことを強くおすすめします。 そのため、ここでは *`this`* の中身が何になるかを理解するための個人的なアイデアを紹介することにします。 この考え方は [Yehuda Katz が書いた記事](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/) からのものです。 ```js function myFunc() { ... } // After each statement, you find the value of *this* in myFunc myFunc.call("myString", "hello") // "myString" -- first .call parameter value is injected into *this* // In non-strict-mode myFunc("hello") // window -- myFunc() is syntax sugar for myFunc.call(window, "hello") // In strict-mode myFunc("hello") // undefined -- myFunc() is syntax sugar for myFunc.call(undefined, "hello") ``` ```js var person = { myFunc: function() { ... } } person.myFunc.call(person, "test") // person Object -- first call parameter is injected into *this* person.myFunc("test") // person Object -- person.myFunc() is syntax sugar for person.myFunc.call(person, "test") var myBoundFunc = person.myFunc.bind("hello") // Creates a new function in which we inject "hello" in *this* value person.myFunc("test") // person Object -- The bind method has no effect on the original method myBoundFunc("test") // "hello" -- myBoundFunc is person.myFunc with "hello" bound to *this* ``` #### 外部のリソース - [Understanding JavaScript Function Invocation and "this" - Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/) - [JavaScript this - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) ### クラス JavaScript は [プロトタイプベース](https://en.wikipedia.org/wiki/Prototype-based_programming) の言語です(例えば、 Java は [クラスベース](https://en.wikipedia.org/wiki/Class-based_programming) の言語です)。 ES6 は、プロトタイプベースの継承に対するシンタックスシュガー(訳注: 原文では「 syntactic sugar 」です)としての JavaScript のクラスを導入しました。 これは新しいクラスベースの継承モデルでは **ありません** 。 もしあなたが他の言語のクラスに馴れていれば、 *クラス* ということばは混乱を招く可能性があります。 もし他の言語のクラスに馴れているなら、 JavaScript のクラスも同じようなものだと考えたりはせず、まったく別物の概念だと考えましょう。 このドキュメントは JavaScript についてゼロから教えようとするものではないため、読者は、プロトタイプが何であって、どのように振る舞うかを知っているものとします。 もしプロトタイプについてよく知らなければ、次のサンプルコードの下に記載された外部のリソースをご覧ください。 #### サンプルコード ES6 以前のプロトタイプ構文: ```js var Person = function(name, age) { this.name = name; this.age = age; } Person.prototype.stringSentence = function() { return "Hello, my name is " + this.name + " and I'm " + this.age; } ``` ES6 のクラス構文: ```js class Person { constructor(name, age) { this.name = name; this.age = age; } stringSentence() { return "Hello, my name is " + this.name + " and I'm " + this.age; } } const myPerson = new Person("Manu", 23); console.log(myPerson.age) // 23 console.log(myPerson.stringSentence()) // "Hello, my name is Manu and I'm 23 ``` #### 外部のリソース プロトタイプの理解のためのリソース: - [Understanding Prototypes in JS - Yehuda Katz](http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/) - [A plain English guide to JS prototypes - Sebastian Porto](http://sporto.github.io/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/) - [Inheritance and the prototype chain - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) クラスの理解のためのリソース: - [ES6 Classes in Depth - Nicolas Bevacqua](https://ponyfoo.com/articles/es6-classes-in-depth) - [ES6 Features - Classes](http://es6-features.org/#ClassDefinition) - [JavaScript Classes - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) ### `extends` キーワードと `super` キーワード `extends` キーワードは、他のクラスの子どもとなるクラスを作成するために、クラス宣言あるいはクラス式に使われます([参考: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends))。 サブクラスはスーパークラスのすべてのプロパティを継承し、追加で新しいプロパティを追加したり継承したプロパティを変更したりすることができます。 `super` キーワードはオブジェクトの親の関数を呼び出すために使用します。 これにはコンストラクターも含まれます。 - コンストラクターの中では、 `super` キーワードは `this` キーワードが使われる前に使わなくてはなりません。 - `super()` を呼び出すと親クラスのコンストラクターが呼ばれます。クラスのコンストラクターに引数を渡したいときは、 `super(arguments)` という形で呼び出します。 - 親クラスが `X` というメソッドを持つ場合は(スタティックメソッドでもよい)、子クラスの中で `super.X()` とすればそれを呼び出すことができます。 #### サンプルコード ```js class Polygon { constructor(height, width) { this.name = 'Polygon'; this.height = height; this.width = width; } getHelloPhrase() { return `Hi, I am a ${this.name}`; } } class Square extends Polygon { constructor(length) { // Here, it calls the parent class' constructor with lengths // provided for the Polygon's width and height super(length, length); // Note: In derived classes, super() must be called before you // can use 'this'. Leaving this out will cause a reference error. this.name = 'Square'; this.length = length; } getCustomHelloPhrase() { const polygonPhrase = super.getHelloPhrase(); // accessing parent method with super.X() syntax return `${polygonPhrase} with a length of ${this.length}`; } get area() { return this.height * this.width; } } const mySquare = new Square(10); console.log(mySquare.area) // 100 console.log(mySquare.getHelloPhrase()) // 'Hi, I am a Square' -- Square inherits from Polygon and has access to its methods console.log(mySquare.getCustomHelloPhrase()) // 'Hi, I am a Square with a length of 10' ``` **メモ:** `Square` クラスの中で `super()` を呼ぶ前に `this` を使おうとすると、 `ReferenceError` が発生します: ```js class Square extends Polygon { constructor(length) { this.height; // ReferenceError, super needs to be called first! // Here, it calls the parent class' constructor with lengths // provided for the Polygon's width and height super(length, length); // Note: In derived classes, super() must be called before you // can use 'this'. Leaving this out will cause a reference error. this.name = 'Square'; } } ``` #### 外部のリソース - [Extends - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) - [Super operator - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) - [Inheritance - MDN](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance) ### Async Await [プロミス](#promises) に加えて、 *`async`* / *`await`* という非同期なコードを扱うための新しい構文を見ることがあるかもしれません。 `async` / `await` 関数の目的は、プロミスを同期的に利用する振る舞いをシンプルにすることです。 そして、プロミスのグループを扱うことです。 プロミスが構造化されたコールバックに似ているのと同じように、 `async` / `await` もジェネレーターとプロミスの組み合わせに似ています。 `async` 関数は *常に* プロミスを返します。 ([参考: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)) > **メモ:** `async` / `await` はプロミスをベースにしているため、 `async` / `await` を理解しようとする前に、プロミスがどんなもので、どのように動作するのかを理解する必要があります。 > **メモ 2:** [*`await`* は *`async`* 関数の中で使わなくてはなりません](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9#f3f0) 。これは、 `await` はコードのトップレベルでは使えない(コードのトップレベルは `async` 関数の中に入っていないので)、という意味です。 #### サンプルコード ```js async function getGithubUser(username) { // async keyword allows usage of await in the function and means function returns a promise const response = await fetch(`https://api.github.com/users/${username}`); // Execution is paused here until the Promise returned by fetch is resolved return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) // logging user response - cannot use await syntax since this code isn't in async function .catch(err => console.log(err)); // if an error is thrown in our async function, we will catch it here ``` #### サンプルコード付きの説明 *`async`* / *`await`* はプロミスの上に構築されていますが、これらを使うとより命令型のスタイルでコードを書くことができます。 *`async`* 演算子は関数に非同期のマークを付けて、常に *プロミス* を返す形にします。 *`async`* 関数の中で *`await`* 演算子を使うことで、その式の戻り値のプロミスがリゾルブかリジェクトのどちらかをするまで(原文では「 until the returned Promise from the expression either resolves or rejects 」です)その行で処理を一時停止することができます。 ```js async function myFunc() { // we can use await operator because this function is async return "hello world"; } myFunc().then(msg => console.log(msg)) // "hello world" -- myFunc's return value is turned into a promise because of async operator ``` `async` 関数の *`return`* 文に到達したときに、プロミスは戻り値を持ってフルフィルされます(訳注: 原文では「 is fullfilled with the value returned 」)。 `async` 関数の中でエラーが発生したら、プロミスのステートは *リジェクテッド* に変わります。 `async` 関数に戻り値が無い場合も、 `async` 関数の実行が完了したときにはプロミスが返され、値を持たずにリゾルブが発生します。 *`await`* 演算子は *プロミス* がフルフィルドになるのを待つために使用するものであり、 *`async`* 関数のボディの中でのみ使用することができます。 処理が *`await`* のところに来たら、プロミスがフルフィルされるまで処理が一時停止されます。 > **メモ:** *`fetch`* は Ajax リクエストができるプロミスを返す関数です。 まず、プロミスを使うと GitHub ユーザー情報の取得がどのようにできたかを見てみましょう: ```js function getGithubUser(username) { return fetch(`https://api.github.com/users/${username}`).then(response => response.json()); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` *`async`* / *`await`* で同じことをすると次のようになります: ```js async function getGithubUser(username) { // promise + await keyword usage allowed const response = await fetch(`https://api.github.com/users/${username}`); // Execution stops here until fetch promise is fulfilled return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` *`async`* / *`await`* 構文は依存関係のある複数のプロミスをチェインするときに特に便利です。 例えば、データベースにあるブログ投稿と作成者情報をフェッチするためのトークンを取得する必要がある場合は次のようになります: > **メモ:** リゾルブされた値のメソッドやプロパティを同一行で利用する場合、 *`await`* 式はかっこで囲う必要があります。 ```js async function fetchPostById(postId) { const token = (await fetch('token_url')).json().token; const post = (await fetch(`/posts/${postId}?token=${token}`)).json(); const author = (await fetch(`/users/${post.authorId}`)).json(); post.author = author; return post; } fetchPostById('gzIrzeo64') .then(post => console.log(post)) .catch(err => console.log(err)); ``` ##### エラーハンドリング *`await`* 式の周りに *`try`* / *`catch`* のブロックを追加しておかないと、キャッチされない例外がーー *`async`* 関数のボディの中で投げられたかどうかにかかわらず、また、 *`await`* でサスペンドされていても ーー *`async`* 関数が返したプロミスをリジェクトします。 `async` 関数の中で `throw` 文を使うことは、リジェクトするプロミスを返すことと同じ意味です。 ([(参考: PonyFoo)](https://ponyfoo.com/articles/understanding-javascript-async-await#error-handling)) > **メモ:** プロミスは同じように振る舞います! プロミスを使った場合、エラーチェインの処理は次のようにしていました: ```js function getUser() { // This promise will be rejected! return new Promise((res, rej) => rej("User not found !")); } function getAvatarByUsername(userId) { return getUser(userId).then(user => user.avatar); } function getUserAvatar(username) { return getAvatarByUsername(username).then(avatar => ({ username, avatar })); } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "User not found !" ``` *`async`* / *`await`* で同じことをすると次のようになります: ```js async function getUser() { // The returned promise will be rejected! throw "User not found !"; } async function getAvatarByUsername(userId) => { const user = await getUser(userId); return user.avatar; } async function getUserAvatar(username) { var avatar = await getAvatarByUsername(username); return { username, avatar }; } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "User not found !" ``` #### 外部のリソース - [Async/Await - JavaScript.Info](https://javascript.info/async-await) - [ES7 Async/Await](http://rossboucher.com/await/#/) - [6 Reasons Why JavaScript’s Async/Await Blows Promises Away](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9) - [JavaScript awaits](https://dev.to/kayis/javascript-awaits) - [Using Async Await in Express with Node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) - [Async Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) - [Await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) - [Using async / await in express with node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) ### True になるもの / False になるもの JavaScript では、 `true` になる値と `false` になる値は、真偽判定のコンテキストで評価されたとき(訳注: 原文では「 when evaluated in a boolean context 」です)に真偽値にキャストされます。 真偽判定のコンテキストの例は、 ```if``` 条件での判定です。 次の値に等しくない値はすべて ```true``` にキャストされます: - ```false``` - ```0``` - ```""``` (空文字列) - ```null``` - ```undefined``` - ```NaN``` *真偽判定のコンテキスト* の例は次のとおりです: - ```if``` 条件評価 ```js if (myVar) {} ``` ```myVar``` にはどんな[第一級市民](https://en.wikipedia.org/wiki/First-class_citizen)(変数、関数、真偽値)を置くこともできますが、真偽判定のコンテキストで評価されているため真偽値にキャストされます。 - 論理 **否定** 演算子 ```!``` の後 この演算子はそのオペランドが `true` に変換できる場合は `false` を返します。 逆の場合は `true` を返します。 ```js !0 // true -- 0 is falsy so it returns true !!0 // false -- 0 is falsy so !0 returns true so !(!0) returns false !!"" // false -- empty string is falsy so NOT (NOT false) equals false ``` - *真偽値* オブジェクトコンストラクターでの使用 ```js new Boolean(0) // false new Boolean(1) // true ``` - 三項演算子の評価部分(訳注: 原文では「 In a ternary evaluation 」です) ```js myVar ? "truthy" : "falsy" ``` `myVar` は真偽判定コンテキストで評価されます。 2 つの値の比較には注意が必要です。 (最終的に真偽値にキャストされる)比較対象のオブジェクトの値は、真偽値にキャストされるのでは **なく** 、 [プリミティブへの変換仕様](http://javascript.info/object-toprimitive) に基いて、プリミティブ値に変換されます。 内部的には、 `[] == true` のようにオブジェクトが真偽値と比較された場合、 `[].toString() == true` という比較が行われます。 ```js let a = [] == true // a is false since [].toString() give "" back. let b = [1] == true // b is true since [1].toString() give "1" back. let c = [2] == true // c is false since [2].toString() give "2" back. ``` #### 外部のリソース - [Truthy (MDN)](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) - [Falsy (MDN)](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) - [Truthy and Falsy values in JS - Josh Clanton](http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html) ### アナモルフィズム / カタモルフィズム #### アナモルフィズム アナモルフィズム(訳注: 原文では「 anamorphisms 」です)とは、あるオブジェクトを、オブジェクト型を含むより複雑な構造体にマップする関数のことです。 それは、シンプルな構造体を複雑な構造体に *アンフォールド* する(訳注: 原文では「 unfolding 」です)処理です。 整数を、整数のリストにアンフォールドする場合を考えてみましょう。 この場合、整数が最初のオブジェクトで、整数のリストがより複雑な構造体です。 **サンプルコード** ```js function downToOne(n) { const list = []; for (let i = n; i > 0; --i) { list.push(i); } return list; } downToOne(5) //=> [ 5, 4, 3, 2, 1 ] ``` #### カタモルフィズム カタモルフィズム(訳注: 原文では「 catamorphisms 」です)とは、アナモルフィズムの逆で、複雑な構造体であるオブジェクトをよりシンプルな構造体に *フォールド* する(訳注: 原文では「 fold 」です)ことです。 次の `product` のサンプルを見てください。 `product` は整数のリストを受け取り単一の整数を返します。 **サンプルコード** ```js function product(list) { let product = 1; for (const n of list) { product = product * n; } return product; } product(downToOne(5)) // 120 ``` #### 外部のリソース * [Anamorphisms in JavaScript](http://raganwald.com/2016/11/30/anamorphisms-in-javascript.html) * [Anamorphism](https://en.wikipedia.org/wiki/Anamorphism) * [Catamorphism](https://en.wikipedia.org/wiki/Catamorphism) ### ジェネレーター `downToOne` 関数を書く別の方法として、ジェネレーターを使ったものがあります。 `Generator` オブジェクトを生成するには、 `function *` 宣言を使わなくてはいけません。 ジェネレーターは、一度脱出した後に、コンテキスト(変数バインディング)を保った形で再突入できる関数です(訳注: 原文では「 Generators are functions that can be exited and later re-entered with its context (variable bindings) saved across re-entrances 」です)。 例えば、上の `downToOne` 関数は次のように書き直すことができます: ```js function * downToOne(n) { for (let i = n; i > 0; --i) { yield i; } } [...downToOne(5)] //[ 5, 4, 3, 2, 1 ] ``` ジェネレーターはイテラブルオブジェクトを返します。 イテレーターの `next()` 関数が呼ばれると、最初の `yield` 式までが実行されます。 `yield` 式はイテレーターから返すべき値を指定します。 `yield*` を使えば、その処理が別のジェネレーター関数に委譲されます。 ジェネレーター式の中で `return` 式が呼ばれると、それはジェネレーターに完了済みという印を付けて、戻り値として返します。 さらに `next()` を呼び出しても新しい値が返されることはありません。 **サンプルコード** ```js // Yield Example function * idMaker() { var index = 0; while (index < 2) { yield index; index = index + 1; } } var gen = idMaker(); gen.next().value; // 0 gen.next().value; // 1 gen.next().value; // undefined ``` `yield*` 式を使えば、ジェネレーターの繰り返しの中で別のジェネレーターを呼び出すことができます。 ```js // Yield * Example function * genB(i) { yield i + 1; yield i + 2; yield i + 3; } function * genA(i) { yield i; yield* genB(i); yield i + 10; } var gen = genA(10); gen.next().value; // 10 gen.next().value; // 11 gen.next().value; // 12 gen.next().value; // 13 gen.next().value; // 20 ``` ```js // Generator Return Example function* yieldAndReturn() { yield "Y"; return "R"; yield "unreachable"; } var gen = yieldAndReturn() gen.next(); // { value: "Y", done: false } gen.next(); // { value: "R", done: true } gen.next(); // { value: undefined, done: true } ``` #### 外部のリソース * [Mozilla MDN Web Docs, Iterators and Generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Generators) ### スタティックメソッド #### 短い説明 `static` キーワードは、スタティックメソッドを宣言するためにクラスの中で使用します。 スタティックメソッドはクラスの中の関数であり、クラスオブジェクトに所属します。 そのクラスのインスタンスからは利用することができません。 #### サンプルコード ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } } //Note that we did not have to create an instance of the Repo class console.log(Repo.getName()) //Repo name is modern-js-cheatsheet let r = new Repo(); console.log(r.getName()) //Uncaught TypeError: repo.getName is not a function ``` #### 詳細な説明 スタティックメソッドは、 `this` キーワードを使えば別のスタティックメソッドの中から呼ぶことができます。 しかし、スタティックではないメソッド(訳注: 原文では「 non-static methods 」です)の場合はこれはできません。 スタティックでないメソッドが `this` キーワードを使ってスタティックメソッドに直接アクセスすることはできません。 ##### スタティックメソッドから別のスタティックメソッドを呼ぶ スタティックメソッドを別のスタティックメソッドから呼び出すには、次のように `this` キーワードを使うことができます: ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } static modifyName(){ return this.getName() + '-added-this' } } console.log(Repo.modifyName()) //Repo name is modern-js-cheatsheet-added-this ``` ##### スタティックでないメソッドからスタティックメソッドを呼ぶ スタティックでないメソッドからはスタティックメソッドを呼ぶ方法が 2 つあります: Non-static methods can call static methods in 2 ways; 1. クラス名を使う スタティックでないメソッドからスタティックメソッドにアクセスするには、クラス名を使って、プロパティのような形でスタティックメソッドを呼び出します。 例: `ClassName.StaticMethodName` ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ return Repo.getName() + ' and it contains some really important stuff' } } // we need to instantiate the class to use non-static methods let r = new Repo() console.log(r.useName()) //Repo name is modern-js-cheatsheet and it contains some really important stuff ``` 2. コンストラクターを使う スタティックメソッドは `constructor` オブジェクトのプロパティとして呼ぶことができます。 ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ //Calls the static method as a property of the constructor return this.constructor.getName() + ' and it contains some really important stuff' } } // we need to instantiate the class to use non-static methods let r = new Repo() console.log(r.useName()) //Repo name is modern-js-cheatsheet and it contains some really important stuff ``` #### 外部のリソース - [static keyword- MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) - [Static Methods- Javascript.info](https://javascript.info/class#static-methods) - [Static Members in ES6- OdeToCode](http://odetocode.com/blogs/scott/archive/2015/02/02/static-members-in-es6.aspx) ## 用語集 ### スコープ 値と式が「見え」て、参照可能な場合なコンテキストのこと。 変数やその他の式が「カレントスコープ」に無い場合は、それらは利用することができません。 ソース: [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Scope) ### 変数ミューテーション 初期値が後から変更されたとき、その変数はミューテートされた(訳注: 原文では「 have been mutated 」です)と言います。 ```js var myArray = []; myArray.push("firstEl") // myArray is being mutated ``` もしある変数がミューテートできなければ、その変数は *イミュータブル* である(訳注: 原文では「 immutable 」です)と言います。 詳しくは、 [MDN の Mutable の記事](https://developer.mozilla.org/en-US/docs/Glossary/Mutable) をご覧ください。 ================================================ FILE: JavaScript/translations/pl_PL.md ================================================ # Współczesny JavaScript - ściągawka ![Modern JavaScript cheatsheet](https://i.imgur.com/aexPxMb.png) Image Credits: [Ahmad Awais ⚡️](https://github.com/ahmadawais) ## Wstęp ### Motywacja W tym dokumencie zebrane zostały elementy języka JavaScript, z którymi często można się spotkać we współczesnych projektach i najnowszych przykładach kodu. Celem tego przewodnika nie jest nauka JavaScriptu od zera, ale pomoc posiadającym podstawową wiedzę developerom, którzy pracując ze współczesnymi bazami kodu (powiedzmy, ucząc się React) napotykają trudności, wynikające z użytych tam konceptów języka JavaScript. Prócz tego, od czasu do czasu będę zamieszczał własne porady, z którymi niekoniecznie trzeba się zgadzać, ale postaram się za każdym razem podkreślać, że chodzi tylko o moja opinię. > **Uwaga:** Większość omawianych tu pojęć pochodzi z nowej wersji języka JavaScript (ES2015, często nazywanego ES6). Bardzo dobre omówienie nowych możliwości wprowadzonych w tej wersji można znaleźć [tutaj](http://es6-features.org). ### Materiały uzupełniające Jeśli masz problem ze zrozumieniem jakiegoś pojęcia, proponuję poszukać odpowiedzi w poniższych źródłach: - [MDN (Mozilla Developer Network)](https://developer.mozilla.org/en-US/search?q=) - [You don't know JS (book)](https://github.com/getify/You-Dont-Know-JS) - [ES6 Features with examples](http://es6-features.org) - [WesBos blog (ES6)](http://wesbos.com/category/es6/) - [Javascript Basics for Beginners](https://www.udacity.com/course/javascript-basics--ud804) - bezpłatny kurs od Udacity - [Reddit (JavaScript)](https://www.reddit.com/r/javascript/) - [Google](https://www.google.com/) - dla znalezienia specjalistycznych blogów i innych źródeł - [StackOverflow](https://stackoverflow.com/questions/tagged/javascript) ## Spis treści - [Współczesny JavaScript - ściągawka](#modern-javascript-cheatsheet) * [Wstęp](#introduction) + [Motywacja](#motivation) + [Materiały uzupełniające](#complementary-resources) * [Spis treści](#table-of-contents) * [Pojęcia](#notions) + [Deklaracja zmiennych: var, const, let](#variable-declaration-var-const-let) - [Krótkie wyjaśnienie](#short-explanation) - [Przykładowy kod](#sample-code) - [Szczegółowe wyjaśnienie](#detailed-explanation) - [Dodatkowe źródła](#external-resource) + [Funkcje strzałkowe (arrow functions)](#-arrow-function) - [Przykładowy kod](#sample-code-1) - [Szczegółowe wyjaśnienie](#detailed-explanation-1) * [Zwięzłość](#concision) * [Użycie *this*](#this-reference) - [Pomocne źródła](#useful-resources) + [Domyślna wartość argumentów funkcji](#function-default-parameter-value) - [Dodatkowe źródła](#external-resource-1) + [Destrukturyzacja obiektów i tablic](#destructuring-objects-and-arrays) - [Wyjaśnienie z przykładowym kodem](#explanation-with-sample-code) - [Pomocne źródła](#useful-resources-1) + [Metody tablicowe - map / filter / reduce](#array-methods---map--filter--reduce) - [Przykładowy kod](#sample-code-2) - [Wyjaśnienie](#explanation) * [Array.prototype.map()](#arrayprototypemap) * [Array.prototype.filter()](#arrayprototypefilter) * [Array.prototype.reduce()](#arrayprototypereduce) - [Dodatkowe źródła](#external-resource-2) + [Operator rozwijania "..."](#spread-operator-) - [Przykładowy kod](#sample-code-3) - [Wyjaśnienie](#explanation-1) * [W obiektach iterowalnych (np. w tablicach)](#in-iterables-like-arrays) * [Parametry rest](#function-rest-parameter) * [Rozwijanie własności obiektów](#object-properties-spreading) - [Dodatkowe źródła](#external-resources) + [Skrócony zapis własności obiektów](#object-property-shorthand) - [Wyjaśnienie](#explanation-2) - [Dodatkowe źródła](#external-resources-1) + [Obietnice (promises)](#promises) - [Przykładowy kod](#sample-code-4) - [Wyjaśnienie](#explanation-3) * [Tworzenie obietnicy (promise)](#create-the-promise) * [Użycie procedur obsługi](#promise-handlers-usage) - [Dodatkowe źródła](#external-resources-2) + [Łańcuchy szablonowe (template literals)](#template-literals) - [Przykładowy kod](#sample-code-5) - [Dodatkowe źródła](#external-resources-3) + [Oznaczone łańcuchy szablonowe (tagged template literals)](#tagged-template-literals) - [Dodatkowe źródła](#external-resources-4) + [Importy / eksporty](#imports--exports) - [Wyjaśnienie z przykładowym kodem](#explanation-with-sample-code-1) * [Nazwane eksporty (named exports)](#named-exports) * [Domyślny import / eksport](#default-import--export) - [Dodatkowe źródła](#external-resources-5) + [*this* w JavaScript](#-javascript-this) - [Dodatkowe źródła](#external-resources-6) + [Klasa](#class)` - [Przykłady](#samples) - [Dodatkowe źródła](#external-resources-7) + [Słowa kluczowe extends i super](#extends-and-super-keywords) - [Przykładowy kod](#sample-code-6) - [Dodatkowe źródła](#external-resources-8) + [Składnia async/await](#async-await) - [Przykładowy kod](#sample-code-7) - [Wyjaśnienie z przykładowym kodem](#explanation-with-sample-code-2) - [Obsługa błędów](#error-handling) - [Dodatkowe źródła](#external-resources-9) + [Prawda / Fałsz](#truthy--falsy) - [Dodatkowe źródła](#external-resources-10) + [Anamorfizmy i Katamorfizmy](#anamorphisms-and-catamorphisms) - [Anamorfizmy](#anamorphisms) - [Katamorfizmy](#catamorphisms) - [Dodatkowe źródła](#external-resources-11) + [Generatory](#generators) - [Dodatkowe źródła](#external-resources-12) + [Metody statyczne](#static-methods) - [Krótkie wyjaśnienie](#short-explanation-1) - [Przykładowy kod](#sample-code-8) - [Szczegółowe wyjaśnienie](#detailed-explanation-2) * [Wzywanie innych metod statycznych z metody statycznej](#calling-other-static-methods-from-a-static-method) * [Wzywanie metod statycznych z metod niestatycznych](#calling-static-methods-from-non-static-methods) - [Dodatkowe źródła](#external-resources-13) * [Słowniczek](#glossary) + [Zakres widoczności (scope)](#-scope) + [Przekształcenie zmiennej (variable mutation)](#-variable-mutation) ## Pojęcia ### Deklaracja zmiennych: var, const, let W języku JavaScript mamy do dyspozycji trzy słowa kluczowe, za pomocą których deklarowane są zmienne. Są to ```var```, ```let``` and ```const```. #### Krótkie wyjaśnienie Zmienne deklarowane z użyciem ```const``` nie moga być ponownie przypisane, natomiast ```let``` i ```var``` mogą. Radziłbym zawsze deklarować zmienne za pomocą ```const```, a ```let``` stosować, kiedy zamierzamy *przekształcać* zmienne bądź przypisywać im inną wartość.
Zakres widoczności Można nadpisać Można zmienić Czasowo martwa strefa
const Blok Nie Tak Tak
let Blok Tak Tak Tak
var Funkcja Tak Tak Nie
#### Przykładowy kod ```javascript const person = "Nick"; person = "John" // Wywoła błąd, person nie może być przepisane ``` ```javascript let person = "Nick"; person = "John"; console.log(person) // "John", przepisanie jest dozwolone z let ``` #### Szczegółowe wyjaśnienie [*Zakres widoczności*] zmiennej oznacza mniej więcej "to, gdzie zmienna jest dostępna w kodzie". ##### var Zakresem widoczności zmiennych deklarowanych za pomocą ```var``` jest funkcja. Oznacza to, że jeśli zmienna była stworzona wewnątrz funkcji, to wszystko w ciele tej funkcji ma dostęp do danej zmiennej. Poza tym, zmienna o opisanym zakresie nie jest dostępna poza funkcją. Można myśleć o tym następująco: jeśli zakres widoczności zmiennej to *X*, to zmienna ta stanowi jak gdyby własność X. ```javascript function myFunction() { var myVar = "Nick"; console.log(myVar); // "Nick" - myVar dostępna wewnątrz funkcji. } console.log(myVar); // ReferenceError, myVar nie jest dostępna poza funkcją. ``` A oto mniej oczywisty przykład: ```javascript function myFunction() { var myVar = "Nick"; if (true) { var myVar = "John"; console.log(myVar); // "John" // ponieważ zakresem myVar jest funkcja, zastępujemy wcześniejszą wartość "Nick" wartością "John" } console.log(myVar); // "John" - zwróć uwagę, jak instrukcje w bloku if wpłynęły na wartość } console.log(myVar); // ReferenceError, myVar nie jest dostępna poza funkcją. ``` Poza tym, zmienne zadeklarowane poprzez *var* przy wykonaniu kodu przemieszczają się na początek zakresu widoczności. Proces ten nazywamy [var hoisting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting). Ten fragment kodu: ```js console.log(myVar) // undefined -- brak błędu var myVar = 2; ``` w momencie wykonania rozumiany jest tak: ```js var myVar; console.log(myVar) // undefined -- brak błędu myVar = 2; ``` ##### let ```var``` i ```let ``` znaczą mniej więcej to samo, ale w przypadku zmiennych zadeklarowanych za pomocą ```let``` - zakres widoczności stanowi blok - są **niedostępne** przed przypisaniem - nie mogą być ponownie zadeklarowane w tym samym zakresie widoczności Przyjrzyjmy się blokowemu zakresu widoczności, używając poprzedniego przykładu: ```javascript function myFunction() { let myVar = "Nick"; if (true) { let myVar = "John"; console.log(myVar); // "John" // ponieważ zakresem widoczności myVar jest blok, // właśnie stworzyliśmy nową zmienną myVar. // zmienna ta jest niedostępna poza blokiem i zupełnie // niezależna od pierwszej zmiennej myVar. } console.log(myVar); // "Nick", instrukcje bloku if NIE wpłynęły na tę zmienną } console.log(myVar); // ReferenceError, myVar nie jest dostępna poza funkcją. ``` A teraz rozpatrzmy, co oznacza, że zmienne zadeklarowane z *let* (i *const*) są niedostępne przed przypisaniem: ```js console.log(myVar) // wywołuje ReferenceError ! let myVar = 2; ``` W odróżnieniu od zmiennych zadeklarowanych poprzez *var*, próba odczytu bądź nadpisania zmiennej stworzonej za pomocą *let* lub *const* przed przypisaniem wywoła błąd. Zjawisko to nazywane jest często [*Czasowo martwą strefą*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let) albo *TDZ* > **Uwaga:** Ściśle rzecz biorąc zmienne zadeklarowane przy pomocy *let* i *const* też są windowane, ale nie przypisywane. Ponieważ nie mogą one być użyte przed przypisaniem, może się wydawać, że nie dochodzi do windowania (hoistingu), co nie jest prawdą. Jeśli chcesz dowiedzieć się więcej, możesz zapoznać się z [dokładnym omówieniem tego zjawiska](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified). Ponadto nie można ponownie zadeklarować zmiennej stworzonej z *let* ```js let myVar = 2; let myVar = 3; // SyntaxError ``` ##### const Zmienne zadeklarowane poprzez słowo kluczowe ```const``` zachowują się, jak te zadeklarowane z *let*, ale nie mogą być ponownie przypisane. Podsumowując, zmienne stworzone z *const*: - ich zakresem widoczności jest blok - nie są dostępne przed przypisaniem - nie mogą być ponownie zadeklarowane w tym samym zakresie widoczności - nie mogą być ponownie przypisane ```js const myVar = "Nick"; myVar = "John" // wywołuje błąd, ponowne przypisanie jest niedozwolone ``` ```js const myVar = "Nick"; const myVar = "John" // wywołuje błąd, ponowna deklaracja jest niedozwolone ``` Jest jednak pewien szczegół : zmienne zadeklarowane z ```const``` nie są [**niezmienne**](#mutation_def) ! Konkretnie, oznacza to, że *objekty* i *tablice* zadeklarowane poprzez ```const``` **mogą** podlegać modyfikacjom. W przypadku obiektów: ```js const person = { name: 'Nick' }; person.name = 'John' // działa! Zmienna person nie jest ponownie przypisywana, ale ulega zmianie. console.log(person.name) // "John" person = "Sandra" // wywoła błąd, ponieważ nie można nadpisywać zmiennych deklarowanych poprzez const ``` W przypadku tablic: ```js const person = []; person.push('John'); // działa! Zmienna person nie jest ponownie przypisywana, ale ulega zmianie. console.log(person[0]) // "John" person = ["Nick"] // wywoła błąd, ponieważ nie można nadpisywać zmiennych deklarowanych poprzez const ``` #### Dodatkowe źródła - [How let and const are scoped in JavaScript - WesBos](http://wesbos.com/javascript-scoping/) - [Temporal Dead Zone (TDZ) Demystified](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) ### Funkcje strzałkowe (arrow functions) W wersji ES6 JavaScript wprowadzone zostały *funkcje strzałkowe* (*arrow functions*) - nowy sposób zapisu funkcji. Oto niektóre jego zalety: - większa zwięzłość - *this* pobierane jest z otaczającego kontekstu - niejawny zwrot (implicit return) #### Przykładowy kod - Zwięzłość i niejawny zwrot ```js function double(x) { return x * 2; } // Tradycyjny sposób console.log(double(2)) // 4 ``` ```js const double = x => x * 2; // Ta sama funkcja jako funkcja strzałkowa z niejawnym zwrotem console.log(double(2)) // 4 ``` - Użycie *this* W funkcji strzałkowej *this* jest równe wartości *this* w otaczającym zakresie widoczności. Zasadniczo, dzięki funkcjom strzałkowym, nie ma już potrzeby używania tricku "that = this" przed wywołaniem funkcji wewnątrz funkcji. ```js function myFunc() { this.myVar = 0; setTimeout(() => { this.myVar++; console.log(this.myVar) // 1 }, 0); } ``` #### Szczegółowe wyjaśnienie ##### Zwięzłość Funkcje strzałkowe są w wielu aspektach bardziej zwięzłe niż tradycyjne funkcje. Rozpatrzmy kilka przypadków: - Jawny vs niejawny zwrot **Jawny zwrot** (**explicit return**) to funkcja, w której ciele użyte jest słowo kluczowe *return*. ```js function double(x) { return x * 2; // this function explicitly returns x * 2, *return* keyword is used } ``` Przy tradycyjnym sposobie pisania funkcji zwrot był zawsze jawny. Jednak arrow functions pozwalają na *niejawny zwrot*, czyli taki, w którym słowo kluczowe *return* nie jest konieczne przy zwrocie wartości. ```js const double = (x) => { return x * 2; // Jawny zwrot } ``` Ponieważ funkcja ta ogranicza się do zwrotu pewnej wartości (poza tym brak innych instrukcji), możemy użyć niejawnego zwrotu. ```js const double = (x) => x * 2; // Correct, returns x*2 ``` By to zrobić, musimy ***usunąć nawiasy* i słowo **return**. Stąd też nazwa *niejawny* (implicit) zwrot - mimo braku słowa kluczowego **return**, funkcja i tak zwróci ```x * 2```. > **Uwaga:** Jeśli funkcja nie zwraca żadnej wartości (z *efektami ubocznymi*), nie ma w niej ani jawnego ani niejawnego zwrotu. Poza tym, jeśli chcemy niejawnie zwrócić *obiekt*, należy **otoczyć go okrągłymi nawiasami**, by nie dopuścić do konfliktu z nawiasami samego bloku. ```js const getPerson = () => ({ name: "Nick", age: 24 }) console.log(getPerson()) // { name: "Nick", age: 24 } -- obiekt niejawnie zwracany przez arrow function ``` - Tylko jeden argument Jeśli funkcja posiada tylko jeden argument, możemy ominąć nawiasy wokół niego. Przyjrzyjmy się ponownie funkcji *double* z poprzedniego kodu: ```js const double = (x) => x * 2; // arrow function ma jeden argument ``` Nawiasy wokół argumentu można usunąć: ```js const double = x => x * 2; // arrow function ma jeden argument ``` - Brak argumentów Gdy funkcja nie ma argumentu, należy użyć okrągłych nawiasów, jeśli chcemy zachować poprawną składnię. ```js () => { // są nawiasy, wszystko w porządku const x = 2; return x; } ``` ```js => { // brak nawiasów, kod nie będzie działać! const x = 2; return x; } ``` ##### Użycie *this* Aby w pełni zrozumieć działanie funkcji strzałkowych, trzeba wiedzieć, jak w JavaScript zachowuje się [this](#this_def). W funckji strzałkowej *this* jest równe wartości *this* w otaczającym kontekście. Oznacza to, że funkcja strzałkowa nie tworzy nowego *this*, ale zamiast tego pobiera je z otoczenia. Bez funkcji strzałkowej, jeśli chcemy otrzymać dostęp do zmiennej przez *this* w funkcji znajdującej się w innej funkcji musimy użyć tricku *that = this* lub *self = this*. Na przykład, używając funkcji setTimeout w myFunc: ```js function myFunc() { this.myVar = 0; var that = this; // that = this trick setTimeout( function() { // Nowy *this* tworzony w tym zakresie widoczności that.myVar++; console.log(that.myVar) // 1 console.log(this.myVar) // undefined -- zobacz: deklaracja funkcji wyżej }, 0 ); } ``` Ale w przypadku funkcji strzałkowej, *this* pobierane jest z otoczenia: ```js function myFunc() { this.myVar = 0; setTimeout( () => { // this pobierane z otoczenia. W tym przypadku - z myFunc. this.myVar++; console.log(this.myVar) // 1 }, 0 ); } ``` #### Pomocne źródła - [Arrow functions introduction - WesBos](http://wesbos.com/arrow-functions/) - [JavaScript arrow function - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - [Arrow function and lexical *this*](https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4) ### Domyślna wartość argumentów funkcji Począwszy od wersji ES2015, możliwe jest ustawienie domyślnej wartości argumentów funkcji przy użyciu następującej składni: ```js function myFunc(x = 10) { return x; } console.log(myFunc()) // 10 -- żadna wartość nie jest podana, x otrzymuje wartość domyślną, czyli 10 console.log(myFunc(5)) // 5 -- wartość podana, więc x otrzymuje wartość 5 console.log(myFunc(undefined)) // 10 -- podana wartość undefined, więc x otrzymuje wartość domyślną, czyli 10 console.log(myFunc(null)) // null -- wartość (null) jest podana, zobacz: niżej. ``` Domyślny argument będzie użyty jedynie w dwóch sytuacjach: - żaden argument nie jest podany - jako argument podano *undefined* Innymi słowami, jeśli jako argument podamy *null*, wartość domyślna **nie zostanie użyta**. > **Note:** Przypisanie wartości domyślnej można zastować także z destrukturyzowanymi parametrami (patrz: następna sekcja) #### Dodatkowe źródła - [Default parameter value - ES6 Features](http://es6-features.org/#DefaultParameterValues) - [Default parameters - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) ### Destrukturyzacja obiektów i tablic *Destrukturyzacja* to wygodny sposób tworzenia nowych zmiennych poprzez wydobycie pewnych wartości z danych przechowywanych w obiektach i tablicach. *Destrukturyzacja* może być użyta do przypisania zmiennym rozbitych na części parametrów funkcji lub *this.props* w projektach React. #### Wyjaśnienie z przykładowym kodem - Obiekt We wszystkich przykładach używać będziemy następującego obiektu: ```js const person = { firstName: "Nick", lastName: "Anderson", age: 35, sex: "M" } ``` Bez destrukturyzacji: ```js const first = person.firstName; const age = person.age; const city = person.city || "Paris"; ``` Z destrukturyzacją, wszystko w jednej linijce: ```js const { firstName: first, age, city = "Paris" } = person; // Gotowe ! console.log(age) // 35 -- Stworzono nową zmienną równą person.age console.log(first) // "Nick" -- Stworzono nową zmienną równą person.firstName console.log(firstName) // ReferenceError -- person.firstName istnieje, ale nowo stworzona zmienna nazywa się first console.log(city) // "Paris" -- Stworzono nową zmienną city i, ponieważ person.city jest równe undefined, zmienna jest równa domyślnej wartość "Paris". ``` **Uwaga:** W ```const { age } = person;``` nawiasy po słowie *const* nie są użyte do deklaracji obiektu ani jako blok, ale jako składnia *destrukturyzacji*. - Argumenty funkcji *Destrukturyzacja* jest często używana do rozbicia parametrów funkcji na części. Bez destrukturyzacji: ```js function joinFirstLastName(person) { const firstName = person.firstName; const lastName = person.lastName; return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` Jeśli destrukturyzujemy parametr *person*, otrzymujemy znacznie bardziej zwięzłą funkcję: ```js function joinFirstLastName({ firstName, lastName }) { // tworzymy zmienne firstName i lastName z części argumentu person. return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` Destrukturyzacja jest jeszcze przyjemniejsza, gdy użyjemy [funkcji strzałkowych](#arrow_func_concept): ```js const joinFirstLastName = ({ firstName, lastName }) => firstName + '-' + lastName; joinFirstLastName(person); // "Nick-Anderson" ``` - Tablica Rozpatrzmy następującą tablicę: ```js const myArray = ["a", "b", "c"]; ``` Bez destrukturyzacji ```js const x = myArray[0]; const y = myArray[1]; ``` Z destrukturyzacją ```js const [x, y] = myArray; // Gotowe ! console.log(x) // "a" console.log(y) // "b" ``` #### Pomocne źródła - [ES6 Features - Destructuring Assignment](http://es6-features.org/#ArrayMatching) - [Destructuring Objects - WesBos](http://wesbos.com/destructuring-objects/) - [ExploringJS - Destructuring](http://exploringjs.com/es6/ch_destructuring.html) ### Metody tablicowe - map / filter / reduce *Map*, *filter* i *reduce* to metody tablicowe zapożyczone z paradygmatu [*programowania funkcyjnego*](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0). Opiszmy je krótko: - **Array.prototype.map()** przyjmuje jako argument tablicę, modyfikuje jej elementy i zwraca nową tablicę ze zmienionymi elementami. - **Array.prototype.filter()** przyjmuje jako argument tablicę, decyduje, które elementy zatrzymać a które usunąć. Zwraca tablicę z zachowanymi elementami. - **Array.prototype.reduce()** przyjmuje jako argument tablicę, wylicza z jej elementów jedną wspólną wartość, którą zwraca. Polecam używać ich jak najczęściej, zgodnie z zasadami programowania funkcyjnego, ponieważ metody tablicowe są zwięzłe, eleganckie i można je ze sobą łączyć. Wykorzystując trzy powyższe metody możemy uniknąć użycia pętli *for* i *forEach* w większości sytuacji. Kiedy następnym razem będziesz chciał skorzystać z pętli *for*, spróbuj zamiast niej użyć kompozycji *map*, *filter* i *reduce*. Z początku może to sprawiać problemy, bo wymaga przyzwyczajenia sie do nowego sposobu myślenia, ale jeśli już go przyswoisz, wszystko będzie prostsze. #### Przykładowy kod ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; const doubledNumbers = numbers.map(n => n * 2); // [0, 2, 4, 6, 8, 10, 12] const evenNumbers = numbers.filter(n => n % 2 === 0); // [0, 2, 4, 6] const sum = numbers.reduce((prev, next) => prev + next, 0); // 21 ``` Obliczmy sumę ocen wszystkich studentów z oceną powyżej 10 łącząc *map*, *filter* i *reduce*: ```js const students = [ { name: "Nick", grade: 10 }, { name: "John", grade: 15 }, { name: "Julia", grade: 19 }, { name: "Nathalie", grade: 9 }, ]; const aboveTenSum = students .map(student => student.grade) // tworzymy tablicę ocen z tablicy studentów za pomocą map .filter(grade => grade >= 10) // filtrujemy tablicę ocen, by pozostawić większe lub równe 10 .reduce((prev, next) => prev + next, 0); // sumujemy wszystkie oceny powyżej 10 console.log(aboveTenSum) // 44 -- 10 (Nick) + 15 (John) + 19 (Julia), Nathalie poniżej 10 - ignorowana ``` #### Wyjaśnienie W przykładach wykorzystywać będziemy poniższą tablicę: ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; ``` ##### Array.prototype.map() ```js const doubledNumbers = numbers.map(function(n) { return n * 2; }); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` Co tu się dzieje? Używamy *map* na tablicy *numbers*, *map* iteruje przez każdy element i używa go jako argumentu funkcji. Celem funkcji jest przeprowadzenie kalkulacji i zwrot nowej wartości, która zastąpi wartość użytą jako argument. Wydzielmy funkcję z tablicy, żeby przyjrzeć się jej bliżej: ```js const doubleN = function(n) { return n * 2; }; const doubledNumbers = numbers.map(doubleN); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` ```numbers.map(doubleN)``` tworzy ```[doubleN(0), doubleN(1), doubleN(2), doubleN(3), doubleN(4), doubleN(5), doubleN(6)]```, które są równe ```[0, 2, 4, 6, 8, 10, 12]```. . > **Uwaga:** Jeśli nie potrzebujesz zwrotu nowej tablicy i chcesz po prostu użyć pętli posiadającej efekty uboczne, możesz rozważyć użycie pętli for / forEach zamiast map. ##### Array.prototype.filter() ```js const evenNumbers = numbers.filter(function(n) { return n % 2 === 0; // true jeśli n jest parzyste, false jeśli nie jest }); console.log(evenNumbers); // [0, 2, 4, 6] ``` Używamy *filter* na tablicy *numbers*, *filter* iteruje przez każdy element i używa go jako argumentu funkcji. Celem funkcji jest zwrot zmiennej typu boolowskiego, która określi, czy daną wartość należy zachować, czy też nie. Następnie funkcja zwraca tablicę, zawierającą jedynie zachowane wartości. ##### Array.prototype.reduce() Celem metody *reduce* jest wyliczenie na podstawie tablicy pewnej pojedynczej wartości. Jakie wyliczenia przeprowadzi metoda, zależy tylko od ciebie. ```js const sum = numbers.reduce( function(acc, n) { return acc + n; }, 0 // wartość zmiennej akumulującej po pierwszej iteracji ); console.log(sum) //21 ``` Tak jak metody .map i .filter, .reduce wykorzystuje tablicę i jako pierwszy argument przyjmuje funkcję. Są jednak pewne różnice: - .reduce przyjmuje dwa argumenty Pierwszy argument to funkcja, która będzie stosowana przy każdej iteracji. Drugi argument to wartość zmiennej akumulującej (w naszym przypadku *acc*) w pierwszej iteracji (by lepiej zrozumieć, czytaj dalej). - Argumenty funkcji Funkcja używana jako pierwszy argument .reduce przyjmuje dwa argumenty. Pierwszy (w naszym przypadku *acc*) to zmienna akumulująca, drugi (*n*) - obecny element. Zmienna akumulująca równa jest wartości zwróconej przez naszą funkcję w **poprzedniej** iteracji. Na początku każdej iteracji *acc* równa jest wartości, która była przekazana jako drugi argument .reduce. ###### W pierwszej iteracji ```acc = 0``` ponieważ jako drugi element *reduce* podaliśmy 0 ```n = 0``` pierwszy element tablicy *array* Funkcja zwraca *acc* + *n* --> 0 + 0 --> 0 ###### W drugiej iteracji ```acc = 0``` ponieważ taką wartość funkcja zwróciła przy poprzedniej iteracji ```n = 1``` drugi element tablicy *array* Funkcja zwraca *acc* + *n* --> 0 + 1 --> 1 ###### W trzeciej iteracji ```acc = 1``` ponieważ taką wartość funkcja zwróciła przy poprzedniej iteracji ```n = 2``` trzeci element tablicy *array* Funkcja zwraca *acc* + *n* --> 1 + 2 --> 3 ###### W czwartej iteracji ```acc = 3``` ponieważ taką wartość funkcja zwróciła przy poprzedniej iteracji ```n = 3``` czwarty element tablicy *array* Funkcja zwraca *acc* + *n* --> 3 + 3 --> 6 ###### [...] W ostatniej iteracji ```acc = 15``` ponieważ taką wartość funkcja zwróciła przy poprzedniej iteracji ```n = 6``` ostatni element tablicy *array* Funkcja zwraca *acc* + *n* --> 15 + 6 --> 21 Ponieważ to ostatnia iteracja, **.reduce** zwraca 21. #### Dodatkowe źródła - [Understanding map / filter / reduce in JS](https://hackernoon.com/understanding-map-filter-and-reduce-in-javascript-5df1c7eee464) ### Operator rozwijania "..." Operator rozwijania ```...``` został wprowadzony z ES2015 i przeznaczony jest do "rozwijania" elementów obiektów iterowalnych (np. tablic) tam, gdzie można zmieścić kilka elementów #### Przykładowy kod ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ```js function myFunc(x, y, ...params) { console.log(x); console.log(y); console.log(params) } myFunc("a", "b", "c", "d", "e", "f") // "a" // "b" // ["c", "d", "e", "f"] ``` ```js const { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } ``` #### Wyjaśnienie ##### W obiektach iterowalnych (np. tablicach) Jeśli mamy dwie następujące tablice: ```js const arr1 = ["a", "b", "c"]; const arr2 = [arr1, "d", "e", "f"]; // [["a", "b", "c"], "d", "e", "f"] ``` Pierwszy element tablicy *arr2* jest tablicą, ponieważ *arr1* został wprowadzony do *arr2* bezpośrednio. Co jednak, jeśli chcemy, by *arr2* było tablicą liter? Możemy rozwinąć (*spread*) elementy *arr1* w tablicy *arr2*. Z operatorem rozwijania ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ##### Parametry rest Operator rest pozwala przedstawić dowolna liczbę argumentów w postaci tablicy, po elementach której można iterować. Istnieje już obiekt **arguments** związany z każdą funkcją i równy tablicy wszystkich argumentów przekazanych do danej funkcji. ```js function myFunc() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } myFunc("Nick", "Anderson", 10, 12, 6); // "Nick" // "Anderson" // 10 // 12 // 6 ``` Wyobraźmy sobie teraz, że chcemy, żeby nasza funkcja tworzyła nowego ucznia z ocenami i średnią. Czy nie byłoby wygodniej zapisać dwa pierwsze argumenty jako dwie oddzielne zmienne, a wszystkie oceny umieścić w iterowalnej tablicy? Właśnie na to pozwala nam operator rest! ```js function createStudent(firstName, lastName, ...grades) { // firstName = "Nick" // lastName = "Anderson" // [10, 12, 6] -- "..." bierze wszystkie pozostałe argumenty przekazane funkcji i tworzy zmienną "grades" z przechowującą je tablicą const avgGrade = grades.reduce((acc, curr) => acc + curr, 0) / grades.length; // oblicza średnią z ocen return { firstName: firstName, lastName: lastName, grades: grades, avgGrade: avgGrade } } const student = createStudent("Nick", "Anderson", 10, 12, 6); console.log(student); // { // firstName: "Nick", // lastName: "Anderson", // grades: [10, 12, 6], // avgGrade: 9,33 // } ``` > **Uwaga:** funkcja createStudent jest zła, bo nie sprawdzamy, czy grades.length istnieje i czy jest różna od zera. Nie ująłem tej sytuacji w kodzie, żeby funkcja była bardziej czytelna. ##### Rozwijanie własności obiektów Aby zrozumieć tę część, polecam najpierw przeczytać poprzednie sekcje dotyczące użycia operatora rest na iterowalnych obiektach i parametrach funkcji. ```js const myObj = { x: 1, y: 2, a: 3, b: 4 }; const { x, y, ...z } = myObj; // destrukturyzacja obiektu console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } // z to reszta destrukturyzowanego obiektu: myObj object minus destrukturyzowane własności x i y const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } // Własności obiektu z są rozwinięte w n ``` #### Dodatkowe źródła - [TC39 - Object rest/spread](https://github.com/tc39/proposal-object-rest-spread) - [Spread operator introduction - WesBos](https://github.com/wesbos/es6-articles/blob/master/28%20-%20Spread%20Operator%20Introduction.md) - [JavaScript & the spread operator](https://codeburst.io/javascript-the-spread-operator-a867a71668ca) - [6 Great uses of the spread operator](https://davidwalsh.name/spread-operator) ### Skrócony zapis własności obiektów Kiedy przypisujemy zmienną do własności obiektu, jeśli nazwa zmiennej jest taka sama, jak nazwa własności, możemy zrobić coś takiego: ```js const x = 10; const myObj = { x }; console.log(myObj.x) // 10 ``` #### Wyjaśnienie Dotychczas (przed ES2015), kiedy chcieliśmy przy deklaracji nowego literału obiektowego (*object literal*) zastosować zmienne jako jego własności, zapisalibyśmy to w ten sposób: ```js const x = 10; const y = 20; const myObj = { x: x, // przypisanie wartości zmiennej x do myObj.x y: y // przypisanie wartości zmiennej y do myObj.y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` Jak widać, jest to dość powtarzalne, bo nazwy własności myObj są takie same, jak nazwy zmiennych, które chcemy przypisać do tych własności. Z ES2015, jeśli nazwa zmiennej jest taka sama jak własności, możemy skorzystać ze skróconego zapisu: ```js const x = 10; const y = 20; const myObj = { x, y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` #### Dodatkowe źródła - [Property shorthand - ES6 Features](http://es6-features.org/#PropertyShorthand) ### Obietnice (promises) Obietnica (promise) to obiekt, który może być zwrócony synchronicznie z asynchronicznej funkcji. ([ref](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#3cd0)). Obietnice pozwalają zapobiec tzw. [callback hell](http://callbackhell.com/), i stosowane są coraz częściej we współczesnych projektach tworzonych w języku JavaScript. #### Przykładowy kod ```js const fetchingPosts = new Promise((res, rej) => { $.get("/posts") .done(posts => res(posts)) .fail(err => rej(err)); }); fetchingPosts .then(posts => console.log(posts)) .catch(err => console.log(err)); ``` #### Wyjaśnienie Kiedy wykonujemy **zapytanie Ajax** odpowiedź nie jest synchroniczna, ponieważ żądamy zasobu, którego pobranie wymaga czasu. Może się nawet zdarzyć, że z jakiegoś powodu (404) zasób nigdy nie zostanie pobrany. Aby radzić sobie w tego typu sytuacjach, ES2015 daje nam obietnice (*promises*). Obietnice mogą mieć trzy różne stany: - oczekujący (pending) - zakończony (fulfilled) - odrzucony (rejected) Powiedzmy, że chcemy wykorzystać obietnice dla obsługi zapytania Ajax w celu pobrania zasobu X. ##### Tworzenie obietnicy Najpierw musimy stworzyć obietnicę. Dla stworzenia zapytania Ajax do zasobu X użyjemy metody GET jQuery. ```js const xFetcherPromise = new Promise( // Tworzymy obietnicę poprzez słowo kluczowe new i zapisujemy go do zmiennej function(resolve, reject) { // Konstruktor obietnicy przyjmuje jako argument funkcję, która sama przyjmuje dwa argumenty: resolve i reject $.get("X") // Uruchamiamy zapytanie Ajax .done(function(X) { // Kiedy zapytanie jest gotowe... resolve(X); // ... wypełniamy obietnicę z wartością X jako argumentem }) .fail(function(error) { // Jeśli zapytanie się nie udało... reject(error); // ... odrzucamy obietnicę z wartością X jako argumentem }); } ) ``` Jak widać na przykładzie, obiekt Promise przyjmuje funkcję-*executor*, która z kolei przy dwa argumenty **resolve** i **reject**. Argumenty te są funkcjami, które przy wezwaniu zmieniają stan obietnicy oczekujący (*pending*) na, odpowiednio, zakończony (*fulfilled*) i odrzucony (*rejected*). Obietnica znajduje się w stanie oczekiwania po stworzeniu instancji, a jej funkcja-*executor* jest natychmiast wykonywana. Kiedy jedna z funkcji *resolve* bądź *reject* zostanie wezwana w funkcji-*executor*, obietnica wywoła związane z nią procedury obsługi. ##### Użycie procedur obsługi By otrzymać rezultat obietnicy (lub błąd), musimy podpiąć ją pod procedury obsługi używając następującego kodu: ```js xFetcherPromise .then(function(X) { console.log(X); }) .catch(function(err) { console.log(err) }) ``` Jeśli wszystko przebiegło prawidłowo, zostaje wywołane *resolve* i wykonana zostaje funkcja przekazana jako argument ```.then```. Jeśli zapytanie się nie udało, zostaje wywołane *reject* i wykonana zostaje funkcja przekazana jako argument ```.catch```. > **Uwaga:** Jeśli obietnica została już wypełniona lub odrzucona w momencie podpięcia odpowiedniej procedury obsługi, procedura będzie wywołana, tak więc nie wyniknie wyścig (race condition) między wykonaniem operacji asynchronicznej i wyznaczeniem procedur obsługi. [(Ref: MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#Description) #### Dodatkowe źródła - [JavaScript Promises for dummies - Jecelyn Yeen](https://scotch.io/tutorials/javascript-promises-for-dummies) - [JavaScript Promise API - David Walsh](https://davidwalsh.name/promises) - [Using promises - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) - [What is a promise - Eric Elliott](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261) - [JavaScript Promises: an Introduction - Jake Archibald](https://developers.google.com/web/fundamentals/getting-started/primers/promises) - [Promise documentation - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) ### Łańcuchy szablonowe (template literals) Łańcuchy szablonowe to [*interpolacja wyrażenia*](https://en.wikipedia.org/wiki/String_interpolation) dla jedno- i wieloliniowych stringów. Inaczej mówiąc, jest to nowa składnia stringów, pozwalająca na wygodne użycie dowolnych wyrażeń JavaScript (np. zmiennych). #### Przykładowy kod ```js const name = "Nick"; `Hello ${name}, następujące wyrażenie jest równe czterem: ${2+2}`; // Hello Nick, następujące wyrażenie jest równe czterem: 4 ``` #### Dodatkowe źródła - [String interpolation - ES6 Features](http://es6-features.org/#StringInterpolation) - [ES6 Template Strings - Addy Osmani](https://developers.google.com/web/updates/2015/01/ES6-Template-Strings) ### Oznaczone łańcuchy szablonowe Tagi szablonowe to *funkcje które mogą być prefiksem dla [łańcucha szablonowego](#template-literals)*. Kiedy funkcja zostaje wezwana w ten sposób, pierwszy argument stanowi tablica *stringów*, które pojawiają się między interpolowanymi zmiennymi, a kolejne parametry to znaczenia wyrażeń wstawionych w string. Dla przechwycenia ich wszystkich można użyć operatora rozwijania. [(Ref: MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals). > **Uwaga :** Słynna biblioteka [styled-components](https://www.styled-components.com/) w dużej mierze polega na tej funkcjonalności. Poniżej znajduje się przykład działania tagów szablonowych: ```js function highlight(strings, ...values) { const interpolation = strings.reduce((prev, current) => { return prev + current + (values.length ? "" + values.shift() + "" : ""); }, ""); return interpolation; } const condiment = "jam"; const meal = "toast"; highlight`I like ${condiment} on ${meal}.`; // "I like jam on toast." ``` I jeszcze jeden - ciekawszy - przykład: ```js function comma(strings, ...values) { return strings.reduce((prev, next) => { let value = values.shift() || []; value = value.join(", "); return prev + next + value; }, ""); } const snacks = ['apples', 'bananas', 'cherries']; comma`I like ${snacks} to snack on.`; // "I like apples, bananas, cherries to snack on." ``` #### Dodatkowe źródła - [Wes Bos on Tagged Template Literals](http://wesbos.com/tagged-template-literals/) - [Library of common template tags](https://github.com/declandewet/common-tags) ### Importy / eksporty Moduły ES6 są używane dla otrzymania dostępu do zmiennych lub funkcji z drugich modułów, przy czym eksport powinien być jasno oznaczony w wyjściowym module. Bardzo polecam zapoznać się z zasobami MDN dotyczącymi importów i eksportów (zobacz: Dodatkowe materiały), znajdziecie tam dokładne i przystępne wyjaśnienie. #### Wyjaśnienie z przykładowym kodem ##### Nazwane eksporty (named exports) Nazwane eksporty są używane do eksportu kilku wartości z modułu. > **Uwaga :** W nazwanych eksportach można stosować jedynie [typy pierwszoklasowe](https://en.wikipedia.org/wiki/First-class_citizen), które posiadają nazwę. ```js // mathConstants.js export const pi = 3.14; export const exp = 2.7; export const alpha = 0.35; // ------------- // myFile.js import { pi, exp } from './mathConstants.js'; // Nazwany import - składnia podobna do destrukturyzacji console.log(pi) // 3.14 console.log(exp) // 2.7 // ------------- // mySecondFile.js import * as constants from './mathConstants.js'; // Wszystkie eksportowane wartości przypisane są do stałych console.log(constants.pi) // 3.14 console.log(constants.exp) // 2.7 ``` Chociaż nazwane importy przypominają *destrukturyzację*, posiadają inną składnią i nie są tym samym. Nie wspierają ani wartości domyślnych, ani *głębokiej* destrukturyzacji. Poza tym, można tworzyć aliasy, ale składnia wygląda inaczej niż przy destrukturyzacji: ```js import { foo as bar } from 'myFile.js'; // foo jest importowane i przypisane do nowej zmiennej bar ``` ##### Domyślny import / export W przypadku domyślnego eksportu na jeden moduł przypada jeden domyślny eksport. Domyślny eksport może być funkcją, klasą, obiektem itp. Wartość ta jest traktowana jako "główna" eksportowana wartość, ponieważ importowanie jej jest najprostsze. [Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Description) ```js // coolNumber.js const ultimateNumber = 42; export default ultimateNumber; // ------------ // myFile.js import number from './coolNumber.js'; // Eksport domyślny, niezależnie od swojej nazwy w wyjściowym module, automatycznie przypisywany jest do zmiennej number; console.log(number) // 42 ``` Eksport funkcji: ```js // sum.js export default function sum(x, y) { return x + y; } // ------------- // myFile.js import sum from './sum.js'; const result = sum(1, 2); console.log(result) // 3 ``` #### Dodatkowe źródła - [ES6 Modules in bulletpoints](https://ponyfoo.com/articles/es6#modules) - [Export - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) - [Import - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) - [Understanding ES6 Modules](https://www.sitepoint.com/understanding-es6-modules/) - [Destructuring special case - import statements](https://ponyfoo.com/articles/es6-destructuring-in-depth#special-case-import-statements) - [Misunderstanding ES6 Modules - Kent C. Dodds](https://medium.com/@kentcdodds/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution-ad2d5ab93ce0) - [Modules in JavaScript](http://exploringjs.com/es6/ch_modules.html#sec_modules-in-javascript) ### *this* w JavaScript Operator *this* zachowuje się inaczej niż w innych językach. W większości przypadków jego zachowanie zależy od tego, jak wywoływana jest funkcja. Zagadnienie to może być dość trudne do zrozumienia, dlatego polecam zapoznać się dokładnie z dodatkowymi materiałami podanymi niżej. Postaram się wyjaśnić, jak sam rozumiem działanie *this*. Nauczyłem się tego z [artykułu Yehudy Katza](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/). ```js function myFunc() { ... } // Po każdym wyrażeniu postaramy się określić znaczenie this w myFunc myFunc.call("myString", "hello") // "myString" -- pierwszy parametr .call zapisywany jest w *this* // W trybie non-strict myFunc("hello") // window -- myFunc() to cukier syntaktyczny dla myFunc.call(window, "hello") // W trybie strict myFunc("hello") // undefined -- myFunc() to cukier syntaktyczny dla myFunc.call(undefined, "hello") ``` ```js var person = { myFunc: function() { ... } } person.myFunc.call(person, "test") // person Object -- pierwszy parametr .call zapisywany jest w *this* person.myFunc("test") // person Object -- person.myFunc() to cukier syntaktyczny dla person.myFunc.call(person, "test") var myBoundFunc = person.myFunc.bind("hello") // Tworzy nową funkcję, w której "hello" zapisywane jest w *this* person.myFunc("test") // person Object -- Metoda bind nie ma wpływu na oryginalną metodę myBoundFunc("test") // "hello" -- myBoundFunc to person.myFunc z "hello" przywiązanym do *this* ``` #### Dodatkowe źródła - [Understanding JavaScript Function Invocation and "this" - Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/) - [JavaScript this - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) ### Klasa JavaScript jest językiem [opartym na prototypach](https://en.wikipedia.org/wiki/Prototype-based_programming) (podczas gdy, na przykład, Java jest [oparta na klasach](https://en.wikipedia.org/wiki/Class-based_programming)). ES6 wprowadza klasy JavaScript, które mają być cukrem syntaktycznym dla dziedziczenia opartego na prototypach a *nie* nowym modelem dziedziczenia opartego na klasach ([ref](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)). Użycie słowa *class* może istotnie prowadzić do błędów, jeśli jesteśmy przyzwyczajeni do klas stosowanych w innych językach. Dlatego też klasy w JavaScript lepiej traktować jak zupełnie odrębne zagadnienie. Ponieważ nasz przewodnik nie ma na celu nauki języka od podstaw, zakładam, że wiesz, czym są prototypy i jak działają. Jeśli nie, zapoznaj się z dodatkowymi materiałami znajdującymi się pod kodem przykładowym. #### Przykłady Składnia prototypu sprzed ES6: ```js var Person = function(name, age) { this.name = name; this.age = age; } Person.prototype.stringSentence = function() { return "Hello, my name is " + this.name + " and I'm " + this.age; } ``` Składnia klasy z ES6: ```js class Person { constructor(name, age) { this.name = name; this.age = age; } stringSentence() { return "Hello, my name is " + this.name + " and I'm " + this.age; } } const myPerson = new Person("Manu", 23); console.log(myPerson.age) // 23 console.log(myPerson.stringSentence()) // "Hello, my name is Manu and I'm 23 ``` #### Dodatkowe źródła Omówienie prototypów: - [Understanding Prototypes in JS - Yehuda Katz](http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/) - [A plain English guide to JS prototypes - Sebastian Porto](http://sporto.github.io/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/) - [Inheritance and the prototype chain - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) Omówienie klas: - [ES6 Classes in Depth - Nicolas Bevacqua](https://ponyfoo.com/articles/es6-classes-in-depth) - [ES6 Features - Classes](http://es6-features.org/#ClassDefinition) - [JavaScript Classes - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) ### Słowa kluczowe `extends` i `super` Słowo kluczowe `extends` używane jest w deklaracji klas w celu stworzenia klasy dziedziczącej od innej klasy ([Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends)). Klasa pochodna dziedziczy wszystkie własności klasy bazowej, może dodawać nowe lub modyfikować odziedziczone własności. Słowo kluczowe `super` służy do wzywania funkcji na klasie bazowej obiektu, włącznie z jej konstruktorem. - słowo kluczowe `super` musi być użyte przed słowem `this` w konstruktorze - Wezwanie `super()` wywołuje konstruktor klasy bazowej. Jeśli chcesz przekazać argumenty w konstruktorze klasy do konstruktora klasy bazowej, użyj `super(arguments)`. - Jeśli klasa bazowa posiada metodę (także statyczną) o nazwie `X`, można użyć `super.X()`, by wywołać ją w klasie pochodnej. #### Przykładowy kod ```js class Polygon { constructor(height, width) { this.name = 'Polygon'; this.height = height; this.width = width; } getHelloPhrase() { return `Hi, I am a ${this.name}`; } } class Square extends Polygon { constructor(length) { // Wzywany jest konstruktor klasy bazowej z szerokością i długością przekazanymi przez Polygon super(length, length); // Uwaga: W klasach pochodnych super() musi zostać wezwane przed 'this'. W przeciwnym razie pojawi się błąd. this.name = 'Square'; this.length = length; } getCustomHelloPhrase() { const polygonPhrase = super.getHelloPhrase(); // super.X() daje dostęp do metody klasy bazowej return `${polygonPhrase} with a length of ${this.length}`; } get area() { return this.height * this.width; } } const mySquare = new Square(10); console.log(mySquare.area) // 100 console.log(mySquare.getHelloPhrase()) // 'Hi, I am a Square' -- Square dziedziczy od Polygon i ma dostęp do jego metod console.log(mySquare.getCustomHelloPhrase()) // 'Hi, I am a Square with a length of 10' ``` **Uwaga :** Jeśli spróbujemy użyć `this` przed wezwaniem `super()` w klasie Square, pojawi się ReferenceError ```js class Square extends Polygon { constructor(length) { this.height; // ReferenceError, najpierw trzeba wezwać super! // Wzywany jest konstruktor klasy bazowej z szerokością i długością przekazanymi przez Polygon super(length, length); // Uwaga: W klasach pochodnych super() musi zostać wezwane przed 'this'. W przeciwnym razie pojawi się błąd. this.name = 'Square'; } } ``` #### Dodatkowe źródła - [Extends - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends) - [Super operator - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) - [Inheritance - MDN](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance) ### Składnia async/await Oprócz [Obietnic (Promises)](#promises), możesz spotkać jeszcze jeden rodzaj składni dla obsługi kodu asynchronicznego, a mianowicie *async / await*. Rolą funkcji async/await jest uproszczenie zachowania używanych synchronicznie obietnic oraz by używać grup Obietnic. Async/await przypomina połączenie generatorów i obietnic. Funkcje async *zawsze* zwracają Obietnicę ([Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)) > **Uwaga :** Ponieważ funkcje async / await bazują na obietnicach, aby prawidłowo stosować wspomniane funkcje, musisz najpierw dobrze rozumieć działanie obietnic. > **Uwaga 2:** [*await* musi zostać użyte w funkcji *async*](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9#f3f0), co oznacza, że await nie można użyć na wyższym poziomie kodu, nie znajdującym się wewnątrz funkcji async. #### Przykładowy kod ```js async function getGithubUser(username) { // słowo kluczowe async pozwala użyć await w funkcji i oznacza, że funkcja zwraca obietnicę const response = await fetch(`https://api.github.com/users/${username}`); // Czeka na obietnicę przed przejściem do reszty kodu return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) // logowanie użytkownika - nie można użyć await, bo nie znajduje się w funkcji async .catch(err => console.log(err)); // jeśli w funkcji async pojawi się błąd, wyłapujemy go tutaj ``` #### Wyjaśnienie z przykładowym kodem *Async / Await* jest zbudowany na obietnicach, ale pozwala na bardziej imperatywny styl kodu. Operator *async* oznacza funkcję jako asynchroniczną. Dana funkcja zawsze zwraca Obietnicę. W funkcji *async* można użyć operatora *async*, aby zatrzymać wykonanie kodu na danej linijce dopóki zwracana Obietnica nie zostanie wypełniona bądź odrzucona. ```js async function myFunc() { // ponieważ to funkcja async, możemy użyć operatora await return "hello world"; } myFunc().then(msg => console.log(msg)) // "hello world" -- wartość zwracana przez myFunc jest przekształcana w obietnicę ze względu na operator async ``` Kiedy zostaje osiągnięte wyrażenie *return* w funkcji async, Obietnica zostaje wypełniona ze zwracaną wartością. Jeśli wewnątrz funkcji async pojawia się błąd, stan Obietnicy zmienia się na *odrzucony* (*rejected*). Jeśli funkcja async nie zwraca żadnej wartości, Obietnica zostanie zwrócona i wypełniona bez wartości, kiedy zakończy się wykonanie funkcji async. Operator *await* jest używany do oczekiwania na wypełnienie Obietnicy i może być użyty jedynie w ciele funkcji *async*. Kiedy zostanie osiągnięty, następuje wstrzymanie wypełnienia kodu do chwili wypełnienia obietnicy. > **Uwaga :** *fetch* to funkcja, która zwraca Obietnicę i pozwala na wykonania zapytania Ajax. Rozpatrzmy przykład użycia fetch z obietnicami: ```js function getGithubUser(username) { return fetch(`https://api.github.com/users/${username}`).then(response => response.json()); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` A oto ekwiwalent z *async / await*: ```js async function getGithubUser(username) { // dozwolone użycie obietnicy + await const response = await fetch(`https://api.github.com/users/${username}`); // Wykonanie wstrzymane do czasu wypełnienia obietnicy fetch return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` Składnia *async / await* jest wyjątkowo użyteczna, gdy chcemy połączyć w łańcuch wzajemnie zależne od siebie obietnice. Na przykład, kiedy potrzebujemy tokena, by pobrać z bazy danych post na blogu i informacje o autorze: > **Uwaga :** wyrażenia *await* muszą być otoczone nawiasami, aby można było wezwać wartości ich metod i własności w jednej linijce. ```js async function fetchPostById(postId) { const token = (await fetch('token_url')).json().token; const post = (await fetch(`/posts/${postId}?token=${token}`)).json(); const author = (await fetch(`/users/${post.authorId}`)).json(); post.author = author; return post; } fetchPostById('gzIrzeo64') .then(post => console.log(post)) .catch(err => console.log(err)); ``` ##### Obsługa błędów Jeśli nie dodamy bloków *try / catch* wokół wyrażeń *await*, nieschwytane wyjątki - niezależnie od tego, czy pojawią się w ciele funkcji *async*, czy zostaną wstrzymane w czasie *await* - doprowadzą do odrzucenia obietnicy zwracanej przez funkcję *async*. Użycie wyrażenia `throw` w funkcji async sprowadza się do tego samego, co zwrot odrzuconej obietnicy. [(Ref: PonyFoo)](https://ponyfoo.com/articles/understanding-javascript-async-await#error-handling). > **Uwaga :** Obietnice zachowują się tak samo! Oto jak obsługujemy błędy z pomocą obietnic: ```js function getUser() { // Obietnica będzie odrzucona! return new Promise((res, rej) => rej("User not found !")); } function getAvatarByUsername(userId) { return getUser(userId).then(user => user.avatar); } function getUserAvatar(username) { return getAvatarByUsername(username).then(avatar => ({ username, avatar })); } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "User not found !" ``` Ekwiwalent z *async / await*: ```js async function getUser() { // Zwrócona obietnica zostanie odrzucona! throw "User not found !"; } async function getAvatarByUsername(userId) => { const user = await getUser(userId); return user.avatar; } async function getUserAvatar(username) { var avatar = await getAvatarByUsername(username); return { username, avatar }; } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "User not found !" ``` #### Dodatkowe źródła - [Async/Await - JavaScript.Info](https://javascript.info/async-await) - [ES7 Async/Await](http://rossboucher.com/await/#/) - [6 Reasons Why JavaScript’s Async/Await Blows Promises Away](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9) - [JavaScript awaits](https://dev.to/kayis/javascript-awaits) - [Using Async Await in Express with Node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) - [Async Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) - [Await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) - [Using async / await in express with node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) ### Prawda / fałsz W JavaScript wartości "prawda" lub "fałsz" określane są w kontekście boolowskim. Przykładem kontekstu boolowskiego może być określenie warunku ```if```: Jako prawda (```true```) określona będzie każda wartość, jeśli nie jest równa: - ```false``` - ```0``` - ```""``` (empty string) - ```null``` - ```undefined``` - ```NaN``` Przykłady *kontekstu boolowskiego*: - określenie warunku ```if``` ```js if (myVar) {} ``` ```myVar``` może być dowolnym [obiektem pierwszoklasowym](https://en.wikipedia.org/wiki/First-class_citizen) (zmienna, funkcja, typ boolowski) ale będzie przekształcona w typ boolowski, ponieważ określana jest w kontekście boolowskim. - Po operatorze logicznym **NOT** ```!``` This operator returns false if its single operand can be converted to true; otherwise, returns true. Operator ten zwraca "fałsz" jeśli jego jedyny operand może być przekształcony w znaczenie "prawda"; w przeciwnym razie zwraca "prawdę" ```js !0 // true -- 0 to "fałsz", więc zwraca "prawdę" !!0 // false -- 0 to "fałsz", więc !0 zwraca "prawdę", więc !(!0) zwraca "fałsz" !!"" // false -- pusty string to "fałsz", więc NOT (NOT false) równe jest "fałszowi" ``` - Z konstruktorem obiektu *Boolean* ```js new Boolean(0) // false new Boolean(1) // true ``` - Z operatorem warunkowym ```js myVar ? "prawda" : "fałsz" ``` myVar jest określana w kontekście boolowskim. ``` #### Dodatkowe źródła - [Truthy (MDN)](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) - [Falsy (MDN)](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) - [Truthy and Falsy values in JS - Josh Clanton](http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html) ### Anomorfizmy i katamorfizmy #### Anamorfizmy Anamorfizmy to funkcje, które mapują pewien obiekt to bardziej złożonej struktury zawierającej typ tego obiektu. Jest to proces *rozwijania* (*unfolding*) prostej struktury do bardziej złożonej. Rozpatrzmy rozwijanie liczby całkowitej do listy liczb całkowitych. Początkowym obiektem jest liczba całkowita, bardziej złożoną strukturą - lista liczb całkowitych. **Przykładowy kod** ```js function downToOne(n) { const list = []; for (let i = n; i > 0; --i) { list.push(i); } return list; } downToOne(5) //=> [ 5, 4, 3, 2, 1 ] ``` #### Katamorfizmy Katamorfizmy to przeciwieństwo anamorfizmów - "zwijają" bardziej skomplikowane struktury do prostszych. Przyjrzyjmy się funkcji `product`, która przyjmuje listę liczb całkowitych i zwraca pojedynczą liczbę całkowitą. **Przykładowy kod** ```js function product(list) { let product = 1; for (const n of list) { product = product * n; } return product; } product(downToOne(5)) // 120 ``` #### Dodatkowe źródła * [Anamorphisms in JavaScript](http://raganwald.com/2016/11/30/anamorphisms-in-javascript.html) * [Anamorphism](https://en.wikipedia.org/wiki/Anamorphism) * [Catamorphism](https://en.wikipedia.org/wiki/Catamorphism) ### Generatory Innym sposobem zapisania funkcji `downToOne` jest użycie Generatora. Stworzenie instancji obiektu `Generator` wymaga użycia deklaracji funkcji `function *`. Generatory to funkcje, które mogą być zamknięte i później uruchomione ponownie z zachowaniem kontekstu między kolejnymi uruchomieniami. Na przykład funkcja `downToOne` może być zapisana tak: ```js function * downToOne(n) { for (let i = n; i > 0; --i) { yield i; } } [...downToOne(5)] //[ 1, 2, 3, 4, 5 ] ``` Generatory zwracają obiekt iterowalny. Kiedy wzywana jest funkcja iteratora `next()`, jest ona wykonywana aż do perwszego wyrażenia `yield`, które określa wartość, jaka zostanie zwrócona przez iterator lub z `yield*`, które odsyła do kolejnej funkcji-generatora. Jeśli w generatorze wezwane jest wyrażenie `return`, generator zostanie oznaczony jako wyczerpany i przekazany jako wartość do zwrotu. Kolejne wezwania `next()` nie zwrócą żadnych nowych wartości. **Przykładowy kod** ```js // Przykład Yield function * idMaker() { var index = 0; while (index < 2) { yield index; index = index + 1; } } var gen = idMaker(); gen.next().value; // 0 gen.next().value; // 1 gen.next().value; // undefined ``` Wyrażenie `yield*` pozwala generatorowi wzywać inną funkcję-generator w czasie iteracji. ```js // Yield * Example function * genB(i) { yield i + 1; yield i + 2; yield i + 3; } function * genA(i) { yield i; yield* genB(i); yield i + 10; } var gen = genA(10); gen.next().value; // 10 gen.next().value; // 11 gen.next().value; // 12 gen.next().value; // 13 gen.next().value; // 20 ``` ```js // Przykład Generator Return function* yieldAndReturn() { yield "Y"; return "R"; yield "unreachable"; } var gen = yieldAndReturn() gen.next(); // { value: "Y", done: false } gen.next(); // { value: "R", done: true } gen.next(); // { value: undefined, done: true } ``` #### Dodatkowe źródła * [Mozilla MDN Web Docs, Iterators and Generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Generators) ### Metody statyczne #### Krótkie wyjaśnienie Słowo kluczowe `static` jest używane w klasach dla deklaracji metod statycznych. Metody statyczne to funkcje klasy, które należą do obiektu klasy, ale nie są dostępne dla instancji tej klasy. #### Przykładowy kod ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } } //Zauważ, że nie musieliśmy tworzyć instancji klasy Repo console.log(Repo.getName()) //Repo name is modern-js-cheatsheet let r = new Repo(); console.log(r.getName()) //Nieprzechwycony TypeError: repo.getName nie jest funkcją ``` #### Szczegółowe wyjaśnienie Metody statyczne mogą być wezwane z innych metod statycznych za pomocą słowa kluczowego `this`, co nie działa w przypadku metod niestatycznych. Metody niestatyczne nie mają bezpośredniego dostępu do metod statycznych z użyciem `this`. ##### Wzywanie innych metod statycznych z metod statycznych Aby wezwać metodę statyczną z innej metody statycznej, należy użyć słowa kluczowego `this`: ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } static modifyName(){ return this.getName() + '-added-this' } } console.log(Repo.modifyName()) //Repo name is modern-js-cheatsheet-added-this ``` ##### Wzywanie metod statycznych z metod niestatycznych Metody niestatyczne mogą wzywać metody statyczne na dwa sposoby; 1. ###### Używając nazwy klasy. Aby zyskać dostęp do metody statycznej z metody niestatycznej używamy nazwy klasy i wzywamy metodę statyczną jak własność, np. `ClassName.StaticMethodName` ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ return Repo.getName() + ' and it contains some really important stuff' } } // musimy stworzyć instancję klasy, by mieć dostęp do metod niestatycznych let r = new Repo() console.log(r.useName()) //Repo name is modern-js-cheatsheet and it contains some really important stuff ``` 2. ###### Używając konstruktora Metody statyczne mogą być wzywane jak własności na obiekcie konstruktora. ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ //Wzywa metodę statyczną jako własność konstruktora return this.constructor.getName() + ' and it contains some really important stuff' } } // musimy stworzyć instancję klasy, by mieć dostęp do metod niestatycznych let r = new Repo() console.log(r.useName()) //Repo name is modern-js-cheatsheet and it contains some really important stuff ``` #### Dodatkowe źródła - [static keyword- MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) - [Static Methods- Javascript.info](https://javascript.info/class#static-methods) - [Static Members in ES6- OdeToCode](http://odetocode.com/blogs/scott/archive/2015/02/02/static-members-in-es6.aspx) ## Słowniczek ### Zakres widoczności (scope) Kontekst, w którym wartości i wyrażenia są "widoczne" lub można się do nich odwoływać. Jeśli zmienna lub inne wyrażenie "nie znajduje się w aktualnym zakresie widoczności", oznacza to, że jest niedostępna do użytku. Źródło: [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Scope) ### Przekształcenie zmiennej (variable mutation) Mówimy, że zmienna została przekształcona, kiedy jej wartość jest inna niż wartość początkowa. ```js var myArray = []; myArray.push("firstEl") // myArray została przekształcona ``` Zmienna jest określana jako "niemodyfikowalna" (*immutable*), kiedy nie może być przekształcana. [Zobacz artykuł](https://developer.mozilla.org/en-US/docs/Glossary/Mutable). ================================================ FILE: JavaScript/translations/pt-BR.md ================================================ # Cheatsheet de JavaScript Moderno ![Modern JavaScript cheatsheet](https://i.imgur.com/aexPxMb.png) Crédito da Imagem: [Ahmad Awais ⚡️](https://github.com/ahmadawais) ## Introdução ### Motivação Esse documento é um conjunto de "cheatsheet" para javascript que você frequentemente encontrará em projetos modernos e na maioria de exemplos de códigos atuais. Esse guia não tem a intenção de te ensinar Javascript do zero, mas sim ajudar desenvolvedores com conhecimentos básicos a se familiarizarem com códigos modernos. Além disso, eu @mbeaudru ocasionalmente forneço dicas que podem ser discutidas, mas tomarei o cuidado de avisar quando eu fizer uma recomendação pessoal. > **Nota:** Muito dos conceitos apresentados aqui vem de uma atualização do Javascript (ES2015, chamada também de ES6). Você pode achar as novas funcionalidades adicionadas nessa atualização [aqui](http://es6-features.org). ### Material Complementar Se você estiver com dificuldades em entender alguma coisa, eu sugiro que você procure por respostas nos seguintes lugares: - [MDN (Mozilla Developer Network)](https://developer.mozilla.org/fr/search?q=) - [You don't know JS (livro)](https://github.com/getify/You-Dont-Know-JS) - [ES6 Funcionalidades e exemplos](http://es6-features.org) - [WesBos blog (ES6)](http://wesbos.com/category/es6/) - [Reddit (JavaScript)](https://www.reddit.com/r/javascript/) - [Google](https://www.google.com/) para encontrar blogs e recursos específicos ## Sumário - [Modern JavaScript cheatsheet](#modern-javascript-cheatsheet) * [Introdução](#Introdução) + [Motivação](#Motivação) + [Material Complementar](#Material-Complementar) * [Tabela de Conteúdos](#Sumário) * [Noções](#Noções) + [Declaração de variáveis: var, const, let](#declaração-de-variáveis-var-const-let) - [Breve explicação](#breve-explicação) - [Exemplo](#exemplo) - [Explicação Detalhada](#explicação-detalhada) - [Material Complementar](#material-complementar) + [Função de Seta](#função-de-seta) - [Exemplo](#exemplo-de-codigo) - [Explicação Detalhada](#detailed-explanation-1) * [Concisão](#concisão) * [Referência *this*](#referência-this) - [Material Útil](#material-útil) + [Parametros padrão de uma Function](#parametros-padrão-de-uma-function) - [Material Complementar](#material-complementar) + [Desestruturação de objetos e arrays](#desestruturação-de-objetos-e-arrays) - [Explicação com exemplo de código](#explicação-com-exemplo-de-código) - [Material Útil](#material-útil-1) + [Metodos de lista - map / filter / reduce](#array-methods---map--filter--reduce) - [Exemplo](#sample-code-2) - [Explicação](#explanation) * [Array.prototype.map()](#arrayprototypemap) * [Array.prototype.filter()](#arrayprototypefilter) * [Array.prototype.reduce()](#arrayprototypereduce) - [Material Complementar](#external-resource) + [Spread operator "..."](#spread-operator-) - [Exemplo](#sample-code-3) - [Explicação](#explanation-1) * [Em interações (como arrays)](#in-iterables-like-array) * [Function rest parameter](#function-rest-parameter) * [Object properties spreading](#object-properties-spreading) - [Material Complementar](#external-resources) + [Object property shorthand](#object-property-shorthand) - [Explicação](#explanation-2) - [Material Complementar](#external-resources-1) + [Promises](#promises) - [Exemplo](#sample-code-4) - [Explicação](#explanation-3) * [Criando uma promise](#create-the-promise) * [Usando uma promise](#use-the-promise) - [External Resources](#external-resources) + [Template literals](#template-literals) - [Sample code](#sample-code-5) - [External resources](#external-resources-2) + [Imports / Exports](#imports--exports) - [Explanation with sample code](#explanation-with-sample-code-1) - [External resources](#external-resources-3) + [JavaScript *this*](#-javascript-this) - [External resources](#external-resources-4) + [Class](#class) - [Samples](#samples) - [External resources](#external-resources-5) + [Async Await](#async-await) - [Sample code](#sample-code-6) - [Explanation](#explanation-4) - [External resources](#external-resources-7) * [Glossary](#glossary) + [Scope](#-scope) + [Variable mutation](#-variable-mutation) ## Noções ### Declaração de variáveis: var, const, let Em JavaScript, existem três palavras-chave disponíveis para declarar uma variável, e cada uma tem suas diferenças. São elas ```var```, ```let``` e ```const```. #### Breve explicação Variáveis declaradas com a palavra-chave ```const``` não podem ser reatribuídas, enquanto ```let``` e ```var``` podem. Eu recomendo sempre declarar suas variáveis com ```const``` por padrão, e com ```let``` se você precisar *modifica-lo* ou reatribuí-lo mais tarde.
Escopo Reatribuível Mutável Zona Temporal Inoperante
const Bloco Não Sim Sim
let Bloco Sim Sim Sim
var Função Sim Sim Não
#### Exemplo ```javascript const person = "Nick"; person = "John" // Irá ocorrer um erro, person não pode ser reatribuída ``` ```javascript let person = "Nick"; person = "John"; console.log(person) // "John", a reatribuição é permitida com let ``` #### Explicação Detalhada O [*escopo*](#scope_def) de uma variável grosseiramente significa "onde esta variável está disponível no código". ##### var Variáveis declaradas com ```var``` são *função escopada*, significando que quando uma variável é criada em uma função, tudo naquela função pode acessar essa variável. Além disso, uma variável de *função escopada* criada em uma função não pode ser acessada fora desta função. Eu recomendo que você imagine isso, como se uma variável *X escopada* significasse que essa variável era uma propriedade de X. ```javascript function myFunction() { var myVar = "Nick"; console.log(myVar); // "Nick" - myVar é acessível dentro da função. } console.log(myVar); // Lança um ReferenceError, myVar não está acessível fora da função. ``` Ainda focado na variável de escopo, aqui está um exemplo mais sutil: ```javascript function myFunction() { var myVar = "Nick"; if (true) { var myVar = "John"; console.log(myVar); // "John" // na verdade, sendo myVar do escopo da função, nós simplesmente apagamos o valor anterior do myVar "Nick" para "John" } console.log(myVar); // "John" - veja como as instruções no bloco if afetaram esse valor } console.log(myVar); // Lança um ReferenceError, myVar não é acessível fora da função. ``` Além disso, variáveis declaradas *var* são movidas para o topo do escopo na execução. É o que chamamos de [içando a var](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting). Esta parte do código: ```js console.log(myVar) // undefined -- sem erro lançado var myVar = 2; ``` é entendido na execução como: ```js var myVar; console.log(myVar) // undefined -- sem erro lançado myVar = 2; ``` ##### let ```var``` e ```let ``` são quase os mesmos, mas variáveis declaradas com ```let``` - são *escopado em bloco* - **não** são acessíveis antes de serem atribuídas - não podem ser re-declaradas no mesmo escopo Vamos ver o impacto do escopo em bloco em nosso exemplo anterior: ```javascript function myFunction() { let myVar = "Nick"; if (true) { let myVar = "John"; console.log(myVar); // "John" // na verdade, myVar sendo escopada em bloco, nós criamos uma nova variável myVar. // essa variável não é acessível fora do bloco e é totalmente independente // da primeira myVar criada ! } console.log(myVar); // "Nick", veja como as instruções no bloco IF NÃO afetou este valor } console.log(myVar); // lançado um ReferenceError, myVar não é acessível fora da fucnção. ``` Agora, o que significa para as variáveis *let* (e *const*) não estarem acessíveis antes de serem atribuídas: ```js console.log(myVar) // lança um ReferenceError ! let myVar = 2; ``` Em contraste com as variáveis *var*, se você tentar ler ou escrever em uma variável *let* ou *const* antes de serem atribuídos, um erro será gerado. Esse fenômeno é freqüentemente chamado [*Zona Temporal Inoperante*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let) ou *TDZ*. > **Nota:** Tecnicamente, as declarações de *let* e *const* também estão sendo içadas, mas não a sua atribuição. Uma vez que elas são feitas para que elas não possam ser usados antes da atribuição, ela intuitivamente parece que não há içamento, mas existe. Saiba mais sobre isso [explicação muito detalhada aqui](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) se quiser saber mais. Além disso, você não pode re-declarar uma variável *let*: ```js let myVar = 2; let myVar = 3; // Retorna um SyntaxError ``` ##### const Variáveis declaradas ```const``` agem como variáveis *let*, mas elas não podem ser reatribuídas. Para resumir, variáveis *const*: - são *escopado em bloco* - não são acessíveis antes de serem atribuídos - não podem ser re-declaradas no mesmo escopo - não podem ser reatribuídas ```js const myVar = "Nick"; myVar = "John" // lança um erro, reatribuição não é permitido ``` ```js const myVar = "Nick"; const myVar = "John" // lança um erro, re-declaração não é permitida ``` Mas há uma sutileza : variáveis ```const``` não são [**imutáveis**](#mutation_def) ! Concretamente, Isto significa que variáveis *objetos* e *arrays* declaradas com ```const``` **podem** ser mutadas. Para objetos: ```js const person = { name: 'Nick' }; person.name = 'John' // isto irá funcionar! A variável objeto person não é completamente reatribuída, mas mutada console.log(person.name) // "John" person = "Sandra" // lança um erro, porque a reatribuição não é permitida com variáveis declaradas com const ``` Para arrays: ```js const person = []; person.push('John'); // isto irá funcionar! A variável array person não é completamente reatribuída, mas mutada console.log(person[0]) // "John" person = ["Nick"] // lança um erro, porque a reatribuição não é permitida com variáveis declaradas com array ``` #### Material Complementar - [Como let e const são escopados em JavaScript - WesBos](http://wesbos.com/javascript-scoping/) - [Zona temporal Inoperante (TDZ) desmistificada](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) ### Função de seta A atualização do JavaScript ES6 introduziu *funções de seta*, que é outra maneira de declarar e usar funções. Aqui estão os benefícios que elas trazem: - Mais conciso - *this* é retirado dos arredores - retorno implícito #### Exemplo de código - Concisão e retorno implícito ```js function double(x) { return x * 2; } // Forma tradicional console.log(double(2)) // 4 ``` ```js const double = x => x * 2; // A mesma função escrita como uma função de seta com retorno implícito console.log(double(2)) // 4 ``` - Referência *this* Em uma função de seta, *this* é igual ao valor *this* do contexto de execução envolvente. Basicamente, com as funções de seta, você não precisa fazer o truque "that/self = this" antes de chamar uma função dentro de uma função. ```js function myFunc() { this.myVar = 0; setTimeout(() => { this.myVar++; console.log(this.myVar) // 1 }, 0); } ``` #### Explicação detalhada ##### Concisão As funções de seta são mais concisas do que as funções tradicionais em diversas maneiras. Vamos rever todos os casos possíveis: - Retorno implícito VS explícito Um **retorno explícito** é uma função em que a palavra-chave *return* é usada em seu corpo. ```js function double(x) { return x * 2; // esta função retorna explicitamente x * 2, a palavra-chave *retorno* é usada } ``` Na maneira tradicional de escrever funções, o retorno sempre foi explícito. Mas com funções de seta, você pode fazer *retorno implícito*, o que significa que você não precisa usar a palavra-chave *return* para retornar um valor. ```js const double = (x) => { return x * 2; // um retorno explícito aqui } ``` Uma vez que esta função apenas retorna algo (sem instruções antes da palavra-chave *return*), podemos fazer um retorno implícito. ```js const double = (x) => x * 2; // Correto, retorna x*2 ``` Para fazer isso, só precisamos **remover os colchetes** e a palavra-chave **return**. É por isso que é chamado de *retorno implícito*, a palavra-chave *return* não existe, mas essa função retornará ```x * 2```. > **Nota:** Se sua função não retornar um valor (com *efeitos colaterais*), ele não faz um retorno explícito nem implícito. Além disso, se você quiser retornar implicitamente um *objeto*, você **deve ter parênteses em torno dele**, pois isso entrará em conflito com as chaves do bloco: ```js const getPerson = () => ({ name: "Nick", age: 24 }) console.log(getPerson()) // { name: "Nick", age: 24 } -- objeto implicitamente retornado pela função de seta ``` - Só um argumento Se a sua função apenas tiver um parâmetro, você pode omitir os parênteses à sua volta. Se pegarmos o código *double* acima: ```js const double = (x) => x * 2; // esta função de seta apenas leva um parâmetro ``` Parênteses ao redor do parâmetro podem ser evitados: ```js const double = x => x * 2; // esta função de seta tem apenas um parâmetro ``` - Nenhum argumento Quando não há argumento fornecido para uma função de seta, você precisa fornecer parênteses, ou não será uma sintaxe válida. ```js () => { // parênteses são fornecidos, tudo está ok const x = 2; return x; } ``` ```js => { // Sem parênteses, isso não funcionará! const x = 2; return x; } ``` ##### Referência *this* Para entender essa sutileza introduzida com funções de seta, você deve saber como [this](#this_def) se comporta em JavaScript. Em funções de seta, *this* é igual ao valor *this* do contexto de execução envolvente. O que significa que uma função de seta não cria um novo *this*, Ela pega do seu entorno em vez disso. Sem uma função de seta, se você quisesse acessar uma variável de *this* em uma função dentro de outra função, você tinha que usar *that = this* ou *self = this*. Por exemplo, usando a função setTimeout dentro de myFunc: ```js function myFunc() { this.myVar = 0; var that = this; // that = this (truque) setTimeout( function() { // Um novo *this* é criado neste escopo de função that.myVar++; console.log(that.myVar) // 1 console.log(this.myVar) // undefined -- veja a declaração da função acima }, 0 ); } ``` Mas com função de seta, *this* é retirado do seu entorno: ```js function myFunc() { this.myVar = 0; setTimeout( () => { // this é retirado do entorno, o que significa de myFunc aqui this.myVar++; console.log(this.myVar) // 1 }, 0 ); } ``` #### Material Útil - [Arrow functions introduction (Introdução à Funções de Seta) - WesBos](http://wesbos.com/arrow-functions/) - [JavaScript arrow function - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - [Arrow function and lexical *this*](https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4) ### Parametros padrão de uma Function A partir da atualização do JavaScript ES2015, você pode definir um valor padrão para os parâmetros da função usando a seguinte sintaxe: ```js function myFunc(x = 10) { return x; } console.log(myFunc()) // 10 -- nenhum valor é fornecido então o valor padrão de x que é 10 será atribuído a x em myFunc console.log(myFunc(5)) // 5 -- um valor é fornecido então x é igual a 5 em myFunc console.log(myFunc(undefined)) // 10 -- um valor undefined é fornecido então o valor padrão é atribuído para x console.log(myFunc(null)) // null -- um valor (null) é fornecido, veja abaixo para mais detalhes neste caso ``` O valor de parâmetro padrão é aplicado em duas e somente duas situações: - Nenhum parâmetro fornecido - *undefined* parâmetro fornecido Em outras palavras, se você passar um *null* o parâmetro padrão **não irá ser aplicado**. > **Nota:** Atribuição de valor padrão também pode ser usada com parâmetros desestruturados (veja o próximo conceito para ver um exemplo) #### Material Complementar - [Default parameter value - ES6 Features](http://es6-features.org/#DefaultParameterValues) - [Default parameters - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) ### Desestruturação de objetos e arrays *Desestruturação* é uma maneira conveniente de criar novas variáveis extraindo alguns valores de dados armazenados em objetos ou arrays (matrizes). Para nomear alguns casos de uso, *desestruturação* pode ser usado para desestruturar parâmetros de função ou *this.props* em projetos React, por exemplo. #### Explicação com exemplo de código - Objeto Vamos considerar o seguinte objeto para todos os exemplos: ```js const person = { firstName: "Nick", lastName: "Anderson", age: 35, sex: "M" } ``` Sem desestruturação ```js const first = person.firstName; const age = person.age; const city = person.city || "Paris"; ``` Com desestruturação, tudo em uma única linha: ```js const { firstName: first, age, city = "Paris" } = person; // É isso ! :) console.log(age) // 35 -- uma nova variável age é criada e é igual a person.age console.log(first) // "Nick" -- uma nova variável first é criada e é igual person.firstName console.log(firstName) // ReferenceError -- person.firstName existe MAS a nova variável criada é nomeada primeiro console.log(city) // "Paris" -- uma nova variável city é criada e uma vez que person.city é indefinida, city é igual ao valor padrão fornecido "Paris". ``` **Nota :** Em ```const { age } = person;```, os colchetes depois da palavra-chave *const* não são usados para declarar um objeto nem um bloco, mas é a sintaxe da *desestruturação*. - Parâmetros de função *Desestruturação* é freqüentemente usado para desestruturar parâmetros de objetos em funções. Sem desestruturação ```js function joinFirstLastName(person) { const firstName = person.firstName; const lastName = person.lastName; return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` Ao desestruturar o parâmetro de objeto *person*, obtemos uma função mais concisa: ```js function joinFirstLastName({ firstName, lastName }) { // criamos variáveis firstName e lastName por desestruturação person parameter return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` A desestruturação é ainda mais agradável para usar com [funções de seta] (#função-de-seta): ```js const joinFirstLastName = ({ firstName, lastName }) => firstName + '-' + lastName; joinFirstLastName(person); // "Nick-Anderson" ``` - Array (Matriz) Vamos considerar a seguinte array: ```js const myArray = ["a", "b", "c"]; ``` Sem desestruturação ```js const x = myArray[0]; const y = myArray[1]; ``` Com desestruturação ```js const [x, y] = myArray; // É isso ! console.log(x) // "a" console.log(y) // "b" ``` #### Material Útil - [ES6 Features - Destructuring Assignment (Funcionalidades ES6 - Atribuição de Destruturação)](http://es6-features.org/#ArrayMatching) - [Destructuring Objects - WesBos](http://wesbos.com/destructuring-objects/) - [ExploringJS - Destructuring](http://exploringjs.com/es6/ch_destructuring.html) ================================================ FILE: JavaScript/translations/ru-RU.md ================================================ # Памятка по современному JavaScript ![Памятка по современному JavaScript](https://i.imgur.com/aexPxMb.png) За картинку спасибо [Ahmad Awais ⚡️](https://github.com/ahmadawais) ## Введение ### Мотивация В этом документе собраны возможности языка JavaScript, с которыми вы наверняка столкнетесь в современных проектах и примерах кода. Цель этого руководства — не обучить вас JavaScript с нуля, а помочь разработчикам с базовыми знаниями, которые при изучении современных кодовых баз (или, скажем, React) сталкиваются со сложностями из-за использованных в них концепций JavaScript. Иногда я буду давать личные советы, которые могут быть спорными, но постараюсь упоминать, что это личное мнение. > **Примечание:** Большинство представленных здесь понятий взяты из обновления языка JavaScript (ES2015, которое часто называют ES6). Вы можете найти новые возможности из этого обновления [здесь](http://es6-features.org); они хорошо описаны. ### Дополнительные ресурсы Если вам сложно разобраться с каким-то понятием, рекомендую искать ответы на вопросы на следующих ресурсах: - [MDN (сеть разработчиков Mozilla)](https://developer.mozilla.org/ru/search?q=). - [Вы не знаете JS (серия книг)](https://github.com/azat-io/you-dont-know-js-ru). - [ES6 Features with examples](http://es6-features.org). - [Блог WesBos (ES6)](http://wesbos.com/category/es6/). - [Javascript Basics for Beginners](https://www.udacity.com/course/javascript-basics--ud804) — бесплатный курс от Udacity. - [Reddit (JavaScript)](https://www.reddit.com/r/javascript/). - [Google](https://www.google.com/) для поиска специализированных блогов и ресурсов. - [StackOverflow](https://stackoverflow.com/questions/tagged/javascript). ## Содержание - [Памятка по современному JavaScript](#Памятка-по-современному-javascript) * [Введение](#Введение) + [Мотивация](#Мотивация) + [Дополнительные ресурсы](#Дополнительные-ресурсы) * [Содержание](#Содержание) * [Понятия](#Понятия) + [Объявление переменных: `var`, `const`, `let`](#Объявление-переменных-var-const-let) - [Краткое объяснение](#Краткое-объяснение) - [Пример кода](#Пример-кода) - [Подробное объяснение](#Подробное-объяснение) - [Дополнительные материалы](#Дополнительные-материалы) + [Стрелочные функции](#-Стрелочные-функции) - [Пример кода](#Пример-кода-1) - [Подробное объяснение](#Подробное-объяснение-1) * [Краткость](#Краткость) * [Использование `this`](#Использование-this) - [Полезные ресурсы](#Полезные-ресурсы) + [Значение аргументов функции по умолчанию](#Значение-аргументов-функции-по-умолчанию) - [Дополнительные материалы](#Дополнительные-материалы-1) + [Деструктуризация объектов и массивов](#Деструктуризация-объектов-и-массивов) - [Объяснение с помощью примера кода](#Объяснение-с-помощью-примера-кода) - [Полезные ресурсы](#Полезные-ресурсы-1) + [Методы массивов - `map` / `filter` / `reduce`](#Методы-массивов--map--filter--reduce) - [Пример кода](#Пример-кода-2) - [Объяснение](#Объяснение) * [`Array.prototype.map()`](#arrayprototypemap) * [`Array.prototype.filter()`](#arrayprototypefilter) * [`Array.prototype.reduce()`](#arrayprototypereduce) - [Дополнительные материалы](#Дополнительные-материалы-2) + [Оператор расширения `...`](#Оператор-расширения-) - [Пример кода](#Пример-кода-3) - [Объяснение](#Объяснение-1) * [В итерируемых объектах (например, массивах)](#В-итерируемых-объектах-например-массивах) * [Оставшиеся аргументы функции](#Оставшиеся-аргументы-функции) * [Расширение свойств объектов](#Расширение-свойств-объектов) - [Дополнительные материалы](#Дополнительные-материалы-3) + [Сокращенная запись свойств объектов](#Сокращенная-запись-свойств-объектов) - [Объяснение](#Объяснение-2) - [Дополнительные материалы](#Дополнительные-материалы-4) + [Промисы](#Промисы) - [Пример кода](#Пример-кода-4) - [Пояснение](#Пояснение) * [Создание промиса](#Создание-промиса) * [Использование обработчиков промисов](#Использование-обработчиков-промисов) - [Дополнительные материалы](#Дополнительные-материалы-5) + [Шаблонные строки](#Шаблонные-строки) - [Пример кода](#Пример-кода-5) - [Дополнительные материалы](#Дополнительные-материалы-6) + [Тегированные шаблонные строки](#Тегированные-шаблонные-строки) - [Дополнительные материалы](#Дополнительные-материалы-7) + [Импорт / экспорт](#Импорт--экспорт) - [Объяснение с помощью примера кода](#Объяснение-с-помощью-примера-кода) * [Именованный экспорт](#Именованный-экспорт) * [Импорт / экспорт по умолчанию](#Импорт--экспорт-по-умолчанию) - [Дополнительные материалы](#Дополнительные-материалы-8) + [`this` в JavaScript](#-this-в-javascript) - [Дополнительные материалы](#Дополнительные-материалы-9) + [Класс](#Класс) - [Примеры](#Примеры) - [Дополнительные материалы](#Дополнительные-материалы-10) + [Ключевые слова Extends и super](#Ключевые-слова-extends-и-super) - [Пример кода](#Пример-кода-6) - [Дополнительные материалы](#Дополнительные-материалы-11) + [Async Await](#async-await) - [Пример кода](#Пример-кода-7) - [Объяснение с помощью примера кода](#Объяснение-с-помощью-примера-кода-1) - [Обработка ошибок](#Обработка-ошибок) - [Дополнительные материалы](#Дополнительные-материалы-12) + [Истина / Ложь](#Истина--Ложь) - [Дополнительные материалы](#Дополнительные-материалы-13) + [Анаморфизмы и катаморфизмы](#Анаморфизмы-и-катаморфизмы) - [Анаморфизмы](#Анаморфизмы) * [Пример кода](#Пример-кода-8) - [Катаморфизмы](#Катаморфизмы) * [Пример кода](#Пример-кода-9) - [Дополнительные материалы](#Дополнительные-материалы-14) + [Генераторы](#Генераторы) - [Пример кода](#Пример-кода-10) - [Дополнительные материалы](#Дополнительные-материалы-15) + [Статические методы](#Статические-методы) - [Краткое объяснение](#Краткое-объяснение-1) - [Пример кода](#Пример-кода-11) - [Подробное объяснение](#Подробное-объяснение-2) * [Вызов статических методов из статического метода](#Вызов-статических-методов-из-статического-метода) * [Вызов статических методов из нестатических методов](#Вызов-статических-методов-из-нестатических-методов) - [Дополнительные материалы](#Дополнительные-материалы-16) * [Глоссарий](#Глоссарий) + [Область видимости](#-Область-видимости) + [Изменение переменных](#-Изменение-переменных) ## Понятия ### Объявление переменных: `var`, `const`, `let` В JavaScript есть три ключевых слова, отвечающих за объявление переменных, и у каждого из них свои особенности. Эти слова − `var`, `let` и `const`. #### Краткое объяснение Переменным, объявленным с помощью ключевого слова `const`, нельзя позже присвоить новое значение, в то время как переменным, объявленным с помощью `let` или `var`, можно. Я рекомендую всегда объявлять переменные ключевым словом `const`, а `let` использовать только в том случае, если позже эту переменную понадобится *изменить* или переопределить.
Область видимости Можно переопределять Можно изменять Временная мертвая зона
`const` Блок Нет Да Да
`let` Блок Да Да Да
`var` Функция Да Да Нет
#### Пример кода ```js const person = "Коля"; person = "Ваня" // Вызовет ошибку, переменной person нельзя присвоить новое значение. ``` ```js let person = "Коля"; person = "Ваня"; console.log(person) // -> "Ваня", присвоение нового значения разрешено в случае с let. ``` #### Подробное объяснение [*Область видимости*](#scope_def) переменной определяет, где эта переменная доступна в коде. ##### `var` Областью видимости переменных, объявленных с помощью `var`, является функция. Это означает, что если переменная была создана внутри функции, то у всего внутри этой функции есть доступ к данной переменной. Кроме того, переменная с областью видимости внутри функции недоступна за пределами этой функции. Можно думать об этом вот так: если у переменной область видимости *Х*, то эта переменная — как бы свойство Х. ```js function myFunction() { var myVar = "Коля"; console.log(myVar); // -> "Коля" — myVar доступна внутри функции. } console.log(myVar); // ReferenceError, myVar недоступна снаружи функции. ``` Вот менее очевидный пример области видимости переменных: ```js function myFunction() { var myVar = "Коля"; if (true) { var myVar = "Ваня"; console.log(myVar); // -> "Ваня" /* На самом деле, область видимости myVar — функция, мы всего лишь удалили предыдущее значение переменной myVar "Коля" и заменили его на "Ваня". */ } console.log(myVar); // -> "Ваня" — обратите внимание, как код в блоке if повлиял на это значение. } console.log(myVar); // -> /* ReferenceError, переменная myVar недоступна за пределами функции, в которой определена. */ ``` Кроме этого, переменные, объявленные с помощью ключевого слова `var`, при выполнении кода перемещаются в начало области видимости. Это называется [поднятие переменных](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/var#Поднятие_переменных). Этот фрагмент кода: ```js console.log(myVar) // -> undefined — ошибок нет. var myVar = 2; ``` при выполнении понимается как: ```js var myVar; console.log(myVar) // -> undefined — ошибок нет. myVar = 2; ``` ##### `let` `var` и `let` примерно одинаковы, в то время как переменные, объявленные словом `let`: - имеют в качестве области видимости блок; - **недоступны** до объявления; - не могут быть повторно объявлены в той же области видимости. Давайте разберемся, в чем особенности блочной области видимости, используя предыдущий пример: ```js function myFunction() { let myVar = "Коля"; if (true) { let myVar = "Ваня"; console.log(myVar); // -> "Ваня" /* Поскольку myVar имеет блочную область видимости, здесь мы только что создали новую переменную myVar. Эта переменная недоступна вне блока и никак не зависит от первой переменной myVar, которую мы создали до этого! */ } console.log(myVar); // -> "Коля" — обратите внимание: инструкции в блоке if НЕ повлияли на значение переменной. } console.log(myVar); // -> ReferenceError, myVar недоступна за пределами функции. ``` Теперь разберемся, что значит «переменные, объявленные с помощью `let` и `const`, недоступны до их объявления»: ```js console.log(myVar) // Вызовет ReferenceError! let myVar = 2; ``` В отличие от переменных, объявленных через `var`, попытка обратиться к переменной `let` или `const` до её объявления вызовет ошибку. Этот феномен часто называют [*Временной мёртвой зоной*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let). > **Примечание:** строго говоря, объявления переменных с использованием `let` и `const` тоже поднимаются, однако их инициализация — нет. Они сделаны так, что использовать их до инициализации нельзя. Поэтому интуитивно кажется, что такие переменные не поднимаются, но на самом деле это не так. Больше информации можно найти в [этом очень подробном объяснении](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified). В дополнение к сказанному: нельзя повторно объявить переменную, объявленную с помощью `let`: ```js let myVar = 2; let myVar = 3; // Вызовет SyntaxError. ``` ##### `const` Переменные, объявленные через `const`, ведут себя так же, как переменные, объявленные через `let`, но к тому же их нельзя переопределять. Итак, переменные, объявленные с помощью `const`: - имеют в качестве области видимости блок; - недоступны до объявления; - не могут быть повторно объявлены в той же области видимости; - не могут быть переопределены. ```js const myVar = "Коля"; myVar = "Ваня" // Вызовет ошибку, переопределять переменную нельзя. ``` ```js const myVar = "Коля"; const myVar = "Ваня" // Вызовет ошибку, объявить переменную можно только один раз. ``` Но есть одна тонкость: переменные, объявленные с помощью `const`, не являются [**неизменными**](#mutation_def)! А именно, это означает, что *объекты* и *массивы*, объявленные с помощью `const`, **могут** быть изменены. В случае объектов: ```js const person = { name: 'Коля', }; person.name = 'Ваня'; // Сработает! Переменная person не полностью переопределяется, а просто меняется. console.log(person.name); // -> "Ваня" person = "Сандра"; // Вызовет ошибку, потому что переменные, объявленные через const, переопределять нельзя. ``` В случае массивов: ```js const person = []; person.push('Ваня'); // Сработает! Переменная person не полностью переопределяется, а просто меняется. console.log(person[0]); // -> "Ваня" person = ["Коля"]; // Вызовет ошибку, потому что переменные, объявленные через const, переопределять нельзя. ``` #### Дополнительные материалы - [How let and const are scoped in JavaScript — WesBos](http://wesbos.com/javascript-scoping/). - [Temporal dead zone (tdz) demystified](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified). ### Стрелочные функции В обновлении JavaScript ES6 добавлены *стрелочные функции* — новый синтаксис записи функций. Вот некоторые их преимущества: - краткость; - `this` берется из окружающего контекста; - неявный возврат. #### Пример кода - Краткость и неявный возврат. ```js function double(x) { return x * 2; } // Обычный способ. console.log(double(2)); // -> 4 ``` ```js const double = x => x * 2; /* Та же функция, записанная в виде стрелочной функции с неявным возвратом. */ console.log(double(2)); // -> 4 ``` - Использование `this`. Внутри стрелочной функции значение `this` такое же, как и во внешней области видимости. В принципе, со стрелочными функциями вам больше не нужно прибегать к хаку `that = this` перед вызовом функции внутри функции. ```js function myFunc() { this.myVar = 0; setTimeout(() => { this.myVar++; console.log(this.myVar); // -> 1 }, 0); } ``` #### Подробное объяснение ##### Краткость Стрелочные функции во многих отношениях более краткие, чем обычные. Рассмотрим все возможные случаи: - Явный и неявный возврат. Функция может **явно возвращать** результат с использованием ключевого слова `return`. ```js function double(x) { return x * 2; // Эта функция явно возвращает x * 2, использовано ключевое слово *return*. } ``` При обычном способе написания функций возврат всегда был явным. Со стрелочными функциями его можно сделать *неявным*. Это значит, что для возврата значения не нужно использовать ключевое слово `return`. ```js const double = (x) => { return x * 2; // Явный возврат. } ``` Поскольку здесь нет ничего, кроме возвращаемого значения, можно вернуть значение без явного указания. ```js const double = (x) => x * 2; // Всё верно, вернётся x * 2. ``` Для этого нам просто нужно **убрать фигурные скобки** и ключевое слово `return`. Поэтому это и называется *неявным* возвратом: ключевого слова `return` нет, но функция все равно вернет `x * 2`. > **Примечание**: Если ваша функция не возвращает никакого значения (с *побочными эффектами*), то в ней нет ни явного, ни неявного возврата. Кроме того, если вы хотите неявно вернуть *объект*, вы **должны заключить его в круглые скобки**, так как иначе он будет конфликтовать с фигурными скобками блоков: ```js const getPerson = () => ({ name: "Коля", age: 24 }) console.log(getPerson()) // { name: "Коля", age: 24 } — объект, неявно возвращенный стрелочной функцией. ``` - Только один аргумент. Если ваша функция принимает только один аргумент, то скобки вокруг него можно опустить. Возвращаясь к функции `double` в коде выше: ```js const double = (x) => x * 2; // Эта стрелочная функция принимает только один аргумент. ``` Скобки вокруг этого аргумента можно опустить: ```js const double = x => x * 2; // Эта стрелочная функция принимает только один аргумент. ``` - Без аргументов. Когда стрелочная функция вообще не принимает никаких аргументов, нужно использовать пустые круглые скобки, иначе синтаксис будет неправильным. ```js () => { // Скобки есть, все хорошо. const x = 2; return x; } ``` ```js => { // Скобок нет, так работать не будет! const x = 2; return x; } ``` ##### Использование `this` Чтобы понять эту тонкость поведения стрелочных функций, нужно понимать, как [`this`](#this_def) ведёт себя в JavaScript. Внутри стрелочной функции значение `this` равно значению `this` внешнего окружения. Это значит, что стрелочная функция не создает новый `this`, а получает его из окружения. Без использования стрелочных функций для получения доступа к переменной через `this` в функции, вложенной в другую функцию, придется использовать хак `that = this` или `self = this`. Вот, к примеру, использование функции `setTimeout` внутри функции `myFunc`: ```js function myFunc() { this.myVar = 0; var that = this; // Тот самый хак *that = this* setTimeout( function() { // В этой области видимости функции создается новый *this*. that.myVar++; console.log(that.myVar); // -> 1 console.log(this.myVar); // -> undefined — см. объявление функции выше. }, 0 ); } ``` Но в случае стрелочных функций `this` берется из окружения: ```js function myFunc() { this.myVar = 0; setTimeout( () => { // this берется из окружения. В данном случае — из myFunc. this.myVar++; console.log(this.myVar); // -> 1 }, 0 ); } ``` #### Полезные ресурсы - [JavaScript Arrow Functions Introduction — WesBos](http://wesbos.com/arrow-functions/). - [Стрелочные функции в JavaScript — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions). - [Javascript ES6 — Arrow Functions and Lexical `this`](https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4). ### Значение аргументов функции по умолчанию Начиная с обновления JavaScript ES2015, аргументам функции можно присваивать значения по умолчанию, используя следующий синтаксис: ```js function myFunc(x = 10) { return x; } console.log(myFunc()); /* -> 10 — никакое значение не передается, поэтому в myFunc х присваивается значение по умолчанию, т.е. 10 */ console.log(myFunc(5)); /* -> 5 — передается значение, поэтому в myFunc х присваивается значение 5 */ console.log(myFunc(undefined)); /* -> 10 — передается значение undefined, поэтому х присваивается значение по умолчанию */ console.log(myFunc(null)); // -> null — передается значение null. Подробнее см. ниже. ``` Значения по умолчанию применяются только в двух случаях: - значение не передано; - передано значение `undefined`. Другими словами, если передать в функцию параметр `null`, то параметр по умолчанию **не применится**. > **Примечание:** Присваивать значение по умолчанию можно в том числе и при работе с деструктурированными параметрами (см. пример в следующем понятии). #### Дополнительные материалы - [Extended Parameter Handling](http://es6-features.org/#DefaultParameterValues). - [Параметры по умолчанию — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Default_parameters). ### Деструктуризация объектов и массивов **Деструктуризация** — это удобный способ создания новых переменных путем извлечения значений из объектов или массивов. На практике *деструктуризацию* можно использовать, чтобы присваивать переменным разбитые на части параметры функции или `this.props` в React-проектах. #### Объяснение с помощью примера кода - Объект. Давайте использовать во всех примерах следующий объект: ```js const person = { firstName: "Коля", lastName: "Андреев", age: 35, sex: "М", }; ``` Без деструктуризации: ```js const first = person.firstName; const age = person.age; const city = person.city || "Санкт-Петербург"; ``` С деструктуризацией всё поместится в одну строку: ```js const { firstName: first, age, city = "Санкт-Петербург" } = person; // И всё! console.log(age); /* -> 35 — Создана новая переменная age, и ей присвоено значение, равное person.age. */ console.log(first); /* -> "Коля" — Создана новая переменная first, и ей присвоено значение, равное person.firstName. */ console.log(firstName); /* -> ReferenceError — person.firstName существует, НО новая созданная переменная называется first. */ console.log(city); /* -> "Санкт-Петербург" — Создана новая переменная city, и, поскольку свойство person.city ранее не было определено, переменной присвоено альтернативное значение "Санкт-Петербург". */ ``` > **Примечание:** В `const { age } = person;` скобки после ключевого слова `const` используются не для обозначения объекта или блока. Это синтаксис *деструктуризации*. - Параметры функции. Деструктуризация часто используется для разбиения параметров функции на части. Без деструктуризации: ```js function joinFirstLastName(person) { const firstName = person.firstName; const lastName = person.lastName; return `${firstName}—${lastName}`; } joinFirstLastName(person); // -> "Коля-Андреев" ``` Если деструктурировать параметр `person`, то функция получится куда более лаконичной: ```js function joinFirstLastName({ firstName, lastName }) { /* Мы создали переменные firstName и lastName из частей параметра person. */ return `${firstName}—${lastName}`; } joinFirstLastName(person); // -> "Коля-Андреев" ``` Ещё удобнее использовать деструктуризацию со [стрелочными функциями](#arrow_func_concept): ```js const joinFirstLastName = ({ firstName, lastName }) => `${firstName}—${lastName}`; joinFirstLastName(person); // -> "Коля-Андреев" ``` - Массив. Давайте рассмотрим следующий массив: ```js const myArray = ["a", "b", "c"]; ``` Без деструктуризации: ```js const x = myArray[0]; const y = myArray[1]; ``` С использованием деструктуризации: ```js const [x, y] = myArray; // Вот и всё! console.log(x); // -> "a" console.log(y); // -> "b" ``` #### Полезные ресурсы - [Destructuring Assignment](http://es6-features.org/#ArrayMatching). - [Destructuring Assignment - WesBos](http://wesbos.com/destructuring-objects/). - [ExploringJS — Destructuring](http://exploringjs.com/es6/ch_destructuring.html). ### Методы массивов — `map` / `filter` / `reduce` `map`, `filter` и `reduce` — это методы массивов, пришедшие из парадигмы [*функционального программирования*](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0). Перечислю их: - `Array.prototype.map()` принимает массив, каким-нибудь образом преобразует его элементы и возвращает новый массив трансформированных элементов. - `Array.prototype.filter()` принимает массив, просматривает каждый элемент и решает, убрать его или оставить. Возвращает массив оставшихся значений. - `Array.prototype.reduce()` принимает массив и вычисляет на основе его элементов какое-то единое значение, которое и возвращает. Я рекомендую пользоваться ими как можно чаще, следуя принципам функционального программирования, потому что они лаконичные, элегантные и их можно комбинировать. Вооружившись этими тремя методами, вы можете обойтись без использования `for` и `forEach` в большинстве ситуаций. Когда в следующий раз соберётесь запустить цикл `for`, попробуйте решить задачу с помощью `map`, `filter` и `reduce`. Поначалу это будет трудно, потому что вам придётся научиться мыслить по-другому, но, разобравшись один раз, вы сможете применять эти методы без особых усилий. #### Пример кода ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; const doubledNumbers = numbers.map(n => n * 2); // -> [0, 2, 4, 6, 8, 10, 12] const evenNumbers = numbers.filter(n => n % 2 === 0); // -> [0, 2, 4, 6] const sum = numbers.reduce((prev, next) => prev + next, 0); // -> 21 ``` Давайте посчитаем сумму баллов всех студентов, которые набрали больше 10 баллов, используя `map`, `filter` и `reduce`: ```js const students = [ { name: "Коля", grade: 10 }, { name: "Ваня", grade: 15 }, { name: "Юля", grade: 19 }, { name: "Наташа", grade: 9 }, ]; const aboveTenSum = students .map(student => student.grade) // Создаём массив оценок из массива студентов с помощью метода map. .filter(grade => grade >= 10) // Выбираем только оценки выше 10 при помощи метода filter. .reduce((prev, next) => prev + next, 0); // Суммируем все оценки выше 10 друг с другом. console.log(aboveTenSum); /* -> 44: 10 (Коля) + 15 (Ваня) + 19 (Юля), оценка Наташи меньше 10 и была проигнорирована */ ``` #### Объяснение Давайте использовать в качестве примера следующий массив: ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; ``` ##### `Array.prototype.map()` ```js const doubledNumbers = numbers.map(function(n) { return n * 2; }); console.log(doubledNumbers); // -> [0, 2, 4, 6, 8, 10, 12] ``` Что же здесь происходит? Мы применяем к массиву `numbers` метод `map`, который взаимодействует с каждым элементом массива, передавая его в нашу функцию. Цель функции — произвести расчёт и вернуть новое значение, чтобы `map` мог подставить его вместо переданного в функцию. Давайте даже вынесем функцию из массива, чтобы было понятнее, что происходит: ```js const doubleN = function(n) { return n * 2; }; const doubledNumbers = numbers.map(doubleN); console.log(doubledNumbers); // -> [0, 2, 4, 6, 8, 10, 12] ``` `numbers.map(doubleN)` создаёт `[doubleN(0), doubleN(1), doubleN(2), doubleN(3), doubleN(4), doubleN(5), doubleN(6)]`, что равняется `[0, 2, 4, 6, 8, 10, 12]`. > **Примечание:** Если вам не нужно возвращать новый массив и вы просто хотите перебрать существующий массив, совершая с его элементами некоторые действия, можете просто использовать `for` / `forEach` вместо метода `map`. ##### `Array.prototype.filter()` ```js const evenNumbers = numbers.filter(function(n) { return n % 2 === 0; // Истинно, если n чётное; ложно, если n нечётное. }); console.log(evenNumbers); // -> [0, 2, 4, 6] ``` Мы применяем `filter` к массиву `numbers`. Метод `filter` взаимодействует с каждым элементом массива и передаёт его в нашу функцию. Функция возвращает булево значение, определяющее, будет ли элемент сохранён в массиве. Затем `filter` возвращает массив отфильтрованных значений. ##### `Array.prototype.reduce()` Цель метода `reduce` заключается в том, чтобы вычислить на основе массива какое-то одно значение. Какие именно вычисления метод произведет с элементами, зависит только от вас. ```js const sum = numbers.reduce( function(acc, n) { return acc + n; }, 0 // Значение аккумулирующей переменной на первом шаге цикла. ); console.log(sum); // -> 21 ``` Так же, как методы `.map` и `.filter`, метод `.reduce` применяется к массиву и в качестве первого параметра принимает функцию. На этот раз, впрочем, кое-что изменилось: - `.reduce` принимает два параметра. Первый параметр — это функция, которая будет вызываться на каждом шаге цикла. Второй параметр — это значение аккумулирующей переменной (`acc` в нашем случае) на первом шаге цикла (чтобы разобраться, читайте далее). - Параметры функции. Функция, которую вы передаёте в качестве первого параметра метода `.reduce`, принимает два аргумента. Первый аргумент — это аккумулирующая переменная (`acc` в нашем примере), второй аргумент — текущий элемент. Аккумулирующая переменная равна значению, возвращённому нашей функцией на **предыдущем** шаге цикла. В самом начале каждого цикла `acc` равна значению, которое было передано в качестве второго параметра `.reduce`. ###### На первом шаге `acc = 0`, потому что мы передали `0` в качестве второго параметра метода `reduce`. `n = 0` — первый элемент массива `number`. Функция возвращает `acc` + `n` --> 0 + 0 --> 0. ###### На втором шаге `acc = 0`, потому что это значение функция вернула на предыдущем шаге. `n = 1` — второй элемент массива `number`. Функция возвращает `acc` + `n` --> 0 + 1 --> 1. ###### На третьем шаге `acc = 1`, потому что это значение функция вернула на предыдущем шаге. `n = 2` — третий элемент массива `number`. Функция возвращает `acc` + `n` --> 1 + 2 --> 3. ###### На четвертом шаге `acc = 3`, потому что это значение функция вернула на предыдущем шаге. `n = 3` — четвёртый элемент массива `number`. Функция возвращает `acc` + `n` --> 3 + 3 --> 6. ###### На последнем шаге `acc = 15`, потому что это значение функция вернула на предыдущем шаге. `n = 6` — последний элемент массива `number`. Функция возвращает `acc` + `n` --> 15 + 6 --> 21. Поскольку это был последний шаг, `.reduce` возвращает `21`. #### Дополнительные материалы - [Understanding map, filter and reduce in JavaScript](https://hackernoon.com/understanding-map-filter-and-reduce-in-javascript-5df1c7eee464). ### Оператор расширения `...` Оператор расширения `...`, появившийся в ES2015, предназначен для развертывания итерируемых объектов (например, массивов) в тех местах, где можно поместить несколько элементов. #### Пример кода ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // -> ["a", "b", "c", "d", "e", "f"] ``` ```js function myFunc(x, y, ...params) { console.log(x); // -> "a" console.log(y); // -> "b" console.log(params); // -> ["c", "d", "e", "f"] } myFunc("a", "b", "c", "d", "e", "f"); // "a" // "b" // ["c", "d", "e", "f"] ``` ```js const { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(x); // -> 1 console.log(y); // -> 2 console.log(z); // -> { a: 3, b: 4 } const n = { x, y, ...z }; console.log(n); // -> { x: 1, y: 2, a: 3, b: 4 } ``` #### Объяснение ##### В итерируемых объектах (например, массивах) Если у нас есть два следующих массива: ```js const arr1 = ["a", "b", "c"]; const arr2 = [arr1, "d", "e", "f"]; // -> [["a", "b", "c"], "d", "e", "f"] ``` Первый элемент массива `arr2` — это массив, потому что `arr1` напрямую вставляется в `arr2`. Но мы хотим, чтобы `arr2` состоял только из букв. Чтобы добиться этого, мы можем *развернуть* элементы массива `arr1` в массиве `arr2`. С использованием оператора расширения: ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // -> ["a", "b", "c", "d", "e", "f"] ``` ##### Оставшиеся аргументы функции Для объединения аргументов можно использовать оператор оставшихся аргументов функции. Этот оператор позволяет представить любое число аргументов в виде массива, элементы которого можно перебрать при помощи цикла. Вообще, к каждой функции уже привязан объект `arguments` — массив, состоящий из всех аргументов, переданных функции. ```js function myFunc() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } myFunc("Коля", "Андреев", 10, 12, 6); // "Коля" // "Андреев" // 10 // 12 // 6 ``` Но давайте представим, что мы хотим, чтобы наша функция создала нового студента со своими оценками и средним баллом. Удобнее будет записать первые два аргумента в две отдельные переменные, а все оценки поместить в массив, который можно перебирать. Именно это позволяет нам сделать оператор оставшихся аргументов! ```js function createStudent(firstName, lastName, ...grades) { /* firstName = "Коля" lastName = "Андреев" [10, 12, 6] — оператор `...` берет все остальные параметры, переданные функции, и создает переменную grades с массивом, в котором они хранятся. */ const avgGrade = grades.reduce((acc, curr) => acc + curr, 0) / grades.length; // Вычисляет средний балл из всех оценок. return { firstName: firstName, lastName: lastName, grades: grades, avgGrade: avgGrade, } } const student = createStudent("Коля", "Андреев", 10, 12, 6); console.log(student); /* { firstName: "Коля", lastName: "Андреев", grades: [10, 12, 6], avgGrade: 9,33 } */ ``` > **Примечание:** `createStudent` — плохая функция, потому что мы не проверяем, существует ли `grades.length` и отличается ли от 0. Но так функцию легче прочитать, поэтому я не учитывал эти случаи. ##### Расширение свойств объектов Чтобы понять эту часть, рекомендую прочитать предыдущие объяснения о применении оператора оставшихся аргументов к итерируемым объектам и параметрам функций. ```js const myObj = { x: 1, y: 2, a: 3, b: 4 }; const { x, y, ...z } = myObj; // Деструктуризация объекта. console.log(x); // -> 1 console.log(y); // -> 2 console.log(z); // -> { a: 3, b: 4 } // z - это остаток от деструктурированного объекта: объект myObj минус деструктурированные свойства х и у. const n = { x, y, ...z }; console.log(n); // -> { x: 1, y: 2, a: 3, b: 4 } // Здесь свойства объекта z расширяются в n ``` #### Дополнительные материалы - [TC39 — Object Rest/Spread Properties for ECMAScript](https://github.com/tc39/proposal-object-rest-spread). - [Spread Operator Introduction — WesBos](https://github.com/wesbos/es6-articles/blob/master/28%20-%20Spread%20Operator%20Introduction.md). - [JavaScript & The spread operator](https://codeburst.io/javascript-the-spread-operator-a867a71668ca). - [6 Great Uses of the Spread Operator](https://davidwalsh.name/spread-operator). ### Сокращенная запись свойств объектов При записи переменной в свойство объекта, если у переменной то же имя, что и у свойства, можно сделать следующее: ```js const x = 10; const myObj = { x }; console.log(myObj.x) // -> 10 ``` #### Объяснение Раньше (до ES2015), если вы хотели при объявлении нового *литерала объекта* использовать переменные в качестве его свойств, вам пришлось бы писать подобный код: ```js const x = 10; const y = 20; const myObj = { x: x, // Запись значения переменной х в myObj.x. y: y, // Запись значения переменной у в myObj.y. }; console.log(myObj.x); // -> 10 console.log(myObj.y); // -> 20 ``` Как видите, приходится повторять одно и то же, потому что имена свойств объекта совпадают с именами переменных, которые вы хотите записать в эти свойства. С ES2015, если имя переменной совпадает с именем свойства, можно использовать такую сокращенную запись: ```js const x = 10; const y = 20; const myObj = { x, y, }; console.log(myObj.x); // -> 10 console.log(myObj.y); // -> 20 ``` #### Дополнительные материалы - [Enhanced Object Properties — ES6 Features](http://es6-features.org/#PropertyShorthand). ### Промисы **Промис (promise)** — это объект, который может быть синхронно возвращён из асинхронной функции ([Ссылка](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#3cd0)). Промисы могут использоваться, чтобы избежать [«ада обратных вызовов»](http://callbackhell.com/), и они всё чаще и чаще используются в современных JavaScript-проектах. #### Пример кода ```js const fetchingPosts = new Promise((res, rej) => { $.get("/posts") .done(posts => res(posts)) .fail(err => rej(err)); }); fetchingPosts .then(posts => console.log(posts)) .catch(err => console.log(err)); ``` #### Пояснение Когда вы делаете *AJAX-запрос*, ответ будет несинхронным, так как вы запрашиваете ресурс, на обработку которого требуется некоторое время. Ответ может быть вообще не получен, если запрашиваемый ресурс недоступен по какой-то причине (404). Чтобы избежать таких ситуаций, в ES2015 были добавлены *промисы*. Промисы могут иметь 3 различных состояния: - выполняется; - выполнено; - отклонено. Предположим, мы хотим использовать промисы для обработки AJAX-запроса для получения ресурса X. ##### Создание промиса Сначала создадим промис. Будем использовать GET-метод jQuery для создания AJAX-запроса к ресурсу X. ```js const xFetcherPromise = new Promise( // Создаём промис с помощью ключевого слова new и сохраняем его в переменную function(resolve, reject) { /* Конструктор промиса принимает в виде параметра функцию, которая, в свою очередь, принимает 2 параметра: resolve и reject. */ $.get("X") // Запускаем AJAX-запрос .done(function(X) { // Как только запрос выполнен... resolve(X); // ... выполняем промис со значением X в качестве параметра. }) .fail(function(error) { // Если запрос не прошёл... reject(error); // ... отклоняем промис со значением error. }); } ) ``` Как видно из рассмотренного примера, объект Promise принимает функцию-*исполнитель*, в свою очередь принимающую два параметра: `resolve` и `reject`. Эти параметры — функции, которые при вызове изменяют состояние промиса со значения *выполняется* на *выполнено* или *отклонено* соответственно. Промис находится в состоянии *выполняется* после создания экземпляра, и его функция-*исполнитель* выполняется немедленно. Как только одна из функций *выполнено* или *отклонено* вызвана в функции-*исполнителе*, промис вызовет связанные с ним обработчики. ##### Использование обработчиков промисов Чтобы получить результат (или ошибку) промиса, нужно назначить ему обработчики следующим образом: ```js xFetcherPromise .then(function(X) { console.log(X); }) .catch(function(err) { console.log(err); }) ``` Если вызов прошёл успешно, вызывается `resolve` и выполняется функция, переданная в метод `.then`. Если вызов не прошёл, вызывается `reject` и выполняется функция, переданная в `.catch`. > **Примечание:** Если промис уже выполнен или отклонён на момент назначения соответствующего обработчика, обработчик всё равно будет вызван. Так что между выполнением асинхронной операции и назначением обработчиков не возникает состояние гонки. [(Ссылка: MDN)](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise) #### Дополнительные материалы - [JavaScript Promises for Dummies — Jecelyn Yeen](https://scotch.io/tutorials/javascript-promises-for-dummies). - [JavaScript Promise API — David Walsh](https://davidwalsh.name/promises). - [Using promises — MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises). - [Master the JavaScript Interview: What is a Promise? — Eric Elliott](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261). - [JavaScript Promises: an Introduction — Jake Archibald](https://developers.google.com/web/fundamentals/getting-started/primers/promises). - [Документация по промисам — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise). ### Шаблонные строки **Шаблонные строки** — это конструкции, позволяющие использовать вставку, или [*интерполяцию выражений*](https://en.wikipedia.org/wiki/String_interpolation), в однострочных и многострочных строках. Другими словами, это новый синтаксис записи строк, с которым удобно использовать любые выражения JavaScript (например, переменные). #### Пример кода ```js const name = "Коля"; `Привет, ${name}, следующее выражение равно четырем: ${2+2}.`; // -> Привет, Коля, следующее выражение равно четырем: 4. ``` #### Дополнительные материалы - [String Interpolation — Особенности ES6](http://es6-features.org/#StringInterpolation). - [Getting Literal With ES6 Template Strings — Addy Osmani](https://developers.google.com/web/updates/2015/01/ES6-Template-Strings). ### Тегированные шаблонные строки **Шаблонные теги** — это *функции, которые могут быть префиксом к [шаблонной строке](#Шаблонные-строки)*. Когда функция вызывается таким образом, первый параметр представляет собой массив *строк*, которые выводятся между интерполированными переменными, а последующие параметры — значения выражений, вставленных в строку. Для захвата всех этих значений используйте оператор расширения `...`. [(Ссылка: MDN)](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals). > **Примечание:** Известная библиотека, которая называется [стилизованные компоненты](https://www.styled-components.com/), основана на этой возможности. Ниже приведен пример работы тегированных шаблонных строк: ```js function highlight(strings, ...values) { const interpolation = strings.reduce((prev, current) => { return prev + current + (values.length ? "" + values.shift() + "" : ""); }, ""); return interpolation; } const meal = "круассаны"; const drink = "кофе"; highlight`Я люблю ${meal} с ${drink}.`; // -> Я люблю круассаны с кофе. ``` Более интересный пример: ```js function comma(strings, ...values) { return strings.reduce((prev, next) => { let value = values.shift() || []; value = value.join(", "); return prev + next + value; }, ""); } const snacks = ["яблоки", "бананы", "апельсины"]; comma`Я люблю ${snacks} на десерт.`; // -> Я люблю яблоки, бананы, апельсины на десерт. ``` #### Дополнительные материалы - [Tagged Template Literals — Wes Bos](http://wesbos.com/tagged-template-literals/). - [Библиотека common-tags](https://github.com/declandewet/common-tags). ### Импорт / экспорт Модули в ES6 используются для получения доступа к переменным и функциям из других модулей (файлов с кодом), причем экспорт этих переменных и функций должен быть четко обозначен в исходном модуле. Крайне рекомендую почитать ресурсы MDN об экспорте/импорте (см. Дополнительные материалы ниже), в них содержится четкая и полная информация. #### Объяснение с примером кода ##### Именованный экспорт Именованный экспорт используется для экспорта нескольких значений из модуля. > **Примечание:** Вы можете именовать экспорт только [объектами первого класса](https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82_%D0%BF%D0%B5%D1%80%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0), у которых есть имя. ```js // mathConstants.js export const pi = 3.14; export const exp = 2.7; export const alpha = 0.35; // ------------- // myFile.js import { pi, exp } from './mathConstants.js'; // Именованный импорт — с синтаксисом, похожим на деструктуризацию. console.log(pi) // -> 3.14 console.log(exp) // -> 2.7 // ------------- // mySecondFile.js import * as constants from './mathConstants.js'; // Все экспортированные значения записываются в переменную constants. console.log(constants.pi) // -> 3.14 console.log(constants.exp) // -> 2.7 ``` Хотя именованный импорт выглядит как *деструктуризация*, это не одно и то же. Кроме того, именованный импорт имеет другой синтаксис, не поддерживает значения по умолчанию и *глубокую* деструктуризацию. Кроме того, можно создавать псевдонимы, но их синтаксис будет отличаться от синтаксиса, используемого при деструктуризации: ```js import { foo as bar } from 'myFile.js'; // foo импортируется и записывается в новую переменную bar. ``` ##### Импорт / экспорт по умолчанию Что касается экспорта по умолчанию, то для каждого модуля (файла) может быть только один экспорт. Экспортом по умолчанию может быть функция, класс, объект или что-то еще. Это значение считается «основным», поскольку его будет проще всего импортировать. [Ссылка: MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/export#Description). ```js // coolNumber.js const ultimateNumber = 42; export default ultimateNumber; // ------------ // myFile.js import number from './coolNumber.js'; /* В переменную number автоматически попадает экспорт по умолчанию — вне зависимости от его имени в исходном модуле. */ console.log(number) // -> 42 ``` Экспорт функций: ```js // sum.js export default function sum(x, y) { return x + y; } // ------------- // myFile.js import sum from './sum.js'; const result = sum(1, 2); console.log(result) // -> 3 ``` #### Дополнительные материалы - [ES6 Modules in bulletpoints](https://ponyfoo.com/articles/es6#modules) - [Экспорт — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/export). - [Импорт — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/import). - [Understanding ES6 Modules](https://www.sitepoint.com/understanding-es6-modules/). - [Destructuring special case — import statements](https://ponyfoo.com/articles/es6-destructuring-in-depth#special-case-import-statements). - [Misunderstanding ES6 Modules — Kent C. Dodds](https://medium.com/@kentcdodds/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution-ad2d5ab93ce0). - [Modules in JavaScript](http://exploringjs.com/es6/ch_modules.html#sec_modules-in-javascript). ### `this` в JavaScript Оператор `this` в JavaScript ведет себя не так, как в других языках. В большинстве случаев он определяется тем, как вызвана функция ([Ссылка: MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/this)). Это сложное понятие с множеством тонкостей, так что я крайне рекомендую вам тщательно изучить приведенные ниже Дополнительные материалы. Я покажу вам, как сам лично определяю, чему равно `this`. Этому меня научила [вот эта статья Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/). ```js function myFunc() { ... } // После каждого выражения находим значение this в myFunc. myFunc.call("myString", "привет"); // myString — в this записывается значение первого параметра .call. // В non-strict-режиме. myFunc("привет"); // window — myFunc() — это синтаксический сахар для myFunc.call(window, "привет"). // В strict-режиме. myFunc("привет"); // undefined — myFunc() — это синтаксический сахар для myFunc.call(undefined, "привет"). ``` ```js var person = { myFunc: function() { ... } } person.myFunc.call(person, "test"); // person Object — в this записывается значение первого параметра call. person.myFunc("test"); // person Object — person.myFunc() — это синтаксический сахар для person.myFunc.call(person, "test"). var myBoundFunc = person.myFunc.bind("привет"); // Создает новую функцию, в которой мы записываем "привет" в значение this. person.myFunc("test"); // person Object — Метод bind не влияет на первоначальный метод. myBoundFunc("test"); // "hello" — myBoundFunc — это person.myFunc, в которой this привязана к "привет". ``` #### Дополнительные материалы - [Understanding JavaScript Function Invocation and "this" — Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/). - [`this` в JavaScript — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/this). ### Класс JavaScript — это язык, [основанный на прототипах](https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D1%82%D0%BE%D1%82%D0%B8%D0%BF%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) (в то время как, например, Java — язык, [основанный на классах](https://en.wikipedia.org/wiki/Class-based_programming)). В обновлении ES6 представлены классы JavaScript, которые являются синтаксическим сахаром для наследования на основе прототипов, а **не** новой моделью наследования на основе классов ([Ссылка](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Classes)). Если вы знакомы с классами в других языках, слово «класс» может ввести вас в заблуждение. Постарайтесь не делать предположений о работе классов в JavaScript на основе других языков. Считайте это совершенно другим понятием. Поскольку этот документ не является попыткой научить вас языку с нуля, я надеюсь, что вы знаете, что такое прототипы и как они себя ведут. Если нет, смотрите дополнительные материалы после примеров. #### Примеры До ES6, синтаксис на основе прототипов: ```js var Person = function(name, age) { this.name = name; this.age = age; }; Person.prototype.stringSentence = function() { return "Привет, меня зовут " + this.name + " и мне " + this.age; }; ``` Начиная с ES6, синтаксис на основе классов: ```js class Person { constructor(name, age) { this.name = name; this.age = age; } stringSentence() { return `Привет, меня зовут ${this.name} и мне ${this.age}`; } } const myPerson = new Person("Маша", 23); console.log(myPerson.age); // -> 23 console.log(myPerson.stringSentence()); // -> "Привет, меня зовут Маша и мне 23 ``` #### Дополнительные материалы Для понимания прототипов: - [Understanding Prototypes in JS — Yehuda Katz](http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/) - [A plain English guide to JS prototypes — Sebastian Porto](http://sporto.github.io/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/) - [Наследование и цепочка прототипов — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Inheritance_and_the_prototype_chain). Для понимания классов: - [ES6 Classes in Depth — Nicolas Bevacqua](https://ponyfoo.com/articles/es6-classes-in-depth) - [ES6 Features — Classes](http://es6-features.org/#ClassDefinition) - [Классы JavaScript — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Classes). ### Ключевые слова `Extends` и `super` Ключевое слово `extends` используется в объявлении класса или в выражениях класса для создания дочернего класса ([Ссылка: MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Classes/extends)). Дочерний класс наследует все свойства родительского класса и дополнительно может добавлять новые свойства или изменять унаследованные. Ключевое слово `super` используется для вызова функций родителя объекта, включая его конструктор. - В конструкторе ключевое слово `super` должно использоваться раньше, чем ключевое слово `this`. - Вызов `super()` вызывает конструктор родительского класса. Если вы хотите передать какие-то аргументы из конструктора класса в конструктор родительского класса, то нужно вызывать функцию следующим образом: `super(arguments)`. - Если у родительского класса есть метод `X` (даже статический), для его вызова в дочернем классе можно использовать `super.X()`. #### Пример кода ```js class Polygon { constructor(height, width) { this.name = 'Многоугольник'; this.height = height; this.width = width; } getHelloPhrase() { return `Привет, я — ${this.name}`; } } class Square extends Polygon { constructor(length) { /* Здесь вызывается конструктор родительского класса со значением length, передаваемым для переменных width и height класса Polygon. */ super(length, length); /* Примечание: в производных классах перед тем, как использовать 'this', нужно вызвать функцию super(), иначе это приведёт к ошибке. */ this.name = 'Квадрат'; this.length = length; } getCustomHelloPhrase() { const polygonPhrase = super.getHelloPhrase(); // Получение доступа к родительскому методу с помощью синтаксиса super.X(). return `${polygonPhrase} с длиной стороны ${this.length}`; } get area() { return this.height * this.width; } } const mySquare = new Square(10); console.log(mySquare.area) // -> 100 console.log(mySquare.getHelloPhrase()) /* -> 'Привет, я — Квадрат' Класс Square наследуется от класса Polygon и имеет доступ к его методам.*/ console.log(mySquare.getCustomHelloPhrase()) // -> 'Привет, я — Квадрат с длиной стороны' ``` > **Примечание**: Если бы мы попытались использовать `this` перед вызовом `super()` в классе Square, произошёл бы ReferenceError: ```js class Square extends Polygon { constructor(length) { this.height; // ReferenceError, сначала нужно вызывать super! /* Здесь вызывается конструктор родительского класса со значением length в качестве значений width и height класса Polygon. */ // Here, it calls the parent class' constructor with lengths super(length, length); /* Примечание: в производных класса super() должен быть вызван до использования 'this'. Иначе это приведёт к ошибке. */ this.name = 'Квадрат'; } } ``` #### Дополнительные материалы - [Extends — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Classes/extends). - [Оператор Super — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/super). - [Inheritance — MDN](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance). ### Async Await Помимо [Промисов](#Промисы) вам может встретиться еще один синтаксис для обработки асинхронного кода — `async`/`await`. Цель функций `async`/`await` — упростить синхронное использование промисов и выполнить какое-либо действие над группой промисов. Точно так же, как промисы похожи на структурированные функции обратного вызова, `async`/`await` похожи на комбинацию генераторов и промисов. ([Ссылка: MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/async_function)) > **Примечание:** перед тем как пытаться понять `async`/`await`, вы должны понимать, что такое промисы и как они работают, поскольку `async`/`await` основаны на промисах. > **Примечание 2:** [`await` должен использоваться в `async` функции](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9#f3f0), что означает, что вы не можете использовать `await` на верхнем уровне вашего кода, так как он не находится внутри async-функции. #### Пример кода ```js async function getGithubUser(username) { // Ключевое слово async позволяет использовать await в функции и означает, что функция возвращает промис. const response = await fetch(`https://api.github.com/users/${username}`); // «Синхронное» ожидание промиса перед переходом на новую строку. return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) /* Логирование пользователя — не может использовать синтаксис await, так как этот код не находится внутри async-функции. */ .catch(err => console.log(err)); // Если в нашей асинхронной функции возникнет ошибка, то мы перехватим ее здесь. ``` #### Объяснение с помощью примера кода `async`/`await` построены на промисах, но позволяют использовать более императивный стиль кода. Оператор `async` объявляет функцию как асинхронную, и данная функция всегда будет возвращать *промис*. В async-функции можно использовать оператор `await` для приостановки выполнения до тех пор, пока возвращаемый промис либо выполнится, либо будет отклонен. ```js async function myFunc() { // Можно использовать оператор await, так как это async-функция. return "hello world"; } myFunc().then(msg => console.log(msg)); // "Привет, мир!" — возвращаемое значение myFunc превращается в промис из-за оператора async. ``` Когда будет достигнут оператор `return` async-функции, промис выполняется с возвращаемым значением. Если внутри async-функции генерируется ошибка, состояние промиса изменится на `rejected`. Если async-функция не возвращает никакого значения, промис всё равно будет возвращен и выполнится без значения, когда выполнение async-функции будет завершено. Оператор `await` используется для ожидания выполнения *Промиса* и может быть использован только в теле async-функции. При этом выполнение кода приостанавливается, пока не будет выполнен промис. > **Примечание:** `fetch` — это функция, возвращающая промис, который позволяет выполнить AJAX-запрос. Давайте сначала посмотрим, как мы можем получить пользователя github с помощью промисов: ```js function getGithubUser(username) { return fetch(`https://api.github.com/users/${username}`).then(response => response.json()); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` Вот эквивалент с использованием `async`/`await`: ```js async function getGithubUser(username) { // Превращение в промис + разрешено использование ключевого слова await. const response = await fetch(`https://api.github.com/users/${username}`); // Выполнение останавливается здесь, пока не закончится выполнение промиса. return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` Синтаксис `async`/`await` особенно удобен для построения цепочек взаимозависимых промисов. Например, вам нужно получить токен для того, чтобы получить публикацию в блоге из базы данных, а затем информацию об авторе. > **Примечание:** Выражение `await` должно быть заключено в круглые скобки для вызова методов и свойств разрешенных значений в одной строке. ```js async function fetchPostById(postId) { const token = (await fetch('token_url')).json().token; const post = (await fetch(`/posts/${postId}?token=${token}`)).json(); const author = (await fetch(`/users/${post.authorId}`)).json(); post.author = author; return post; } fetchPostById('gzIrzeo64') .then(post => console.log(post)) .catch(err => console.log(err)); ``` ##### Обработка ошибок Если мы не добавим блок `try` / `catch` вокруг выражения `await`, неперехваченные исключения — неважно, были ли они выброшены в теле вашей async-функции или во время ожидания выполнения `await` — отклонят промис, возвращенный из async-функции. Использование состояния `throw` в асинхронной функции — то же самое, что возврат промиса, который был отклонен. [(Ссылка: PonyFoo)](https://ponyfoo.com/articles/understanding-javascript-async-await#error-handling). > **Примечание:** Промисы ведут себя так же! С помощью промисов вот как бы мы обработали ошибки: ```js function getUser() { // Этот промис будет отклонен! return new Promise((res, rej) => rej("Пользователь не найден!")); } function getAvatarByUsername(userId) { return getUser(userId).then(user => user.avatar); } function getUserAvatar(username) { return getAvatarByUsername(username).then(avatar => ({ username, avatar })); } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // -> "Пользователь не найден!" ``` Эквивалент с использованием `async`/`await`: ```js async function getUser() { // Возвращенный промис будет отклонен! throw "User not found !"; } async function getAvatarByUsername(userId) => { const user = await getUser(userId); return user.avatar; } async function getUserAvatar(username) { var avatar = await getAvatarByUsername(username); return { username, avatar }; } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // -> "Пользователь не найден!" ``` #### Дополнительные материалы - [Async/Await — JavaScript.Info](https://javascript.info/async-await). - [ES7 Async/Await](http://rossboucher.com/await/#/). - [6 Reasons Why JavaScript’s Async/Await Blows Promises Away](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9). - [JavaScript awaits](https://dev.to/kayis/javascript-awaits). - [Using Async Await in Express with Node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016). - [Функция Async](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/async_function). - [Await](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/await). - [Using async / await in express with node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016). ### Истина / Ложь В JavaScript «истинность» или «ложность» значения определяется при вычислении этого значения в булевом контексте. Примером булева контекста может быть вычисление в условии `if`. Любое значение будет приведено к `true` (истина), кроме: - `false` (ложь); - `0`; - `""` (пустая строка); - `null`; - `undefined`; - `NaN`. Вот примеры *булева контекста*: - значение условия `if`. ```js if (myVar) {} ``` Значение `myVar` может быть любым [объектом первого класса](https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82_%D0%BF%D0%B5%D1%80%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0) (переменная, функция, логическое значение), но оно будет преобразовано в логическое значение, поскольку вычисляется в булевом контексте. - После логического оператора **NOT** `!`. Этот оператор возвращает значение «ложь», если его единственный операнд может быть преобразован к значению «истина»; иначе он возвращает значение «истина». ```js !0 // -> «истина»: 0 — это «ложь», поэтому вернется "истина". !!0 // -> «ложь»: 0 — это «ложь», следовательно !0 возвращает истину, а !(!0) возвращает «ложь». !!"" // -> «ложь»: пустая строка — «ложь», поэтому НЕ (НЕ «ложь») равно «ложь». ``` - Конструктор объектов типа `Boolean`. ```js new Boolean(0); // «ложь» new Boolean(1); // «истина» ``` - Тернарный оператор. ```js myVar ? "истина" : "ложь" ``` Значение `myVar` вычисляется в булевом контексте. Будьте внимательны при сравнении двух значений. Значения объектов (которые должны быть приведены к истине), **не** приводятся к булеву типу, а приводятся к примитивному типу в соответствии со [спецификацией](http://javascript.info/object-toprimitive). Внутри, когда объект сравнивается с булевым значением, например, `[] == true`, выполняется `[].toString() == true`, происходит следующее: ```js let a = [] == true // a ложно, так как [].toString() возвращает пустую строку (""). let b = [1] == true // b истинно, так как [1].toString() возвращает "1". let c = [2] == true // c ложно, так как [2].toString() возвращает "2". ``` #### Дополнительные материалы - [Truthy (MDN)](https://developer.mozilla.org/en-US/docs/Glossary/Truthy). - [Falsy (MDN)](https://developer.mozilla.org/en-US/docs/Glossary/Falsy). - [Truthy and Falsy values in JS — Josh Clanton](http://adripofjavascript.com/blog/drips/truthy-and-falsy-values-in-javascript.html). ### Анаморфизмы и катаморфизмы #### Анаморфизмы Анаморфизмы — это фунции, которые отображают некоторый объект на более сложную структуру, содержащую тип объекта. Это процесс *разворачивания* простой структуры в более сложную. Рассмотрим разворачивание целого числа в список целых чисел. Целое число — наш изначальный объект, а список целых чисел — более сложная структура. ##### Пример кода ```js function downToOne(n) { const list = []; for (let i = n; i > 0; --i) { list.push(i); } return list; } downToOne(5) //-> [ 5, 4, 3, 2, 1 ] ``` #### Катаморфизмы Катаморфизмы противоположны анаморфизмам: они берут объекты более сложной структуры и *складывают* их в более простые структуры. Рассмотрим следующий пример функции `product`, которая принимает список целых чисел и возвращает простое целое число. ##### Пример кода ```js function product(list) { let product = 1; for (const n of list) { product = product * n; } return product; } product(downToOne(5)) // -> 120 ``` #### Дополнительные материалы - [Anamorphisms in JavaScript](http://raganwald.com/2016/11/30/anamorphisms-in-javascript.html). - [Anamorphism](https://en.wikipedia.org/wiki/Anamorphism). - [Catamorphism](https://en.wikipedia.org/wiki/Catamorphism). ### Генераторы Другой способ написания функции `downToOne` — использование генератора. Чтобы создать объект типа `Generator`, нужно использовать объявление `function *`. Генераторы — это функции, выполнение которых может быть прервано, а затем продолжено с тем же контекстом (привязками переменных), сохраняющимся при всех вызовах. Например, функция `downToOne` может быть переписана следующим образом: ```js function * downToOne(n) { for (let i = n; i > 0; --i) { yield i; } } [...downToOne(5)] // -> [ 5, 4, 3, 2, 1 ] ``` Генераторы возвращают итерируемый объект. Когда вызывается метод `next()` итератор, она выполняется до первого выражения `yield`, которое указывает значение, которое должно быть возвращено из итератора или с помощью `yield*`, которое дегегирует выполнение другому генератору. Когда в генераторе вызывается выражение `return`, он будет помечать генератор как выполненный и возвращать значение из выражения `return`. Дальнейшие вызовы `next()` не будут возвращать никаких новых значений. #### Пример кода ```js // Пример использования function * idMaker() { var index = 0; while (index < 2) { yield index; index = index + 1; } } var gen = idMaker(); gen.next().value; // -> 0 gen.next().value; // -> 1 gen.next().value; // -> undefined ``` Выражение `yield*` позволяет генератору вызывать другую функцию-генератор во время итерации. ```js // Пример использования yield * function * genB(i) { yield i + 1; yield i + 2; yield i + 3; } function * genA(i) { yield i; yield* genB(i); yield i + 10; } var gen = genA(10); gen.next().value; // -> 10 gen.next().value; // -> 11 gen.next().value; // -> 12 gen.next().value; // -> 13 gen.next().value; // -> 20 ``` ```js // Пример возврата из генератора function* yieldAndReturn() { yield "Y"; return "R"; yield "unreachable"; } var gen = yieldAndReturn() gen.next(); // -> { value: "Y", done: false } gen.next(); // -> { value: "R", done: true } gen.next(); // -> { value: undefined, done: true } ``` #### Дополнительные материалы - [Итераторы и генераторы — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Iterators_and_Generators#%D0%93%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D1%8B). ### Статические методы #### Краткое объяснение Ключевое слово `static` используется в классах для объявления статических методов. Статические методы — это функции в классе, которые принадлежат объекту класса и недоступны никаким экземплярам этого класса. #### Пример кода ```js class Repo { static getName() { return "Repo name is modern-js-cheatsheet"; } } // Обратите внимание, что нам не пришлось создавать экземпляр класса Repo. console.log(Repo.getName()); // Repo name is modern-js-cheatsheet let r = new Repo(); console.log(r.getName()); // Не пойманный TypeError: repo.getName не является функцией. ``` #### Подробное объяснение Статические методы можно вызвать в другом статическом методе, используя ключевое слово `this`, однако это не работает для нестатических методов. Нестатические методы не могут напрямую обращаться к статическим методам, используя ключевое слово `this`. ##### Вызов статических методов из статического метода. Для вызова статического метода из другого статического метода можно использовать ключевое слово `this` следующим образом: ```js class Repo { static getName() { return "Repo name is modern-js-cheatsheet"; } static modifyName(){ return `${this.getName()}-added-this`; } } console.log(Repo.modifyName()); // Repo name is modern-js-cheatsheet-added-this ``` ##### Вызов статических методов из нестатических методов Нестатические методы могут вызывать статические двумя способами: 1. Используя имя класса. Чтобы получить доступ к статическому методы из нестатического, используем имя класса и вызываем статический метод как обычное свойство, например, `ClassName.StaticMethodName`: ```js class Repo { static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ return `${Repo.getName()} and it contains some really important stuff`; } } // Нужно создать экземпляр класса для использования нестатических методов. let r = new Repo(); console.log(r.useName()); // Repo name is modern-js-cheatsheet and it contains some really important stuff ``` 2. Используя конструктор. Статические методы можно вызвать как свойства объекта-конструктора класса. ```js class Repo { static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ // Вызывает статический метод как обычное свойство конструктора. return `${this.constructor.getName()} and it contains some really important stuff`; } } // Нужно создать экземпляр класса для использования нестатических функций. let r = new Repo(); console.log(r.useName()); // Repo name is modern-js-cheatsheet and it contains some really important stuff ``` #### Дополнительные материалы - [Ключевое слово static — MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Classes/static). - [Static Methods- Javascript.info](https://javascript.info/class#static-methods). - [Static Members in ES6 — OdeToCode](http://odetocode.com/blogs/scott/archive/2015/02/02/static-members-in-es6.aspx). ## Глоссарий ### Область видимости Контекст, в котором переменная и выражения являются «видимыми» или могут быть получены. Если переменная или выражение находятся «вне текущей области видимости», значит, их нельзя использовать. Источник: [MDN](https://developer.mozilla.org/ru/docs/Glossary/Scope) ### Изменение переменных Говорят, что переменная изменилась, когда её значение изменилось относительно начального. ```js var myArray = []; myArray.push("firstEl") // Значение myArray изменено. ``` Переменная называется *неизменяемой*, если она не может быть изменена. Более подробно [смотрите в статье на MDN](https://developer.mozilla.org/ru/docs/Glossary/Mutable). ================================================ FILE: JavaScript/translations/th-TH.md ================================================ # Modern JavaScript Cheatsheet ![Modern JavaScript cheatsheet](https://i.imgur.com/aexPxMb.png) เครดิตรูปภาพ: [Ahmad Awais ⚡️](https://github.com/ahmadawais) ## เกริ่นนำ ### จุดประสงค์ เอกสารนี้เป็น cheatsheet ชุดคำสั่งของภาษา JavaScript ที่คุณได้พบเจอเป็นประจำใน​โปรเจ็คและโค้ดตัวอย่างใหม่ๆ บทความนี้ไม่ได้มีจุดประสงค์ในการสอน Javascript ตั้งแต่พื้นฐาน แต่ต้องการจะช่วยให้ Developer ที่มีพื้นฐานอยู่แล้วแต่อาจจะติดปัญหาในการเข้าใจในโค้ด Javascript สมัยใหม่ (ยกตัวอย่างเช่นกำลังเรียนรู้ React อยู่) เนื่องจากมีการใช้ concept ของ Javascript สมัยใหม่ นอกจากนี้ผมจะแนะนำเคล็ดลับส่วนตัว(ซึ่งอาจจะมีบางคนไม่เห็นด้วย)ใส่ไว้ในบางส่วน โดยจะมีหมายเหตุบอกเอาไว้ > **หมายเหตุ:** คอนเซปส่วนใหญ่ในนี้จะมาจากการอัปเดตใหม่ๆของ JavaScript (ES2015, หรือโดยทั่วไปเรียกว่า ES6). คุณสามารถดูฟีเจอร์ใหม่ๆของ Javascript ที่เพิ่มเข้ามาโดยสามารถติดตามได้จาก [ที่นี่](http://es6-features.org); ซึ่งเป็นเว็บไซต์ที่ดีทีเดียว ### แหล่งเรียนรู้ฟรีที่แนะนำเพิ่มเติม เมื่อติดปัญหาในการเข้าใจตรงจุดไหนแนะนำให้ลองหาคำตอบจากแหล่งข้อมูลเพิ่มเติมเหล่านี้ดูก่อน: - [MDN (Mozilla Developer Network)](https://developer.mozilla.org/en-US/search?q=) - [You don't know JS (book)](https://github.com/getify/You-Dont-Know-JS) - [ES6 Features with examples](http://es6-features.org) - [WesBos blog (ES6)](http://wesbos.com/category/es6/) - [Javascript Basics for Beginners](https://www.udacity.com/course/javascript-basics--ud804) - คอร์สฟรีจาก Udacity - [Reddit (JavaScript)](https://www.reddit.com/r/javascript/) - [Google](https://www.google.com/) to find specific blog and resources - [StackOverflow](https://stackoverflow.com/questions/tagged/javascript) ## สารบัญ - [Modern JavaScript cheatsheet](#modern-javascript-cheatsheet) * [เกริ่นนำ](#เกริ่นนำ) + [จุดประสงค์](#จุดประสงค์) + [แหล่งเรียนรู้ฟรีที่แนะนำเพิ่มเติม](#แหล่งเรียนรู้ฟรีที่แนะนำเพิ่มเติม) * [สารบัญ](#สารบัญ) * [เนื้อหา](#เนื้อหา) + [การประกาศตัวแปร: var, const, let](#การประกาศตัวแปร-var-const-let) - [อธิบายสั้นๆ](#อธิบายสั้นๆ) - [ตัวอย่างโค้ด](#ตัวอย่างโค้ด) - [อธิบายรายละเอียด](#อธิบายรายละเอียด) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก) + [Arrow ฟังก์ชั่น](#-arrow-ฟังก์ชั่น) - [ตัวอย่างโค้ด](#ตัวอย่างโค้ด-1) - [อธิบายรายละเอียด](#อธิบายรายละเอียด-1) * [การย่อสั้น](#การย่อสั้น) * [การอ้างอิงของ *this*](#การอ้างอิงของ-this) - [แหล่งข้อมูลที่มีประโยชน์](#แหล่งข้อมูลที่มีประโยชน์) + [ค่า default parameter ของฟังก์ชั่น](#ค่า-default-parameter-ของฟังก์ชั่น) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-1) + [Destructuring objects และ arrays](#destructuring-objects-และ-arrays) - [อธิบายตัวอย่างโค้ด](#อธิบายตัวอย่างโค้ด) - [แหล่งข้อมูลที่มีประโยชน์](#แหล่งข้อมูลที่มีประโยชน์-1) + [Array methods - map / filter / reduce](#array-methods---map--filter--reduce) - [ตัวอย่างโค้ด](#ตัวอย่างโค้ด-2) - [อธิบาย](#อธิบาย) * [Array.prototype.map()](#arrayprototypemap) * [Array.prototype.filter()](#arrayprototypefilter) * [Array.prototype.reduce()](#arrayprototypereduce) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-2) + [Spread operator "..."](#spread-operator-) - [ตัวอย่างโค้ด](#ตัวอย่างโค้ด-3) - [อธิบาย](#อธิบาย-1) * [ใช้กับสิ่งที่สามารถวนลูปได้ (iterables) (แบบ arrays)](#ใช้กับสิ่งที่สามารถวนลูปได้-iterables-แบบ-arrays) * [Rest parameter ของฟังก์ชั่น](#rest-parameter-ของฟังก์ชั่น) * [Object properties spreading](#object-properties-spreading) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก) + [Object property shorthand](#object-property-shorthand) - [อธิบาย](#อธิบาย-2) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-1) + [Promises](#promises) - [ตัวอย่างโค้ด](#ตัวอย่างโค้ด-4) - [อธิบาย](#อธิบาย-3) * [การสร้าง Promise](#create-the-promise) * [การใช้งาน Promise handlers](#การใช้งาน-promise-handlers) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-2) + [Template literals](#template-literals) - [ตัวอย่างโค้ด](#ตัวอย่างโค้ด-5) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-3) + [Tagged Template Literals](#tagged-template-literals) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-4) + [Imports / Exports](#imports--exports) - [อธิบายตัวอย่างโค้ด](#อธิบายตัวอย่างโค้ด-1) * [Named exports](#named-exports) * [Default import / export](#default-import--export) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-5) + [JavaScript *this*](#-javascript-this) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-6) + [Class](#class) - [ตัวอย่าง](#samples) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-7) + [Async Await](#async-await) - [ตัวอย่างโค้ด](#ตัวอย่างโค้ด-6) - [อธิบายตัวอย่างโค้ด](#อธิบายตัวอย่างโค้ด-2) - [การจัดการกับ Error](#การจัดการกับ-error) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-8) + [Truthy / Falsy](#truthy--falsy) + [Static Methods](#static-methods) - [อธิบายสั้นๆ](#อธิบายสั้นๆ-1) - [ตัวอย่างโค้ด](#ตัวอย่างโค้ด-7) - [อธิบายรายละเอียด](#อธิบายรายละเอียด-2) * [เรียก static methods อื่นจาก static method](#เรียก-static-methods-อื่นจาก-static-method) * [เรียก static methods จาก non-static method](#เรียก-static-methods-จาก-non-static-method) - [ข้อมูลเพิ่มเติมจากภายนอก](#ข้อมูลเพิ่มเติมจากภายนอก-9) * [คำศัพธ์](#คำศัพธ์) + [Scope](#-scope) + [Variable mutation](#-variable-mutation) ## เนื้อหา ### การประกาศตัวแปร: var, const, let ใน JavaScript มีวิธีการประกาศตัวแปรได้ 3 แบบคือ ```var```, ```let``` และ ```const``` ซึ่งแต่ละแบบมีความแตกต่างกัน #### อธิบายสั้นๆ ตัวแปรที่ประกาศโดยใช้ ```const``` จะไม่สามารถถูก assign ค่าให้กับตัวแปรใหม่ได้ ในขณะที่ ```let``` กับ ```var``` สามารถทำได้ ผมแนะนำให้ประกาศตัวแปรด้วย ```const``` เสมอและค่อยเปลี่ยนเป็น ```let``` ถ้าคุณต้องการ*เปลี่ยนแปลงค่า (mutate)* หรือ assign ค่าให้ตัวแปรในภายหลัง
Scope สามารถ Assign ค่าใหม่ได้ สามารถเปลี่ยนแปลงค่าได้ Temporal Dead Zone
const Block ไม่ใช่ ใช่ ใช่
let Block ใช่ ใช่ ใช่
var Function ใช่ ใช่ ไม่ใช่
#### ตัวอย่างโค้ด ```javascript const person = "Nick"; person = "John" // จะ thrown error เพราะว่า person ไม่สามารถ assign ค่าใหม่ได้ ``` ```javascript let person = "Nick"; person = "John"; console.log(person) // "John", let จะยอมให้สามารถ assign ค่าใหม่ได้ ``` #### อธิบายรายละเอียด อธิบาย [*scope*](#scope_def) ของตัวแปรได้อย่างคร่าวๆ หมายถึง "ขอบเขตที่ตัวแปรสามารถใช้งานได้ภายในโค้ด" ##### var ตัวแปรที่ถูกประกาศด้วย ```var``` จะเป็น *function scoped* เมื่อตัวแปรถูกสร้างภายใน function โค้ดใน function นั้นสามารถเข้าถึงตัวแปรนั้นได้ และตัวแปร *function scoped* ที่ถูกสร้างใน function จะไม่สามารถถูกเข้าถึงจากภายนอก function ได้ แนะนำให้ลองจินตนาการดูว่าถ้าตัวแปรเป็นตัวแปร *X scoped* หมายความว่าตัวแปรนี้เป็น property ของ X เท่านั้น ```javascript function myFunction() { var myVar = "Nick"; console.log(myVar); // "Nick" - myVar จะสามารถเข้าถึงได้จากภายใน function } console.log(myVar); // จะเกิด ReferenceError เพราะ myVar ไม่สามารถเข้าถึงได้จากภายนอก function ``` ตัวอย่างเพิ่มเติมสำหรับเรื่อง scope ของตัวแปร ```javascript function myFunction() { var myVar = "Nick"; if (true) { var myVar = "John"; console.log(myVar); // "John" // จริงๆ แล้ว myvar เป็นตัวแปร function scoped เราแค่ได้ลบค่าตัวแปร myVar จาก "Nick" และเปลี่ยนเป็น "John" } console.log(myVar); // "John" - จะเห็นได้ว่าค่าได้ถูกเปลี่ยนไปแล้ว } console.log(myVar); // จะเกิด ReferenceError เพราะ myVar ไม่สามารถเข้าถึงได้จากภายนอก function ``` นอกจากนี้ตัวแปรที่ประกาสด้วย *var* จะถูกย้ายตอน execution ไปอยู่ด้านบนสุดของ scope และนี่คือสิ่งที่เราเรียกว่า [var hoisting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting). โค้ดตัวอย่างกรณีนี้: ```js console.log(myVar) // undefined -- ไม่มีการเกิด error var myVar = 2; ``` เพราะว่าตามความเข้าใจเวลา Execution จะเป็นแบบนี้: ```js var myVar; console.log(myVar) // undefined -- ไม่มีการเกิด error myVar = 2; ``` ##### let ```var``` และ ```let ``` จะคล้ายกันแต่ตัวแปรที่ประกาศด้วย ```let``` จะ - เป็น *block scoped* - จะ**ไม่สามารถ**เข้าถึงก่อนที่มันจะถูก assign ค่าได้ - ไม่สามารถประกาศตัวแปรซ้ำใน scope เดียวกันได้ ลองดูตัวอย่างเรื่องผลกระทบ (side effect) ของ block-scoping จากตัวอย่างก่อนหน้า ```javascript function myFunction() { let myVar = "Nick"; if (true) { let myVar = "John"; console.log(myVar); // "John" // จริงๆ แล้ว myVar เป็น block scoped เราสามารถสร้างตัวแปร myVar ใหม่ได้ // ตัวแปรนี้จะไม่สามารถเข้าถึงได้จากภายนอก block นี้และเป็นอิสระจากกัน // กับตัวแปร myVar ตัวแรกที่เราสร้าง ! } console.log(myVar); // "Nick", จะเห็นตามที่อธิบายข้างต้นว่าภายใน block ไม่ส่งผลกระทบกับค่านี้ } console.log(myVar); // จะเกิด ReferenceError เพราะ myVar จะไม่สามารถเข้าถึงได้จากภายนอก function ``` ตอนนี้น่าจะเข้าใจเหตุผลแล้วว่าทำไมตัวแปรที่ประกาศโดยใช้ *let* (และ *const*) ไม่สามารถเข้าถึงได้ก่อนจะถูก assign ค่า ```js console.log(myVar) // เกิด ReferenceError ! let myVar = 2; ``` สิ่งนี้จะแตกต่างกับตัวแปรที่ประกาศโดยใช้ *var* ถ้าเราพยายามที่จะอ่านหรือเขียนตัวแปรที่ประกาศโดย *let* หรือ *const* ก่อนที่ทำการ assign ค่าจะเกิด Error ทันที ปรากฏการณ์นี้มักถูกเรียกว่า [*Temporal dead zone*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let) หรือ *TDZ*. > **หมายเหตุ:** ในทางเทคนิคแล้ว การประกาศตัวแปร *let* กับ *const* เป็น hoisted เหมือนกัน, แต่ไม่ใช่กับการ assign ค่า ดังนั้นเมื่อมันไม่สามารถใช้งานได้ก่อน assign ค่าได้ทำให้ดูเหมือนว่าไม่มี hoisting แต่จริงๆ แล้วมันมี อ่าน[คำอธิบายเพิ่มเติมแบบละเอียดที่นี่](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) ถ้าคุณต้องการ เพิ่มเติม คุณไม่สามารถประกาศตัวแปรที่ประกาศด้วย *let* ซ้ำได้: ```js let myVar = 2; let myVar = 3; // เกิด SyntaxError ``` ##### const การประกาศตัวแปรโดยใช้ ```const``` จะเหมือนกับ *let* แต่ต่างตรงที่พวกมันจะไม่สามารถ assign ค่าซ้ำได้ สรุปสั้นๆ สำหรับตัวแปรที่ประกาศแบบ *const*: - เป็น *block scoped* - ไม่สามารถเข้าถึงได้ก่อนถูก assign ค่า - ไม่สามารถประกาศซ้ำได้ใน scope เดียวกัน - ไม่สามารถ assign ซ้ำได้ ```js const myVar = "Nick"; myVar = "John" // เกิด error เพราะไม่สามารถ assign ค่าซ้ำได้ ``` ```js const myVar = "Nick"; const myVar = "John" // เกิด error เพราะไม่สามารถประกาศตัวแปรซ้ำได้ ``` มีบางจุดที่ต้องระวัง: ตัวแปร ```const``` ไม่ใช่ [**immutable**](#mutation_def) ! อธิบายเพิ่มเติมคือตัวแปรที่ประกาศโดย ```const``` ที่เก็บค่าเป็น *object* และ *array* ค่าข้างใน**สามารถ**เปลี่ยนแปลงได้ สำหรับ objects: ```js const person = { name: 'Nick' }; person.name = 'John' // สามารถทำได้ ! ตัวแปร person ไม่ได้ถูก assign ใหม่ แต่ถูกแปลงค่าข้างใน console.log(person.name) // "John" person = "Sandra" // เกิด error เพราะว่าไม่สามารถ assign ค่าซ้ำได้สำหรับตัวแปรที่ประกาศด้วย const ``` สำหรับ arrays: ```js const person = []; person.push('John'); // สามารถทำได้ ! ตัวแปร person ไม่ได้ถูก assign ใหม่ แต่ถูกแปลงค่าข้างใน console.log(person[0]) // "John" person = ["Nick"] // เกิด error เพราะว่าไม่สามารถ assign ค่าซ้ำได้สำหรับตัวแปรที่ประกาศด้วย const ``` #### ข้อมูลเพิ่มเติมจากภายนอก - [How let and const are scoped in JavaScript - WesBos](http://wesbos.com/javascript-scoping/) - [Temporal Dead Zone (TDZ) Demystified](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) ### Arrow ฟังก์ชั่น ใน JavaScript อัปเดต ES6 มี *arrow ฟังก์ชั่น* ซึ่งเป็นการประกาศและใช้ฟังก์ชั่นในรูปแบบใหม่ และมีความสามารถที่มาเพิ่มเติมดังนี้ - เขียนสั้นกระชับมากขึ้น - *this* อ้างอิงถึงภายนอกรอบๆ - การ return ค่าทันทีได้แบบตรงไปตรงมา #### ตัวอย่างโค้ด - การ return ที่สั้นกระชัดและตรงไปตรงมามากขึ้น ```js function double(x) { return x * 2; } // วิธีปกติ console.log(double(2)) // 4 ``` ```js const double = x => x * 2; // ฟังก์ชั่นเดียวกันที่เปลี่ยนมาเขียนโดยใช้ arrow ฟังก์ชั่นและ return ทันที console.log(double(2)) // 4 ``` - การอ้างอิงเมื่อใช้ *this* ใน arrow ฟังก์ชั่น *this* จะอ้างอิงถึงค่าของ *this* ที่อยู่บริบทที่ครอบอยู่ พูดง่ายๆ คือเมื่อใช้ arrow ฟังก์ชั่นคุณไม่จำเป็นต้องทำทริค "that = this" ก่อนเรียกฟังก์ชั่นอื่นภายในฟังก์ชั่นอีกทีอีกต่อไป ```js function myFunc() { this.myVar = 0; setTimeout(() => { this.myVar++; console.log(this.myVar) // 1 }, 0); } ``` #### อธิบายรายละเอียด ##### การย่อสั้น Arrow ฟังก์ชั่นจะสั้นกระชับกว่าฟังก์ชั่นแบบปกติทั่วไป ลองมาดูวิธีการเขียนแบบที่สามารถเขียนได้ดังนี้: - Implicit VS Explicit return **Explicit return** หมายถึง function ที่ต้องมีการใช้คีย์เวิร์ด *return* ข้างในตัวมัน ```js function double(x) { return x * 2; // ฟังก์ชั่นนี้เป็น explicitly returns x * 2, ดังนั้นต้องมีคีย์เวิร์ด *return* } ``` โดยวิธีเขียนฟังก์ชั่นแบบปกติแล้ว การ return จะเป็น explicit จะเสมอ แต่สำหรับ arrow ฟังก์ชั่นคุณสามารถทำ *implicit return* ซึ่งหมายความว่าคุณไม่จำเป็นต้องใช้คีย์เวิร์ด *return* เพื่อ return ค่าได้เลย ในการเขียน implicit return จะทำให้สามารถเขียนโค้ดได้เหลือเพียง 1 บรรทัด ```js const double = (x) => { return x * 2; // Explicit return ตรงนี้ } ``` เมื่อมันทำแค่ return ค่าตรงนั้นทันที เราสามารถเขียนแบบ implicit return ได้ข้างล่าง ```js const double = (x) => x * 2; ``` และจากข้างบน ที่เราต้องทำมีแค่ **เอาปีกกา** กับคีย์เวิร์ด **return** ออก แบบนี้เลยเรียกว่า *implicit* return เพราะว่าไม่จำเป็นต้องใช้คีย์เวิร์ด return แต่ฟังก์ชั่นก็ยัง return ```x * 2``` อยู่ > **หมายเหตุ:** ถ้าฟังก์ชั่นของคุณไม่ได้ต้องการการ return ค่า (พร้อมกับ *side effects*) จะใช้แบบไหนก็ไม่ต่างกัน นอกจากนี้ ถ้าคุณใช้ implicit return ค่าเป็น *object* คุณ**ต้องใช้วงเล็บครอบ** เพื่อป้องกันการสับสนกับ block scope ตามข้างล่าง ```js const getPerson = () => ({ name: "Nick", age: 24 }) console.log(getPerson()) // { name: "Nick", age: 24 } -- object implicitly return ค่าโดยใช้ arrow function ``` - มี argument แค่ตัวเดียว ถ้า function รับ parameter เพียงแค่ตัวเดียว สามารถเอาวงเล็บออกได้ ถ้าเราปรับปรุงจากโค้ด *double* ก่อนหน้าจะได้ดังนี้ ```js const double = (x) => x * 2; // arrow ฟังก์ชั่นนี้รับเพียง 1 parameter ``` วงเล็บสามารถเอาออกได้ดังนี้: ```js const double = x => x * 2; // arrow ฟังก์ชั่นนี้รับเพียง 1 parameter ``` - ไม่มี argument เมื่อไม่ต้องการ argument ใดๆ เลยใน arrow function คุณจำเป็นต้องใส่วงเล็บ ไม่อย่างนั้นมันจะไม่ใช่ syntax ที่ถูกต้อง ```js () => { // ถ้ามีวงเล็บ ทุกอย่างจะปกติ const x = 2; return x; } ``` ```js => { // ถ้าไม่มีวงเล็บ จะใช้งานไม่ได้! const x = 2; return x; } ``` ##### การอ้างอิงของ *this* เพื่อที่จะเข้าใจเรื่อง this กับ arrow ฟังก์ชั่นคุณต้องเข้าใจก่อนว่า [this](#this_def) ทำงานยังไงใน JavaScript ใน arrow function *this* มีค่าเท่าที่ค่าของ *this* ที่เป็นบริบทที่ครอบมันอยู่ นั่หมายถึงว่า arrow ฟังก์ชั่นไม่สร้าง *this* ขึ้นมาใหม่ แต่ว่ามันเอาค่าที่อยู่รอบนอกของมันมาใช้แทน ถ้าไม่ใช่ arrow ฟังก์ชั่นถ้าคุณต้องการใช้งานตัวแปร *this* ของฟังก์ชั่นเมื่ออยู่ภายใน function อีกที เพื่ออ้างอิงถึง *this* ภายนอก คุณจะต้องใช้ *that = this* หรือว่า *self = this* เป็นทริคเพื่ออ้างอิงถึง ยกตัวอย่างเช่น เมื่อใช้ฟังก์ชั่น setTimeout ภายใน myFunc: ```js function myFunc() { this.myVar = 0; var that = this; // ทริค that = this setTimeout( function() { // *this* ใหม่ถูกสร้างภายใน function scope นี้ that.myVar++; console.log(that.myVar) // 1 console.log(this.myVar) // undefined -- เพราะว่าไปหาที่ฟังก์ชั่นที่อยู่นี้ ไม่ใช่ myFunc }, 0 ); } ``` แต่เมื่อใช้ arrow ฟังก์ชั่น *this* จะอ้างอิงถึงที่อยู่รอบๆ ตัวมัน: ```js function myFunc() { this.myVar = 0; setTimeout( () => { // this มาจากรอบๆ นั่นหมายถึง myFunc ในกรณีนี้ this.myVar++; console.log(this.myVar) // 1 }, 0 ); } ``` #### หล่งข้อมูลที่มีประโยชน์ - [Arrow functions introduction - WesBos](http://wesbos.com/arrow-functions/) - [JavaScript arrow function - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - [Arrow function and lexical *this*](https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4) ### ค่า Default Parameter ของฟังก์ชั่น ตั้งแต่อัปเดตของ ES2015 JavaScript คุณสามารถตั้งค่า default ให้กับ parameter ของฟังก์ชั่นได้แล้วโดยใช้ syntax ตามข้างล่างนี้: ```js function myFunc(x = 10) { return x; } console.log(myFunc()) // 10 -- ไม่ได้มีค่าโยนเข้าไปใน parameter ดังนั้นค่า x จะถูก assign เป็นค่า default ของ myFunc นั่นก็คือ 10 console.log(myFunc(5)) // 5 -- มีค่าโยนเข้าไปใน paramter ดังนั้นค่า x จะมีค่าเท่ากับ 5 ใน myFunc console.log(myFunc(undefined)) // 10 -- โยนค่าเป็น undefined ไป ดังนั้นจะนำค่า default มาใช้ซึ่งก็คือ 10 console.log(myFunc(null)) // null -- โยนค่า null เข้าไปจึงได้ค่า x เป็น null, ดูรายละเอียดเพิ่มเติมข้างล่าง ``` ค่า default paramter จะถูกเรียกใช้ในสองกรณีนี้เท่านั้น: - ไม่โย parameter มาให้ - รับค่า parameter เป็น *undefined* หรือในอีกความหมายนึงคือ ถ้าคุณส่งค่าเป็น *null* จะไม่มีการใช้งาน default parameter > **หมายเหตุ:** ค่า Default สามารถใช้ร่วมกับ destructured parameters ได้ (อันนี้จะอยู่ในเนื้อห้าถัดไป) #### ข้อมูลเพิ่มเติมจากภายนอก - [Default parameter value - ES6 Features](http://es6-features.org/#DefaultParameterValues) - [Default parameters - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) ### Destructuring objects และ arrays *Destructuring* เป็นวิธีในการสร้างตัวแปรใหม่จากการแยกค่าบางค่าจากข้างในของ objects หรือ arrays ซึ่งทำให้สะดวกมากยิ่งขึ้น ยกตัวอย่างสำหรับการใช้งานเช่น *destructuring* สามารถใช้ในการแยกส่วน parameters ของฟังก์ชั่น หรือว่า *this.props* ที่มักเจอประจำในโปรเจ็คที่เป็น React #### อธิบายตัวอย่างโค้ด - Object ลองพิจารณา object ข้างล่างเป็นตัวอย่าง: ```js const person = { firstName: "Nick", lastName: "Anderson", age: 35, sex: "M" } ``` เมื่อไม่ใช้ destructuring: ```js const first = person.firstName; const age = person.age; const city = person.city || "Paris"; ``` เมื่อใช้ destructuring สามารถเขียนในบรรทัดเดียวได้แบบนี้: ```js const { firstName: first, age, city = "Paris" } = person; // แบบนี้ ! console.log(age) // 35 -- ตัวแปร age ถูกสร้างขึ้นมาใหม่และมีค่าเท่ากับ person.age console.log(first) // "Nick" -- ตัวแปร first ถูกสร้างขึ้นมาใหม่และมีค่าเท่ากับ person.firstName console.log(firstName) // ReferenceError -- person.firstName มีอยู่จริง แต่ตัวแปรที่ถูกสร้างขึ้นใหม่ถูกตั้งชื่อว่า first console.log(city) // "Paris" -- ตัวแปร city ถูกสร้างขึ้นใหม่ และ person.city มีค่าเป็น undefined เพราะฉะนั้น city จะมีค่าเท่ากับ default ที่ระบุไว้คือ "Paris" ``` **หมายเหตุ :** ใน ```const { age } = person;```, ปีกกาหลังคีย์เวิร์ด *const* มีได้หมายถึงเป็นการประกาศ object หรือว่า block แต่มันหมายถึงเป็น *destructuring* syntax - Parameters ของฟังก์ชั่น *Destructuring* จะใช้บ่อยในการ destructure objects parameters ในฟังก์ชั่น ถ้าไม่มี destructuring ```js function joinFirstLastName(person) { const firstName = person.firstName; const lastName = person.lastName; return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` *person* สามารถทำ destructuring เพื่อให้สั้นกระชับขึ้นได้ดังนี้: ```js function joinFirstLastName({ firstName, lastName }) { // สร้างตัวแปร firstName กับ lastName โดยการ destructuring ตัวแปร return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` Destructuring ยังถูกใช้บ่อยควบคู่กับ [arrow ฟังก์ชั่น](#arrow_func_concept): ```js const joinFirstLastName = ({ firstName, lastName }) => firstName + '-' + lastName; joinFirstLastName(person); // "Nick-Anderson" ``` - Array จาก array ข้างล่างต่อไปนี้: ```js const myArray = ["a", "b", "c"]; ``` เมื่อไม่มี destructuring ```js const x = myArray[0]; const y = myArray[1]; ``` เมื่อมี destructuring ```js const [x, y] = myArray; // แบบนี้ ! console.log(x) // "a" console.log(y) // "b" ``` #### แหล่งข้อมูลที่มีประโยชน์ - [ES6 Features - Destructuring Assignment](http://es6-features.org/#ArrayMatching) - [Destructuring Objects - WesBos](http://wesbos.com/destructuring-objects/) - [ExploringJS - Destructuring](http://exploringjs.com/es6/ch_destructuring.html) ### Array methods - map / filter / reduce *Map*, *filter* และ *reduce* เป็น method ของ array ที่มาจาก programming paradigm ที่ชื่อว่า [*functional programming*](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0). สรุปแบบสั้นๆ: - **Array.prototype.map()** นำ array มาวนลูป ทำอะไรบางอย่างกับค่าของมันแต่ละค่าแล้ว return กลับกลายเป็น array ที่แปลงค่าแล้ว. - **Array.prototype.filter()** นำ array มาวนลูป เลิอกว่าค่าไหนเก็บไว้และค่าไหนทิ้ง และ return กลับไปเป็น array ที่ถูกเลือกแล้ว - **Array.prototype.reduce()** นำ array มาวนลูปและประกอบกันแต่ละค่าเหลือเพียงค่าเดียวเพื่อ return กลับไป แนะนำให้ใช้พวกนี้มากที่สุดเท่าที่จะทำได้ตามทฤษฐีของ functional programming เพราะว่ามันสั้นกระชับและสวยกว่า เมื่อมี 3 methods นี้ คุณสามารถละการใช้ *for* และ *forEach* ลูปในสถานการณ์ส่วนใหญ่ได้ เมื่อคุณจะใช้ *for* ลูป ลองเปลี่ยนมาใช้ *map*, *filter* และ *reduce* แทน แรกๆ อาจจะติดเพราะว่าต้องเปลี่ยนวิธีในการคิดแต่หลังจากเข้าใจและใช้ไปซักระยะจะสามารถใช้งานได้อย่างง่ายดาย #### ตัวอย่างโค้ด ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; const doubledNumbers = numbers.map(n => n * 2); // [0, 2, 4, 6, 8, 10, 12] const evenNumbers = numbers.filter(n => n % 2 === 0); // [0, 2, 4, 6] const sum = numbers.reduce((prev, next) => prev + next, 0); // 21 ``` คำนวณผลรวมเกรดทั้งหมดของนักเรียนโดยใช้ map, filter และ reduce: ```js const students = [ { name: "Nick", grade: 10 }, { name: "John", grade: 15 }, { name: "Julia", grade: 19 }, { name: "Nathalie", grade: 9 }, ]; const aboveTenSum = students .map(student => student.grade) // เรา map ข้อมูลนักเรียนให้กลายเป็น array ที่มีแต่เกรด .filter(grade => grade >= 10) // เรา filter เกรดให้เก็บไว้เฉพาะที่มีค่ามากกว่าเท่ากับ 10 .reduce((prev, next) => prev + next, 0); // เรารวมผลรวมของทุกเกรดทีละคน console.log(aboveTenSum) // 44 -- 10 (Nick) + 15 (John) + 19 (Julia), Nathalie ได้เกรดต่ำกว่า 10 จะถูกข้ามไป ``` #### อธิบาย ลองดู array ของตัวเลขต่อไปนี้ที่จะใช้ในตัวอย่าง: ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; ``` ##### Array.prototype.map() ```js const doubledNumbers = numbers.map(function(n) { return n * 2; }); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` เกิดอะไรขึ้นในข้างบนบ้าง? เราใช้ .map กับ array ที่เก็บ *ตัวเลข* โดย map จะทำการวนรอบ (iterate) ทุกๆ ค่าที่อยู่ภายใน array และส่งค่าต่อเข้าไปในฟังก์ชั่นของเรา เป้าหมายของฟังก์ชั่นนี้คือต้องการสร้างค่าใหม่จากค่าเดิมที่ส่งเข้ามาและส่งกลับไป ถ้ากระจายฟังก์ชั่นให้อ่านง่ายขึ้นจะเป็นตามภาพดังนี้: ```js const doubleN = function(n) { return n * 2; }; const doubledNumbers = numbers.map(doubleN); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` ```numbers.map(doubleN)``` produces ```[doubleN(0), doubleN(1), doubleN(2), doubleN(3), doubleN(4), doubleN(5), doubleN(6)]``` จะเท่ากับ ```[0, 2, 4, 6, 8, 10, 12]```. > **หมายเหตุ:** ถ้าคุณไม่ต้องการ return array ใหม่ แต่ต้องการทำลูปที่สร้าง side effects การใช้ for / forEach ลูปน่าจะเหมาะมากกว่าใช้ map ##### Array.prototype.filter() ```js const evenNumbers = numbers.filter(function(n) { return n % 2 === 0; // ถ้า n เป็นเลขคู่จะเป็น true, และ false ถ้า n ไม่ใช่ }); console.log(evenNumbers); // [0, 2, 4, 6] ``` เราใช้ .filter กับ array ที่เก็บ *ตัวเลข* ชุดเดิม, filter จะทำการวนรอบ (iterate) ทุกค่าใน array และส่งเข้าไปในฟังก์ชั่นของเรา เป้าหมายของฟังก์ชั่นนี้คือการ return เป็น boolean ว่าค่านั้นๆ จะต้องการเก็บเอาไว้หรือทิ้ง ผลสุดท้ายของ filter จะ return array ที่เหลือแต่ค่าที่เลือกเก็บเท่านั้น ##### Array.prototype.reduce() reduce method จะทำหน้าที่ *reduce* ทุกค่าใน array โดยมันจะวนรอบ (iterate) ค่าทั้งหมดให้กลายเหลือเป็นค่าเดียว โดยวิธีการประกอบค่าต่างๆ ยังไงอยู่ที่เรากำหนดในฟังก์ชั่น ```js const sum = numbers.reduce( function(acc, n) { return acc + n; }, 0 // ตัวสะสมค่าตัวแปรสำหรับการวนลูปรอบแรก ); console.log(sum) //21 ``` เหมือนกับ method ของ .map และ .filter เพียงแต่ว่า .reduce จะนำค่าที่ได้จากรอบก่อนหน้ามาส่งต่อเป็น parameter แรกของฟังก์ชั่น มาดูความแตกต่าง: - .reduce รับ parameter สองตัว parameter แรกจะเป็นฟังก์ชั่นสำหรับการวนรอบ (itelation) parameter ที่สองจะเป็นค่าตัวแปรสะสม (ในที่นี้หมายถึง *acc*) สำหรับการวนรอบรอบแรก (คำข้อถัดไปจะมีอธิบายว่าทำไมต้องมี) - Parameters ของฟังก์ชั่น ฟังก์ชั่นที่ส่งเข้าไปใน parameter แรกของ .reduce จะได้รับ parameter ทั้งหมด 2 ตัว โดยตัวแรก (ในที่นี้คือ *acc*) คือตัวแปรสะสม ในขณะที่ตัวแปรที่สอง (*n*) คือค่าปัจจุบันของรอบลูปนั้นๆ ตัวแปรสะสมจะเท่ากับค่าที่ return ในฟังก์ชั่นของการวนรอบ (iteration) ก่อนหน้า ในการวนรอบแรก *acc* จะมีค่าเท่ากับค่าที่คุณส่งเป็น parameter ที่สองให้กับ .reduce นั่นเลยจำเป็นต้องโยนค่า 0 เข้าไปเป็น parameter ที่สองของ reduce นั่นเอง ###### ในการวนรอบรอบแรก ```acc = 0``` เพราะเราส่งค่า 0 เป็น parameter ที่สองให้กับ reduce ```n = 0``` ค่าแรกของ array ที่เก็บ *ตัวเลข* ฟังก์ชั่นจะ returns *acc* + *n* --> 0 + 0 --> 0 ###### ในการวนรอบรอบที่สอง ```acc = 0``` เพราะว่ามันคือค่าที่มาจากการ return ของฟังก์ชั่นในการวนรอบก่อนหน้า ```n = 1``` ค่าที่สองของ array ที่เก็บ *ตัวเลข* ฟังก์ชั่นจะ returns *acc* + *n* --> 0 + 1 --> 1 ###### ในการวนรอบรอบที่สาม ```acc = 1``` เพราะว่ามันคือค่าที่มาจากการ return ของฟังก์ชั่นในการวนรอบก่อนหน้า ```n = 2``` ค่าที่สามของ array ที่เก็บ *ตัวเลข* ฟังก์ชั่นจะ returns *acc* + *n* --> 1 + 2 --> 3 ###### ในการวนรอบรอบที่สี่ ```acc = 3``` เพราะว่ามันคือค่าที่มาจากการ return ของฟังก์ชั่นในการวนรอบก่อนหน้า ```n = 3``` ค่าที่สี่ของ array ที่เก็บ *ตัวเลข* ฟังก์ชั่นจะ returns *acc* + *n* --> 3 + 3 --> 6 ###### [...] ในการวนรอบสุดท้าย ```acc = 15``` เพราะว่ามันคือค่าที่มาจากการ return ของฟังก์ชั่นในการวนรอบก่อนหน้า ```n = 6``` ค่าสุดท้ายของ array ที่เก็บ *ตัวเลข* ฟังก์ชั่นจะ returns *acc* + *n* --> 15 + 6 --> 21 ในการวนรอบสุดท้าย **.reduce** จะคืนค่า 21 กลับไป #### ข้อมูลเพิ่มเติมภายนอก - [Understanding map / filter / reduce in JS](https://hackernoon.com/understanding-map-filter-and-reduce-in-javascript-5df1c7eee464) ### Spread operator "..." spread operator ```...``` เป็นของใหม่ใน ES2015 และใช้สำหรับแผ่ขยายค่าของสิ่งที่สามารถนำมาวนรอบได้ (อย่างเช่น array) แตกออกเป็นชิ้นๆ และนำไปใส่ที่อื่น #### โค้ดตัวอย่าง ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ```js function myFunc(x, y, ...params) { console.log(x); console.log(y); console.log(params) } myFunc("a", "b", "c", "d", "e", "f") // "a" // "b" // ["c", "d", "e", "f"] ``` ```js const { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } ``` #### อธิบาย ##### ใช้กับสิ่งที่สามารถวนลูปได้ (iterables) (แบบ arrays) ถ้าเรามี array สองตัวดังนี้: ```js const arr1 = ["a", "b", "c"]; const arr2 = [arr1, "d", "e", "f"]; // [["a", "b", "c"], "d", "e", "f"] ``` ใน *arr2* ค่าแรกจะเป็น array เพราะว่า *arr1* ถูกนำเข้าไปใส่ใน *arr2* แต่ถ้าเราต้องให้ *arr2* เป็น array ของตัวอักษรเพียงอย่างเดียว สิ่งที่เราต้องทำคือเราสามารถ *spread* ค่าต่างๆ ของ *arr1* เข้าไปสู่ *arr2* เมื่อใช้ spread operator ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ##### Rest parameter ของฟังก์ชั่น ใน parameter ของฟังก์ชั่นเราสามารถใช้ rest operator สำหรับรวม parameters เป็น array ที่เราสามารถนำไปวนลูปได้ ถ้าเทียบก็เหมือนการห่อ **arguments** ที่รับมาเป็น object เอาไว้ ```js function myFunc() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } myFunc("Nick", "Anderson", 10, 12, 6); // "Nick" // "Anderson" // 10 // 12 // 6 ``` แต่ถ้าเราต้องการให้ function นี้สร้าง student ใหม่พร้อมกับ grade ทั้งหมดของนักเรียนและค่าเฉลี่ยเกรด จะง่ายกว่าถ้าเราแยกให้สอง parameter แรกเป็นตัวแปรแยก และที่เหลือจากนั้นเป็น grade ที่เราสามารถนำไปวนรอบ (itelate) ได้มันน่าจะดีกว่ารึเปล่า? และ rest operator ทำให้เราสามารถทำแบบนั้นได้! ```js function createStudent(firstName, lastName, ...grades) { // firstName = "Nick" // lastName = "Anderson" // [10, 12, 6] -- "..." นำ paramters ที่รับเข้ามาที่เหลือสร้างเป็นตัวแปร array ชื่อ "grades" const avgGrade = grades.reduce((acc, curr) => acc + curr, 0) / grades.length; // คำนวณค่าเฉลี่ยของ grades return { firstName: firstName, lastName: lastName, grades: grades, avgGrade: avgGrade } } const student = createStudent("Nick", "Anderson", 10, 12, 6); console.log(student); // { // firstName: "Nick", // lastName: "Anderson", // grades: [10, 12, 6], // avgGrade: 9,33 // } ``` > **หมายเหตุ:** ฟังก์ชั่น createStudent ยังไม่ดีเท่าไหร่เพราะว่าเรายังไม่ได้เช็ก grades.length ในกรณีที่ไม่มีค่าอยู่จริงหรือไม่ใช่ 0 แต่มันง่ายกว่าถ้าเขียนแบบนี้เพื่อทำความเข้าใจ เพราะฉะนั้นในโค้ดตัวอย่างเลยจะไม่มีการจัดการกับกรณีนี้ ##### Object properties spreading ก่อนจะเข้าเรื่องนี้ แนะนำให้อ่านคำอธิบายก่อนหน้าสำหรับ rest operator ที่ทำการห่อ parameter กลายเป็น object ที่สามารถทำการวนลูปได้ (itelable) ```js const myObj = { x: 1, y: 2, a: 3, b: 4 }; const { x, y, ...z } = myObj; // object destructuring ตรงนี้ console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } // z จะได้ค่าที่เหลือของ object ที่ถูก destructured แล้ว: myObj object เมื่อลบค่า x และ y properties ที่ถูก destructured ออกไปแล้ว const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } // เมื่อนำ z object มา spread กลับเข้าไปให้กับตัวแปร n จะได้ค่าดังเดิม ``` #### ข้อมูลเพิ่มเติมจากภายนอก - [TC39 - Object rest/spread](https://github.com/tc39/proposal-object-rest-spread) - [Spread operator introduction - WesBos](https://github.com/wesbos/es6-articles/blob/master/28%20-%20Spread%20Operator%20Introduction.md) - [JavaScript & the spread operator](https://codeburst.io/javascript-the-spread-operator-a867a71668ca) - [6 Great uses of the spread operator](https://davidwalsh.name/spread-operator) ### Object property shorthand เมื่อ assign ค่าใช้ตัวแปรเป็น object property ถ้าชื่อตัวแปรมีค่าเท่ากับชื่อ property คุณสามารถทำแบบนี้ได้: ```js const x = 10; const myObj = { x }; console.log(myObj.x) // 10 ``` #### อธิบาย ปกติแล้ว (pre-ES2015) เมื่อคุณประกาศ *object literal* ใหม่ และต้องการใช้ค่าของตัวแปรไปเป็นค่าให้กับ object properties นั้นปกติแล้วต้องเขียนแบบนี้: ```js const x = 10; const y = 20; const myObj = { x: x, // assign ค่าของตัวแปร x ให้เป็นค่าของ myObj.x y: y // assign ค่าของตัวแปร y ให้เป็นค่าของ myObj.y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` จะเห็นว่ามันซ้ำซ้อนกันเพราะว่าชื่อ properties ของ myObj เป็นชื่อเดียวกับตัวแปรที่ต้องการ assign ให้กับ properties เหล่านั้น เมื่อเขียนด้วย ES2015 เมื่อชื่อตัวแปรเป็นชื่อเดียวกับชื่อ property สามารถเขียนให้สั้นลงเป็นแบบนี้ได้: ```js const x = 10; const y = 20; const myObj = { x, y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` #### ข้อมูลเพิ่มเติมจากภายนอก - [Property shorthand - ES6 Features](http://es6-features.org/#PropertyShorthand) ### Promises Promise เป็น object ที่สามารถ return ค่าแบบ synchronous จากฟังก์ชั่นที่เป็น asynchronous ได้ ([ref](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#3cd0)). Promise สามารถใช้เพื่อแก้ปัญหาของ [callback hell](http://callbackhell.com/) และมันมักนำไปใช้ในโค้ด Javascript โปรเจ็คใหม่ๆ ที่ทันสมัย #### ตัวอย่างโค้ด ```js const fetchingPosts = new Promise((res, rej) => { $.get("/posts") .done(posts => res(posts)) .fail(err => rej(err)); }); fetchingPosts .then(posts => console.log(posts)) .catch(err => console.log(err)); ``` #### อธิบาย เมื่อคุณสร้าง *Ajax request* จะได้รับ response ที่ไม่ synchronous เพราะว่ามันต้องใช้เวลาเพื่อจะได้ผลลัพธ์ที่กลับมา และมันอาจจะไม่ได้ค่าที่ต้องการกลับมาถ้า request ที่ส่งไปไม่สามารถใช้งานได้ด้วยเหตุบางประการ (404) เพื่อรับมือกับสถานการณ์แบบนั้น ES2015 ได้มี *promises* ซึ่ง promise มีทั้งหมด 3 states ด้วยกัน: - Pending - Fulfilled - Rejected หรือพูดอีกอย่างว่าเราต้องการใช้ promise ไปการจัดการกับพวก Ajax request เพื่อดึงข้อมูลจาก X ##### การสร้าง promise ก่อนที่เราจะใช้ promise เราจะใช้ jQuery สำหรับการทำ Ajax request ไปหา X ```js const xFetcherPromise = new Promise( // สร้าง promise โดยใช้คีย์เวิร์ด "new" และเก็บลงตัวแปร function(resolve, reject) { // constructor ของ promise รับ parameter เป็นฟังก์ชั่นที่มี parameter ชื่อ resolve และ reject ด้วยตัวมันเอง $.get("X") // ส่ง Ajax request .done(function(X) { // เมื่อ request เสร็จแล้ว ... resolve(X); // ... resolve promise ด้วยค่า X กลับไปเป็น parameter }) .fail(function(error) { // ถ้า request เกิดผิดพลาด... reject(error); // ... reject promise แล้วส่ง error กลับไปเป็น parameter }); } ) ``` จากที่เห็นในตัวอย่างข้างบน Promise object จะรับ *executor* ฟังก์ชั่นที่รับ parameter สองตัวคือ **resolve** และ **reject** ซึ่งสองตัวนี้ถ้ามีการเรียกใช้จะเป็นการย้าย state ของ promise จาก *pending* ไปสู่ *fulfilled* หรือ *rejected* promise จะอยู่ใน pending state หลังสร้าง instance และฟังก์ชั่น *executor* ของมันจะทำงานทันที และเมื่อมีการเรียกใช้ฟังก์ชั่น *resolve* หรือ *reject* ภายใน *executor* ฟังก์ชั่นตัว promise จะมีสิ่งที่เรียกว่า handlers คอยจัดการกับสิ่งที่เกิดขึ้น ##### การใช้งาน Promise handlers เพื่อที่จะรับผลลัพธ์ของ promise (หรือว่า error) เราจะสามารถควบคุมด้วย handlers โดยทำได้ดังนี้: ```js xFetcherPromise .then(function(X) { console.log(X); }) .catch(function(err) { console.log(err) }) ``` ถ้า promise ทำงานสมบูรณ์และเรียกใช้ *resolve* โดยจะส่งค่าที่ได้ไปเป็น parameter ในฟังก์ชั่นใน ```.then``` ถ้าเกิดข้อผิดพลาด *reject* จะถูกเรียกแล้วส่งค่าไปเป็น parameter ในฟังก์ชั่นใน ```.catch``` > **หมายเหตุ :** ถ้า promise เข้าไปสู่ state fulfilled หรือ rejected โดยที่มีการใช้ handler แล้ว handler จะถูกเรียกใช้ ทำให้ไม่เกิด race condition ระหว่างรอ asynchronous เสร็จสมบูรณ์กับ handlers [(Ref: MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#Description) #### ข้อมูลเพิ่มเติมจากภายนอก - [JavaScript Promises for dummies - Jecelyn Yeen](https://scotch.io/tutorials/javascript-promises-for-dummies) - [JavaScript Promise API - David Walsh](https://davidwalsh.name/promises) - [Using promises - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) - [What is a promise - Eric Elliott](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261) - [JavaScript Promises: an Introduction - Jake Archibald](https://developers.google.com/web/fundamentals/getting-started/primers/promises) - [Promise documentation - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) ### Template literals Template literals เป็น [*expression interpolation*](https://en.wikipedia.org/wiki/String_interpolation) สำหรับ strings ที่สามารถทำได้ตั้งแต่บรรทัดเดียวถึงหลายบรรทัด หรือในอีกกรณีนึงก็คือ มันเป็น syntax ของ string ที่สามารถใช้ JavaScript expesssions ข้างในได้อย่างสะดวกมากขึ้น (ยกตัวอย่างเช่นแทรกตัวแปรภายใน string) #### ตัวอย่างโค้ด ```js const name = "Nick"; `Hello ${name}, the following expression is equal to four : ${2+2}`; // Hello Nick, the following expression is equal to four: 4 ``` #### ข้อมูลเพิ่มเติมจากภายนอก - [String interpolation - ES6 Features](http://es6-features.org/#StringInterpolation) - [ES6 Template Strings - Addy Osmani](https://developers.google.com/web/updates/2015/01/ES6-Template-Strings) ### Tagged template literals Template tags คือ *ฟังก์ชั่นที่สามารถกลายเป็นให้กับ [template literal](#template-literals) ได้*. ถ้าฟังก์ชั่นถูกเรียกใช้แบบนี้ parameter แรกจะเป็น array ของ *strings* ที่แสดงระหว่างตัวแปรของ template's interpolated และ parameter อื่นที่ตามมาคือค่า interpolated ดังนั้นถ้าใช้ spread operator `...` ก็จะสามารถรวบรวม parameter ที่เหลือทั้งหมดได้ [(Ref: MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals). > **หมายเหตุ :** Library ชื่อดังอย่าง [styled-components](https://www.styled-components.com/) ใช้ฟีเจอร์นี้อย่างเต็มรูปแบบ ข้างล่างคือตัวอย่างของการนำไปใช้งาน ```js function highlight(strings, ...values) { const interpolation = strings.reduce((prev, current) => { return prev + current + (values.length ? "" + values.shift() + "" : ""); }, ""); return interpolation; } const condiment = "jam"; const meal = "toast"; highlight`I like ${condiment} on ${meal}.`; // "I like jam on toast." ``` ตัวอย่างที่น่าสนใจเพิ่มเติม: ```js function comma(strings, ...values) { return strings.reduce((prev, next) => { let value = values.shift() || []; value = value.join(", "); return prev + next + value; }, ""); } const snacks = ['apples', 'bananas', 'cherries']; comma`I like ${snacks} to snack on.`; // "I like apples, bananas, cherries to snack on." ``` #### ข้อมูลเพิ่มเติมจากภายนอก - [Wes Bos on Tagged Template Literals](http://wesbos.com/tagged-template-literals/) - [Library of common template tags](https://github.com/declandewet/common-tags) ### Imports / Exports ES6 modules สามารถเข้าถึงตัวแปรต่างๆ ของ modules ที่ทำการแยก export ค่าต่างๆ ได้ด้วยการ imports แนะนำให้ลองอ่านข้อมูลเพิ่มเติมใน MDN resources เกี่ยวกับเรื่อง import/export (ดูข้อมูลเพิ่มเติมภายนอกข้างล่าง) จะดีเป็นอย่างมาก เนื้อหาข้างในค่อนข้างอธิบายได้ตรงไปตรงมาและสมบูรณ์แบบ #### อธิบายตัวอย่างโค้ด ##### Named exports Named exports ใช้สำหรับการ export หลายๆ ค่าของ module > **หมายเหตุ :** สามารถ export แบบ name-export [first-class citizens](https://en.wikipedia.org/wiki/First-class_citizen) ได้เฉพาะกับของที่มีชื่อเท่านั้น. ```js // mathConstants.js export const pi = 3.14; export const exp = 2.7; export const alpha = 0.35; // ------------- // myFile.js import { pi, exp } from './mathConstants.js'; // Named import -- คล้ายๆ กับ syntax destructuring console.log(pi) // 3.14 console.log(exp) // 2.7 // ------------- // mySecondFile.js import * as constants from './mathConstants.js'; // ทำค่าทั้งหมดที่มีการ exports มาเป็นตัวแปร console.log(constants.pi) // 3.14 console.log(constants.exp) // 2.7 ``` named imports จะคล้ายกับ *destructuring* แต่ว่าจริงๆ แล้วมีความต่างและไม่เหมือนกัน มันไม่รองรับการใช้ default value หรือว่า *deep* destructuring นอกจากนี้คุณสามารถทำ alias ได้อยู่ เพียงแต่ว่า syntax จะแตกต่างกับ destructuring เป็นรูปแบบตามข้างล่าง ```js import { foo as bar } from 'myFile.js'; // foo ถูก import เข้ามาและเอาไปเป็นค่าตัวแปรใหม่ที่ชื่อว่า bar ``` ##### Default import / export สำหรับ default export เราจะสามารถ export default ได้แค่ตัวเดียวต่อ module และค่า default ที่ export สามารถเป็นได้ทั้ง function, class, object หรืออะไรก็ตาม ค่านี้เป็นเหมือนค่า "หลัก" ในการ export และมันจะง่ายต่อการ import เวลานำไปใช้ [Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Description) ```js // coolNumber.js const ultimateNumber = 42; export default ultimateNumber; // ------------ // myFile.js import number from './coolNumber.js'; // Default export จะอิสระในการตั้งชื่อในหน้าที่ import เข้าไปใช้งาน อย่างข้างบนจะถูกเก็บลงตัวแปรชื่อ number ซึ่งเราสามารถตั้งเองได้ console.log(number) // 42 ``` Export ฟังก์ชั่น: ```js // sum.js export default function sum(x, y) { return x + y; } // ------------- // myFile.js import sum from './sum.js'; const result = sum(1, 2); console.log(result) // 3 ``` #### ข้อมูลเพิ่มเติมจากภายนอก - [ES6 Modules in bulletpoints](https://ponyfoo.com/articles/es6#modules) - [Export - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) - [Import - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) - [Understanding ES6 Modules](https://www.sitepoint.com/understanding-es6-modules/) - [Destructuring special case - import statements](https://ponyfoo.com/articles/es6-destructuring-in-depth#special-case-import-statements) - [Misunderstanding ES6 Modules - Kent C. Dodds](https://medium.com/@kentcdodds/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution-ad2d5ab93ce0) - [Modules in JavaScript](http://exploringjs.com/es6/ch_modules.html#sec_modules-in-javascript) ### JavaScript *this* *this* operator จะแตกต่างกับาภาษาอื่นๆ และโดยกรณีส่วนมากเป็นกำหนดเองว่า this จะทำงานในบริบทไหนในฟังก์ชั่น ([Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)). เนื้อหานี้จะมีรายละเอียดที่ค่อนข้างอ่อนไหวและยากอยู่พอสมควร แนะนำให้ลองอ่านข้อมูลภายนอกเพิ่มเติมข้างล่าง ดังนั้นในที่นี้จะเขียนโดยอิงจากความเข้าใจส่วนตัวจาก[บทความที่เขียนโดย Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/) อีกที ```js function myFunc() { ... } // ข้างล่างจะแสดงให้เห็นค่าของ *this* ใน myFunc myFunc.call("myString", "hello") // "myString" -- ค่า parameter แรกใน .call จะถูกกำหนดเป็น *this* // ในโหมด non-strict-mode myFunc("hello") // window -- myFunc() เป็น syntax เหมือนกับเรียก myFunc.call(window, "hello") // ในโหมด strict-mode myFunc("hello") // undefined -- myFunc() เป็น syntax เหมือนกับเรียก myFunc.call(undefined, "hello") ``` ```js var person = { myFunc: function() { ... } } person.myFunc.call(person, "test") // person Object -- ค่า parameter แรกใน .call จะถูกกำหนดเป็น *this* person.myFunc("test") // person Object -- person.myFunc() เป็น syntax เหมือนกับเรียก person.myFunc.call(person, "test") var myBoundFunc = person.myFunc.bind("hello") // สร้างฟังก์ชั่นใหม่ที่ผูก "hello" เป็นค่าของ *this* person.myFunc("test") // person Object -- bind method ไม่มีผลใดๆ กับ method ดั้งเดิม myBoundFunc("test") // "hello" -- myBoundFunc เป็น person.myFunc ที่มี "hello" เป็น *this* ``` #### ข้อมูลเพิ่มเติมจากภายนอก - [Understanding JavaScript Function Invocation and "this" - Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/) - [JavaScript this - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) ### Class JavaScript เป็นภาษาที่เป็น [prototype-based](https://en.wikipedia.org/wiki/Prototype-based_programming) (เมื่อเปรียบเทียบกับ Java ที่เป็นภาษาที่เป็น [class-based](https://en.wikipedia.org/wiki/Class-based_programming)). ES6 ได้ทำให้ JavaScript เสมือนมี class ขึ้นมา แต่จริงๆแล้วเกิดจากการสืบทอดจาก prototype-based และ **ไม่ใช่** class-based ([ref](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)). คำว่า *class* จะไม่เหมือนกับ class ในภาษาอื่นๆ เป็นไปได้ควรทำความเข้าใจกับ class ใน JavaScript ก่อน assume ว่ามันจะเหมือนภาษาอื่น บทความนี้ไม่ได้สอนเรื่องภาษาตั้งแต่เริ่มต้น เราเชื่อคุณรู้อยู่แล้วว่า prototypes คืออะไรและทำหน้าที่อะไร แต่ถ้ายังไม่เข้าใจเรื่องพวกนี้เรามี link บางส่วนที่จะช่วยอธิบายเพื่อให้เรื่องเหล่านี้ได้ดีมากขึ้น - [Understanding Prototypes in JS - Yehuda Katz](http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/) - [A plain English guide to JS prototypes - Sebastian Porto](http://sporto.github.io/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/) - [Inheritance and the prototype chain - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) #### ตัวอย่าง ก่อนจะมี ES6 ต้องเขียนแบบ prototype syntax: ```js var Person = function(name, age) { this.name = name; this.age = age; } Person.prototype.stringSentence = function() { return "Hello, my name is " + this.name + " and I'm " + this.age; } ``` เมื่อใช้ Syntax แบบ ES6: ```js class Person { constructor(name, age) { this.name = name; this.age = age; } stringSentence() { return "Hello, my name is " + this.name + " and I'm " + this.age; } } const myPerson = new Person("Manu", 23); console.log(myPerson.age) // 23 console.log(myPerson.stringSentence()) // "Hello, my name is Manu and I'm 23 ``` #### ข้อมูลเพิ่มเติมจากภายนอก สำหรับทำความเข้าใจ prototype: - [Understanding Prototypes in JS - Yehuda Katz](http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/) - [A plain English guide to JS prototypes - Sebastian Porto](http://sporto.github.io/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/) - [Inheritance and the prototype chain - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) สำหรับทำความเข้าใจ classes: - [ES6 Classes in Depth - Nicolas Bevacqua](https://ponyfoo.com/articles/es6-classes-in-depth) - [ES6 Features - Classes](http://es6-features.org/#ClassDefinition) - [JavaScript Classes - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) ### Async Await เพิ่มเติมจาก [Promises](#promises) จะมี syntax รูปแบบใหม่ให้สำหรับจัดการกับ asynchronous ชื่อว่า *async / await* จุดประสงค์ของ async/await function คือทำให้สามารถจัดการกับการใช้ promise synchronous ได้ง่ายขึ้น และทำพฤติกรรมคล้ายๆ กับ Promises ถ้าให้เปรียบเทียบคือถ้า Promises มีโครงสร้างคล้ายคลึงกับ callback สำหรับ async/await จะมีโครงสร้างคล้าย generators ผสมกับ promises นั่นเอง ซึ่ง async function จะ return เป็น Promise *เสมอ* ([Ref: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)) > **หมายเหตุ :** ต้องเข้าใจก่อนว่า promise คืออะไร และทำงานยังไง ก่อนที่จะพยายามทำความเข้าใจ async / await > **หมายเหตุ 2:** [*await* จะต้องใช้ใน *async* function](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9#f3f0), นั่นหมายความว่าคุณไม่สามารถใช้ await ใน top level ของโค้ดได้ ถ้ามันไม่ได้อยู่ใน async function. #### ตัวอย่างโค้ด ```js async function getGithubUser(username) { // คีย์เวิร์ด async ทำให้สามารถใช้ await ภายในฟังก์ชั่นได้ นั่นหมายถึงฟังก์ชั่นนี้ return เป็น promise const response = await fetch(`https://api.github.com/users/${username}`); // Execution จะหยุดที่ตรงนี้จนกว่า promise จะ return หลังจาก fetch แล้ว resolved return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) // log ข้อมูล response ของ user - ไม่สามารถใช้ syntax await ได้เพราะโค้ดไม่ได้เป็น async function .catch(err => console.log(err)); // ถ้า error มีการ thrown ใน async function จะสามารถ catch ได้ที่นี่ ``` #### อธิบายตัวอย่างโค้ด *Async / Await* สร้างมาจาก promise แต่ว่าออกแบบมาให้เขียนในรูปแบบที่ง่ายกว่า *async* operator จะเปลี่ยนฟังก์ชั่นเป็น asynchronous และจะ return เป็น *Promise* คุณสามารถใช้ *await* operator ใน *async* function เพื่อหยุดการ execution ที่บรรทัดนั้นๆ จนกว่า Promise จะ return ค่ากลับมาโดย resolves หรือ rejects ```js async function myFunc() { // เราสามารถใช้ await operator เพราะฟังก์ชั่นนี้กำหนดเป็น async return "hello world"; } myFunc().then(msg => console.log(msg)) // "hello world" -- ค่าที่คืนจากฟังก์ชั่น myFunc จะถูกเปลี่ยนไปเป็น promise เพราะว่ามีการใช้ async operator ``` เมื่อถึงบรรทัด *return* ของ async function ตัว Promise ที่ได้รับค่าแล้วจะ return กลับไป ถ้าเกิด error และมีการ thrown ข้างใน async function ตัว promise state จะถูกเปลี่ยนเป็น *rejected* และถ้ากรณีไม่มีค่า return จาก async function ตัว promise จะยังคง return และ resolve แบบไม่มีค่ากลับไปเมื่อ async function ทำงานเสร็จสมบูรณ์ *await* operator จะใช้สำหรับรอ *Promise* จนกว่าจะได้รับค่า และสามารถใช้ได้เฉพาะในฟังก์ชั่นที่เป็น *async* เท่านั้น เมื่อโค้ด execution มาถึงจะหยุดจนกว่า promise จะได้รับการเติมเต็มข้อมูล (fulfilled) > **หมายเหตุ :** *fetch* เป็นฟังก์ชั่นที่ return เป็น Promise ที่สามารถทำ AJAX request ได้ มาดูกันว่าเราสามารถใช้ fetch ข้อมูล github user ด้วย promises ยังไงได้บ้าง: ```js function getGithubUser(username) { return fetch(`https://api.github.com/users/${username}`).then(response => response.json()); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` และอันนี้คือถ้ากรณีใช้ *async / await* จะเป็นยังไง: ```js async function getGithubUser(username) { // ใช้งาน promise + await ร่วมกัน const response = await fetch(`https://api.github.com/users/${username}`); // Execution จะหยุดที่นี่จนกว่าข้อมูลใน Promise จะได้รับการเติมเต็ม (fulfilled) return response.json(); } getGithubUser('mbeaudru') .then(user => console.log(user)) .catch(err => console.log(err)); ``` *async / await* syntax ทำให้เราสามารถเขียน promise แบบ chain ได้สะดวกสบายมากขึ้น ยกตัวอย่างเช่น ถ้าเราต้องการเอาค่า token ก่อนเพื่อที่จะนำข้านี้ไป fetch ข้อมูล blog post ที่อยู่ใน database เพื่อเอาข้อมูลคนเขียน post เราจะสามารถให้มันทำงานตามลำดับได้: > **หมายเหตุ :** *await* ต้องครอบด้วยวงเล็บเพื่อรอให้เรียก resolve และได้รับค่าก่อน ถึงจะนำไปใช้ต่อได้ถ้าเขียนในบรรทัดเดียวกันหรือเขียนแบบ chain ```js async function fetchPostById(postId) { const token = (await fetch('token_url')).json().token; const post = (await fetch(`/posts/${postId}?token=${token}`)).json(); const author = (await fetch(`/users/${post.authorId}`)).json(); post.author = author; return post; } fetchPostById('gzIrzeo64') .then(post => console.log(post)) .catch(err => console.log(err)); ``` ##### การจัดการกับ Error นอกจากเพิ่ม *try / catch* blocks ครอบการใช้ *await* เพื่อดัก uncaught exceptions แล้ว - ไม่ว่าอะไรก็ตามที่ thrown ภายใน *async* function หรือว่ามันโดนยกเลิกระหว่าง *await* – จะ reject ตัว promise กลับไปใน *async* function ดังนั้นถ้าใช้ `throw` ใน async function จะเหมือนกับ return ตัว Promise ที่ rejects นั่นเอง [(Ref: PonyFoo)](https://ponyfoo.com/articles/understanding-javascript-async-await#error-handling). > **หมายเหตุ :** Promises เป็นแบบเดียวกัน! เมื่อใช้ Promises เราจะสามารถจัดการกับ error chain ได้แบบนี้: ```js function getUser() { // Promise อันนี้จะโดน rejected! return new Promise((res, rej) => rej("User not found !")); } function getAvatarByUsername(userId) { return getUser(userId).then(user => user.avatar); } function getUserAvatar(username) { return getAvatarByUsername(username).then(avatar => ({ username, avatar })); } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "User not found !" ``` กรณีถ้าใช้ *async / await*: ```js async function getUser() { // Promise ที่จะ return กลับไปจะ rejected! throw "User not found !"; } async function getAvatarByUsername(userId) => { const user = await getUser(userId); return user.avatar; } async function getUserAvatar(username) { var avatar = await getAvatarByUsername(username); return { username, avatar }; } getUserAvatar('mbeaudru') .then(res => console.log(res)) .catch(err => console.log(err)); // "User not found !" ``` #### ข้อมูลเพิ่มเติมจากภายนอก - [Async/Await - JavaScript.Info](https://javascript.info/async-await) - [ES7 Async/Await](http://rossboucher.com/await/#/) - [6 Reasons Why JavaScript’s Async/Await Blows Promises Away](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9) - [JavaScript awaits](https://dev.to/kayis/javascript-awaits) - [Using Async Await in Express with Node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) - [Async Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) - [Await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) - [Using async / await in express with node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) ### Truthy / Falsy ใน JavaScript ค่า truthy หรือ falsy เป็นค่าที่สามารถถูก casted ไปเป็น boolean เมื่ออยู่ในบริบทที่ต้องกระประเมินค่าเป็น boolean ยกตัวอย่างบริบทของ boolean เมื่อถูกนำไปใช้ใน ```if```: ค่าทั้งหมดสามารถถูก casted ไปเป็น ```true``` ยกเว้นแต่ว่ามันจะเป็นค่าเหล่านี้: - false - 0 - "" (empty string) - null - undefined - NaN นี่คือตัวอย่างของ *บริบทของ boolean*: - การประเมินค่าเมื่ออยู่ใน ```if``` condition ```js if (myVar) {} ``` ```myVar``` สามารถเป็นอะไรก็ได้ [first-class citizen](https://en.wikipedia.org/wiki/First-class_citizen) (ตัวแปร, ฟังก์ชั่น, boolean) แต่มันจะถูก casted ไปเป็น boolean เพราะว่ามันกำลังถูกประเมินอยู่ในบริบทของ boolean - การใช้ **NOT** ```!``` operator operator นี้จะ return false ถ้า operand สามารถถูก convert ไปเป็น true ได้ ```js !0 // true -- 0 เป็น falsy ดังนั้นมันจะ returns true !!0 // false -- 0 เป็น falsy ดังนั้น !0 จะ returns true และดังนั้น !(!0) จะ returns false !!"" // false -- string ว่างเป็น falsy ดังนั้น NOT (NOT false) จะเท่ากับ false ``` - เมื่อใช้ *Boolean* object constructor ```js new Boolean(0) // false new Boolean(1) // true ``` - ในกรณีใช้ ternary evaluation ```js myVar ? "truthy" : "falsy" ``` myVar ถูกประเมินให้อยู่ในบริบทของ boolean ### Static Methods #### อธิบายสั้นๆ คีย์เวิร์ด `static` สามารถใช้ใน class เพื่อประกาศเป็น static method ได้ ตัว static method เป็นฟังก์ชั่นใน class ที่เป็นของ class object และจะไม่ใช่ของตัว instance ของ class นั้นๆ #### ตัวอย่างโค้ด ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } } //หมายเหตุ เราไม่ได้มีการสร้าง instance จาก Repo class console.log(Repo.getName()) //Repo name คือ modern-js-cheatsheet let r = new Repo(); console.log(r.getName()) //Uncaught TypeError: repo.getName is not a function ``` #### อธิบายรายละเอียด Static method สามารถเรียก static method ตัวอื่นโดยใช้คีย์เวิร์ด `this` ได้ซึ่งจะไม่สามารถทำได้สำหรับ non-static methods และ non-static methods จะไม่สามารถเข้าถึง static method อื่นโดยใช้คีย์เวิร์ด `this` ได้ ##### เรียก static methods อื่นจาก static method เพื่อจะเรียก static method จาก static method อื่น ใช้คีย์เวิร์ด `this` แบบนี้ได้: ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } static modifyName(){ return this.getName() + '-added-this' } } console.log(Repo.modifyName()) //Repo name คือ modern-js-cheatsheet-added-this ``` ##### เรียก static methods อื่นจาก non-static method Non-static methods สามารถเรียก static methods ได้ใน 2 ทาง; 1. ###### ใช้ชื่อ class. เพื่อที่จะใช้ static method จาก non-static method เราใช้ชื่อ class และเรียก static method เหมือนเป็น property ตัวอย่างเช่น `ClassName.StaticMethodName` ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ return Repo.getName() + ' and it contains some really important stuff' } } // เราต้องสร้าง instance จาก class ขึ้นมาก่อนเพื่อใช้เป็น non-static methods let r = new Repo() console.log(r.useName()) //Repo name คือ modern-js-cheatsheet and it contains some really important stuff ``` 2. ###### ใช้ constructor Static methods สามารถเรียกเหมือนเป็น properties ได้ใน constructor object ```js class Repo{ static getName() { return "Repo name is modern-js-cheatsheet" } useName(){ //เรียก static method เหมือนเป็น property ของ constructor return this.constructor.getName() + ' and it contains some really important stuff' } } // เราต้องสร้าง instance จาก class ขึ้นมาก่อนเพื่อใช้เป็น non-static methods let r = new Repo() console.log(r.useName()) //Repo name คือ modern-js-cheatsheet and it contains some really important stuff ``` #### ข้อมูลเพิ่มเติมจากภายนอก - [static keyword- MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) - [Static Methods- Javascript.info](https://javascript.info/class#static-methods) - [Static Members in ES6- OdeToCode](http://odetocode.com/blogs/scott/archive/2015/02/02/static-members-in-es6.aspx) ## คำศัพธ์ ### Scope บริบทที่ค่าหรือ expression นั้น "มีตัวตน" หรือว่าสามารถอ้างอิงถึงได้ ถ้าตัวแปรหรือ expression ไม่ได้เป็น "อยู่ใน scope นั้นๆ" จะไม่สามารถใช้ได้ แหล่งอ้างอิง: [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Scope) ### Variable mutation หมายถึงตัวแปรที่ถูกการแปลงค่า (mutated) จากค่าตั้งต้นและถูกเปลี่ยนในภายหลัง ```js var myArray = []; myArray.push("firstEl") // myArray กำลังถูกแปลงค่า (mutated) ``` ตัวแปรจะถูกเรียกว่า *immutable* ถ้ามันไม่สามารถแปลงค่า (mutated) ได้ [อ่านบทความ MDN Mutable](https://developer.mozilla.org/en-US/docs/Glossary/Mutable) สำหรับข้อมูลเพิ่มเติม ================================================ FILE: JavaScript/translations/zh-CN.md ================================================ # Modern JavaScript Cheatsheet 简体中文版 ![Modern JavaScript cheatsheet](https://i.imgur.com/aexPxMb.png) Image Credits: [Ahmad Awais ⚡️](https://github.com/ahmadawais) ## 简介 ### 初心 这份文档整理了在当前前端项目中经常需要查阅的内容,并给出了最新的代码示例。 你或许会因为不熟悉当前一些新的代码库(例如 React)所用到的 JavaScript 概念,而很难上手这些新框架。所以本文档的目的并非从零教你 JavaScript,而是帮助已经有一定编程基础的你。 除此之外,我(作者:[Manuel Beaudru](https://github.com/mbeaudru))偶尔会写上一些我的小技巧,也会注意提示这只是我的个人提议。 > **注:** 这篇文档里提到的大多数概念来自于目前最新的 JavaScript(ES2015,即 ES6),你可以在[这里](http://es6-features.org)查看新增的特性,网站做得很棒。 ### 参考材料 当你觉得有的概念不容易理解时,你可以在下面的链接里面寻找答案。 - [MDN (Mozilla Developer Network)](https://developer.mozilla.org/zh-CN/search?q=) - [You don't know JS(书)](https://github.com/getify/You-Dont-Know-JS) - [ES6 新特性和例子](http://es6-features.org) - [WesBos 博客中 ES6 类别](http://wesbos.com/category/es6/) - [Reddit (JavaScript)](https://www.reddit.com/r/javascript/) - [Google](https://www.google.com/) 可直接查找特定的博客和资源 - [StackOverflow](https://stackoverflow.com/questions/tagged/javascript) ## 目录 - [Modern JavaScript Cheatsheet 简体中文版](#Modern-JavaScript-Cheatsheet-简体中文版) * [简介](#简介) + [初心](#初心) + [参考材料](#参考材料) * [目录](#目录) * [正文](#正文) + [变量声明: var, const, let](#变量声明-var-const-let) - [简述](#简述) - [代码示例](#代码示例) - [详述](#详述) - [延伸资料](#延伸资料) + [箭头函数](#箭头函数) - [简述](#简述-1) - [详述](#详述-1) * [简洁性](#简洁性) * [*this* 关键字](#this-关键字) - [相关资料](#相关资料) + [方法默认参数值](#方法默认参数值) ## 正文 ### 变量声明: var, const, let 在 JavaScript 中,声明变量时可以用三个不同的关键词,分别是 `var`,`let` 以及 `const` ,它们各有异同。 #### 简述 用 `const` 声明的变量,不能被重新赋值,而另两个 `var` 和 `let` 是可以的。 所以我建议默认情况下你都用 `const` 来声明变量,在你需要 *改变* 或是声明之后再重新指派它的时候,才用 `let` 来声明变量。 | - | 作用域 | 是否可重新赋值 | 是否可变 | [暂存死区](#tdz_sample) | | ----- | ---- | ------- | -------------------------- | ------------------- | | const | 块级 | × | [√](#const_mutable_sample) | √ | | let | 块级 | √ | √ | √ | | var | 函数 | √ | √ | × | #### 代码示例 ```javascript const person = "Nick"; person = "John" // 因为 person 不能被重新赋值,所以会报错 ``` ```javascript let person = "Nick"; person = "John"; console.log(person) // "John", 使用 let 声明的变量可以重新赋值 ``` #### 详述 简单来讲,变量的作用域([*scope*](#scope_def))是指“在这部分代码中可以访问到此变量”。 ##### var 使用 `var` 定义的变量,其作用域是定义它的函数内部(*function scoped*),也就是说在函数内部创建一个 `var` 变量的时候,在此函数内部可以任意访问这个变量,但在函数之外,这样的局部变量是无法被访问的。 我建议你这样理解,如果一个变量是 *X 作用域(scoped)* 类型的,那就是说这个变量是 X 的属性之一。(译注:X 有 function 和 block 两类,代表函数作用域和块级作用域。) ```javascript function myFunction() { var myVar = "Nick"; console.log(myVar); // "Nick" - 在这个函数中 myVar 可被访问到 } console.log(myVar); // 抛出错误 ReferenceError, 在函数之外 myVar 则无法访问 ``` 继续来看变量的作用域,下面有更多精妙的例子: ```javascript function myFunction() { var myVar = "Nick"; if (true) { var myVar = "John"; console.log(myVar); // "John" // 实际上 myVar 是函数级作用域变量,重新声明的时候,相当于用 "John" 抹去了 myVar 之前的值 "Nick" } console.log(myVar); // "John" - 可见 if 块中的代码会如何影响变量 } console.log(myVar); // 抛出错误 ReferenceError, 在函数之外 myVar 则无法访问 ``` 另外,*var* 声明的变量在执行的时候,就像会被移动到作用域的开始,这就是我们所说的[变量声明提升(var hoisting)](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/**var)。 所以看下面这段代码: ```javascript console.log(myVar) // undefined -- 没有提示错误 var myVar = 2; ``` 之所以没有发生错误,是因为它执行时会被解释为这样: ```javascript var myVar; console.log(myVar) // undefined -- 没有提示错误 myVar = 2; ``` ##### let `var` 和 `let` 几乎是一样的,但是用 `let` 声明的变量有如下特性: - *块级作用域*( block scoped ) - 在被赋值之前,是**无法**访问使用的 - 在同一个作用域之下,不能被重新声明 我们来看看之前例子中提到的块级作用域( block scoping )的效果: ```javascript function myFunction() { let myVar = "Nick"; if (true) { let myVar = "John"; console.log(myVar); // "John" // 实际上 myVar 是块级作用域的变量,在 if 块中,我们相当于是创建了一个新变量, // 这个变量在此块之外是无法被访问的,而且它完全区别于我们创建的第一个 myVar 变量! } console.log(myVar); // "Nick", 可见 if 块中的代码,并没有影响到这个变量的值 } console.log(myVar); // 抛出错误 ReferenceError,在函数外部无法访问到 myVar。 ``` 现在,来看看 *let*(和 *const* )声明的变量在赋值前无法访问是什么意思: ```javascript console.log(myVar) // 提示错误 ReferenceError ! let myVar = 2; ``` 这就是它们和 *var* 变量的区别,如果你在还未赋值给 *let* 或者 *const* 变量之前,就想读写它,是会提示错误的。这种情况常被称作暂存死区([*Temporal dead zone*](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let#let_的暂存死区与错误))或者 *TDZ*。 > **注意:** 从技术上讲,*let* 和 *const* 变量声明时也存在提升,但并不代表它们的赋值也会被提升。但由于它被设计成了赋值之前无法使用,所以我们直观感觉上它没有被提升,但其实是存在提升的。如果想了解更多细节,请看[这篇文章](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified)。 另外,在同一作用域内你不能重新声明一个 *let* 变量。 ```js let myVar = 2; let myVar = 3; // 提示语法错误 SyntaxError ``` ##### const `const` 声明的变量很像 `let`,但它不能被重新赋值。 总结一下 `const` 变量的特点如下: - *块级作用域* - 赋值之前无法使用 - 在同一个作用域内部,你不能重新声明一个变量 - 不能被重新指派 ```Javascript const myVar = "Nick"; myVar = "John" // 提示错误,不允许重新赋值 const 变量 ``` 但这里有一个小细节:`const` 变量并非完全[不可变](#mutation_def),如果这个变量是 `object` 和 `array` 类型的值,那它的值是**可以改变**的。assign 对于对象类型来说: ```js const person = { name: 'Nick' }; person.name = 'John' // 这会生效的!person 并非完全重新指派( reassigned ),只是值变化了( mutated ) console.log(person.name) // "John" person = "Sandra" // 提示错误,因为用 const 声明的变量不能被重新指派 ``` 对于数组类型来说: ```js const person = []; person.push('John'); // 这也会生效!person 并非完全重新指派( reassigned ),只是值变化了( mutated ) console.log(person[0]) // "John" person = ["Nick"] // 提示错误,因为用 const 声明的变量不能被重新指派 ``` #### 延伸资料 - [How let and const are scoped in JavaScript - WesBos](http://wesbos.com/javascript-scoping/) - [Temporal Dead Zone (TDZ) Demystified](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) ### 箭头函数 ES6 JS 的最新版本已经介绍了*箭头函数*, 箭头函数是以另一种方式声明和使用函数。以下是箭头函数带来的一些好处: - 更加简洁 - 从上下文获取*this* - 隐式的返回方式 #### 简述 - 简洁性和隐式的返回方式 ```js function double(x) { return x * 2; } // 传统函数声明方式 console.log(double(2)) // 4 ``` ```js const double = x => x * 2; // 同样的函数,使用具有隐式返回方式的箭头函数来表示 console.log(double(2)) // 4 ``` - *this* 关键字 在箭头函数中, *this*的值就等于函数所处的封闭的可执行上下文的*this*。简单来说,就是在箭头函数中,当你调用一个位于函数体内部的函数时,在内部函数中,你不需要使用"that = this" 这样的声明语句。 ```js function myFunc() { this.myVar = 0; setTimeout(() => { this.myVar++; console.log(this.myVar) // 1 }, 0); } ``` #### 详述 ##### 简洁性 箭头函数从很多方面都比传统的函数简洁。案例如下: - 隐式返回 VS 显式返回 **显式返回** 指的是函数的返回语句使用了return 关键字 ```js function double(x) { return x * 2; // 使用了*return*关键字,显式返回 x * 2 } ``` 传统函数总是伴随着显式返回。使用箭头函数,你可以使用*隐式返回*,即不需要在函数体内使用return关键字就可以返回值。 隐式返回需要将所需代码写在一条语句中。 ```js const double = (x) => { return x * 2; // 显式返回 } ``` 鉴于只返回单值,我们可以使用隐式返回。 ```js const double = (x) => x * 2; ``` 为实现隐式返回,我们只需要 **移除花括号** 和 **return** 关键字。之所以被称为*隐式*返回,是因为*return*关键字不存在的情况下,函数仍可返回 ```x * 2```。 > **注意:** 如果你的函数不是返回一个单值(伴有*连带值*),那么既不可以使用显式返回也不可以使用隐式返回。 除此之外, 如果你想隐式返回一个*object* 则必须使用圆括号对其修饰, ```js const getPerson = () => ({ name: "Nick", age: 24 }) console.log(getPerson()) // { name: "Nick", age: 24 } -- 箭头函数返回的对象 ``` - 函数只有一个参数 如果你的箭头函数只有一个参数,你可以省略修饰参数的圆括号,重新观察上面的代码: ```js const double = (x) => x * 2; // 箭头函数只有一个参数 ``` 参数外面的圆括号可以省略: ```js const double = x => x * 2; // 箭头函数只有一个参数 ``` - 函数无参数 当箭头函数无参数时,必须使用圆括号,否则会出现语法错误. ```js () => { // 必须提供圆括号 const x = 2; return x; } ``` ```js => { // 无圆括号,错误! const x = 2; return x; } ``` ##### *this* 关键字 要理解箭头函数中this的微妙之处,你必须首先了解JavaScript中[this](#this_def) 的行为。 在箭头函数中, *this*的值就等于函数所处的封闭可执行上下文的*this*。这句话的意思就是箭头函数不创建一个新的*this*, 而是从其所处的上下文环境中获取。 没有箭头函数,如果你想要从*this*访问函数内部的函数中的一个变量,你必须使用*that = this*或者*self = this*这样的技巧。 例如, 使用位于myFunc内部的函数setTimeout: ```js function myFunc() { this.myVar = 0; var that = this; // that = this setTimeout( function() { // 在函数的内部创建一个新的 that.myVar++; console.log(that.myVar) // 1 console.log(this.myVar) // 未定义 -- 请参照上面的函数this定义 }, 0 ); } ``` 但是一旦使用箭头函数, *this* 将从包含这个箭头函数的上下文中获取: ```js function myFunc() { this.myVar = 0; setTimeout( () => { // 从上下文中获取this, 在这里就是 myFunc this.myVar++; console.log(this.myVar) // 1 }, 0 ); } ``` #### 相关资料 - [Arrow functions introduction - WesBos](http://wesbos.com/arrow-functions/) - [JavaScript arrow function - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - [Arrow function and lexical *this*](https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4) #### 方法默认参数值 从 ES2015 以后开始,你可以使用下面的语法,给你的方法参数来设置默认值 ```js function myFunc(x = 10) { return x; } console.log(myFunc()) // 10 -- 没有值传入,所以默认的值10传给了myFunc console.log(myFunc(5)) // 5 -- 一个值被传入,所以x等于5 console.log(myFunc(undefined)) // 10 -- undefined 值提供了,所以默认值关联了x console.log(myFunc(null)) // null -- 提供了 (null) , 见一下详细解释 ``` 默认参数有且只有在以下两种情况下才会生效: - 没有参数提供的时候 - *undefined* 参数被提供的时候 换句话说,如果你传入*NULL* 默认值**将不会生效** ================================================ FILE: JavaScript/translations/zh-TW.md ================================================ # Modern JavaScript Cheatsheet 繁體中文版 ![Modern JavaScript cheatsheet](https://i.imgur.com/aexPxMb.png) 圖片來源: [Ahmad Awais ⚡️](https://github.com/ahmadawais) ### 譯者的話 > 原標題:[mbeaudru/modern-js-cheatsheet](https://github.com/mbeaudru/modern-js-cheatsheet) > > 原作者:[BEAUDRU Manuel](https://github.com/mbeaudru) > > 對於現代 JavaScript 開發而言,這篇文章整理了不少知識點,當作複習或是學習都很不錯。自己一直以來都是做為讀者的角色,很少主動為整個開源社群做些實際貢獻,這點一直感到蠻慚愧的,就像是 Sublime 是啟蒙你寫程式的第一個 editor,當你開始工作賺錢後卻遲遲不買 license 是類似的道理。趁著短暫的假日譯者盡可能的把翻譯做到盡善盡美,畢竟不是專業的,要做到信達雅的程度其實不太可能,但過程中確實查閱了不少相關資料,部分關鍵字因為怕超譯所以會在後頭括號保留原文。 > > 另外也想藉著這回翻譯的經驗說點八股的,英文真的天殺的重要,能夠直接閱讀原文始終是最能理解原意的方式。整篇 cheatsheet 從意譯的角度出發,詞意有所疑問或是理解錯誤都煩請發個 Pull Request 謝謝。 > > 2017/09/30 Update > > 昨天晚上收到簡體中文譯者的來信提醒,才發現原來 Issue 內早已有社群朋友 @BirkhoffLee 正在做繁體中文的翻譯 ([詳情可見此討論串](https://github.com/mbeaudru/modern-js-cheatsheet/issues/15)),真的很抱歉昨天才驚覺這件事,譯者在這裡推薦大家如果有空也可以多多瀏覽 @BirkhoffLee 翻譯過的 [機器學習動手玩](https://github.com/humphd/have-fun-with-machine-learning/blob/master/README_zh-tw.md) 以及相關專案,他也是位對於開源社群推廣非常積極的開發者。最後關於這份繁體中文文件,譯者會在這一兩天回顧下文件翻譯用詞有無需要調整的地方,確認過後便會 merge 回原作者的 repo,大概是醬。 ## 介紹 ### 動機 本文檔整理了各種現代化 JavaScript 開發過程中經常使用到的腳本。 該份指南的目標並不是放在幫助初學者從零基礎到入門,而是為了幫助那些因為 JavaScript 新式語法導致可能很難熟悉現代函數庫使用方式 (以 React 做為舉例) 的開發人員。 此外我也會偶爾提供一些個人主觀的建議和技巧,而這些建議可能會造成部分的爭議性,但請務必留意,當我做出這些舉例時這僅僅是出自於個人的推薦作法。 > **注意:** 此處介紹的大部分概念出自於 JavaScript 的語言更新 (ES2015,更多人稱其作 ES6)。你可以在[這個好地方](http://es6-features.org)找到更多添加的新功能。 ### 配套資源 當你在試圖理解一個新概念時,我建議你可以去瀏覽以下這些資源尋找解答: - [MDN (Mozilla Developer Network)](https://developer.mozilla.org/fr/search?q=) - [You don't know JS (book)](https://github.com/getify/You-Dont-Know-JS) - [ES6 Features with examples](http://es6-features.org) - [WesBos blog (ES6)](http://wesbos.com/category/es6/) - [Reddit (JavaScript)](https://www.reddit.com/r/javascript/) - [Google](https://www.google.com/) 搜尋特定相關主題的部落格文章和資源 ## 目錄 - [Modern JavaScript cheatsheet 繁體中文版](#modern-javascript-cheatsheet) * [介紹](#introduction) + [動機](#motivation) + [配套資源](#complementary-resources) * [目錄](#table-of-contents) * [概念](#notions) + [變數聲明: var, const, let](#variable-declaration-var-const-let) - [簡短解釋](#short-explanation-1) - [範例程式碼](#sample-code-2) - [詳細說明](#detailed-explanation-3) - [外部資源](#external-resource-4) + [箭頭函數](#-arrow-function-4) - [範例程式碼](#sample-code-5) - [詳細說明](#detailed-explanation-6) * [簡潔性](#concision-7) * [*this* 關鍵字參照](#this-reference-8) - [有用資源](#useful-resources-9) + [函數預設值](#function-default-parameter-value-10) - [外部資源](#external-resource-11) + [objects 和 arrays 的解構](#destructuring-objects-and-arrays-12) - [說明和範例程式碼](#explanation-with-sample-code-13) - [有用資源](#useful-resources-14) + [Array 的操作方法 - map / filter / reduce](#array-methods---map--filter--reduce-15) - [範例程式碼](#sample-code-16) - [說明](#explanation-17) * [Array.prototype.map()](#arrayprototypemap-18) * [Array.prototype.filter()](#arrayprototypefilter-19) * [Array.prototype.reduce()](#arrayprototypereduce-20) - [外部資源](#external-resource-21) + [展開運算子 "..."](#spread-operator-22) - [範例程式碼](#sample-code-23) - [說明](#explanation-24) * [迭代用法 (如同 array)](#in-iterables-like-array-25) * [不定參數](#function-rest-parameter-26) * [Object 屬性擴展](#object-properties-spreading-27) - [外部資源](#external-resources-28) + [Object 屬性簡寫](#object-property-shorthand-29) - [說明](#explanation-30) - [外部資源](#external-resources-31) + [Promises](#promises-32) - [範例程式碼](#sample-code-33) - [說明](#explanation-34) * [創造 promise](#create-the-promise-35) * [使用 promise](#use-the-promise-36) - [外部資源](#external-resources-37) + [模板字符串](#template-literals-38) - [範例程式碼](#sample-code-39) - [外部資源](#external-resources-40) + [Imports / Exports](#imports--exports-41) - [說明與範例程式碼](#explanation-with-sample-code-42) - [外部資源](#external-resources-43) + [JavaScript *this*](#-javascript-this-44) - [外部資源](#external-resources-45) + [Class](#class-46) - [範例](#samples-47) - [外部資源](#external-resources-48) + [Async Await](#async-await-49) - [範例程式碼](#sample-code-50) - [說明](#explanation-51) - [外部資源](#external-resources-52) * [術語詞彙](#glossary-53) + [作用域範圍](#-scope-54) + [變數變異](#-variable-variance-55) ## 概念 ### 變數聲明: var, const, let 在 JavaScript 中有三個不同關鍵字可用於宣告一個變數,分別是 ```var```, ```let``` 和 ```const```。 #### 簡短解釋 使用 ```const``` 關鍵字宣告的變數無法被重新指派, 而 ```let``` 和 ```var``` 是可以的。 我會建議在默認情況下一律使用 ```const``` ,當你需要改變它或是稍後才重新指派時才使用 ```let``` 。
作用域範圍 是否可重新指派 狀態變更 暫時性死區 (Temporal Dead Zone)
const 區塊 不是
let 區塊
var 函數 不是
#### 範例程式碼 ```javascript const person = "Nick"; person = "John" // 會有錯誤跳出,person 不能被重新指派 ``` ```javascript let person = "Nick"; person = "John"; console.log(person) // "John" 在 let 的使用下允許被重新指派 ``` #### 詳細說明 變數的 [*作用域範圍 (scope)*](#scope_def) 大致上意味著 "這個變數的效力可被作用在哪段程式碼 (where is this variable available in the code)"。 ##### var ```var``` 宣告的變數是 *函數範圍 (function scoped)* 的,這表示當函數中創造變數的時候,該函數中的所有內容都可以訪問並使用該變數。相反的,在函數外創造的 *區塊範圍 (block scoped)* 變數則無法被使用。 我會建議你把它看作是一個 *X scoped* 範圍的變數代表著這個變數是 X 的屬性之一。 ```javascript function myFunction() { var myVar = "Nick"; console.log(myVar); // "Nick" - myVar 可以在函數範圍之內被使用 } console.log(myVar); // Undefined, myVar 在函數範圍外部無法被使用 ``` 持續觀察變數的作用域範圍,這裡有個更細微的範例: ```javascript function myFunction() { var myVar = "Nick"; if (true) { var myVar = "John"; console.log(myVar); // "John" // actually, myVar 是函數範圍之內的,我們剛剛覆蓋了之前的 myVar 變數,值從 "Nick" 變成 "John" } console.log(myVar); // "John" - 印出來看看區塊如何影響 myVar 這個變數的值 } console.log(myVar); // Undefined, myVar 在函數範圍外部無法被使用 ``` 此外, *var* 宣告出來的變數在程式執行之時就會被移到作用域的頂部。這個就是我們所說的[變數提升 (var hoisting)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting)。 這段程式碼: ```js console.log(myVar) // undefined -- 沒有錯誤發生 var myVar = 2; ``` 在程式執行過程中被解讀為: ```js var myVar; console.log(myVar) // undefined -- 沒有錯誤發生 myVar = 2; ``` ##### let ```var``` 和 ```let ``` 大致上行為相同, ```let``` 在宣告變數時 - 作用域是 *區塊範圍 (block scoped)* - 在被指派值以前 **無法** 被存取使用 - 同一個作用域之下不能被重新宣告 採用我們前面的例子來看看區塊範圍 (block scoped) 的影響: ```javascript function myFunction() { let myVar = "Nick"; if (true) { let myVar = "John"; console.log(myVar); // "John" // 事實上,myVar 是區塊範圍之內的,我們剛剛創造了一個全新的 myVar 變數 // 這個變數是無法從區塊範圍以外的地方存取, // 而且它也是完全獨立於我們創造的第一個 myVar 變數! } console.log(myVar); // "Nick", 查看 if 區塊中的程式會不會影響到 myVar 這個值 } console.log(myVar); // Undefined, myVar 在函數範圍外部無法被使用 ``` 現在我們來看看 *let* ( 和 *const* ) 變數在被賦值以前無法被使用是什麼意思: ```js console.log(myVar) // 觸發 ReferenceError 錯誤! let myVar = 2; ``` 和 *var* 變數比較之下,如果在指派 *let* 或是 *const* 變數的值之前嘗試讀取或是寫入的動作是會引發錯誤的。這種現象通常被稱之為 [*Temporal dead zone*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone_and_errors_with_let) 或者是 *TDZ*。 > **注意:** 技術上而言, *let* 和 *const* 變數在聲明時也是會被提升的,但並不是指它們的賦值。因為他們在被指派之前是不能使用的,所以直觀上就像是沒有提升一樣,但它們其實是有的。如果你想知道更多的話請查看 [更加詳細解釋的這篇文章](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified)。 此外,你不能重新宣告一個 *let* 變數: ```js let myVar = 2; let myVar = 3; // 跳出 SyntaxError 錯誤 ``` ##### const ```const``` 宣告出來的行為如同 *let* 變數,但它們同樣都不能被重新宣告。 總結一下, *const* 變數: - 作用域是 *區塊範圍 (block scoped)* - 在被指派值以前 **無法** 被存取使用 - 同一個作用域之下不能被重新宣告 - 無法被重新指派新值 ```js const myVar = "Nick"; myVar = "John" // 跳出錯誤,不允許重新指派新值 ``` ```js const myVar = "Nick"; const myVar = "John" // 跳出錯誤, 重新宣告是不被允許的 ``` 但有個精妙之處 : ```const``` 變數不是[**不可變的**](#mutation_def) ! 更具體而言,這代表著 *object* 和 *array* 中由 ```const``` 宣告出來的變數是 **可以** 被改變的。 對於 objects: ```js const person = { name: 'Nick' }; person.name = 'John' // 這完全可行! person 這個變數尚未完全被重新指派,但它確實改變了 console.log(person.name) // "John" person = "Sandra" // 跳出錯誤,因為重新指派時是不允許使用 const 宣告出來的變數的 ``` 對於 arrays: ```js const person = []; person.push('John'); // 這完全可行! person 這個變數尚未完全被重新指派,但它確實改變了 console.log(person[0]) // "John" person = ["Nick"] // 跳出錯誤,因為重新指派時是不允許使用 const 宣告出來的變數的 ``` #### 外部資源 - [How let and const are scoped in JavaScript - WesBos](http://wesbos.com/javascript-scoping/) - [Temporal Dead Zone (TDZ) Demystified](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified) ### 箭頭函數 ES6 的更新正式引入了 *箭頭函數 (arrow functions)*,這是另外一種宣告和使用函數的方法。以下是它們所帶來的好處: - 更為簡潔 - *this* 的值繼承自外圍作用域 (*this* is picked up from surroundings) - 隱式回傳 (implicit return) #### 範例程式碼 - 簡潔性和隱式回傳 (implicit return) ```js function double(x) { return x * 2; } // 傳統作法 console.log(double(2)) // 4 ``` ```js const double = x => x * 2; // 仍然是同樣的函數,寫成帶有隱式回傳的作法 console.log(double(2)) // 4 ``` - *this* 關鍵字參照 在箭頭函數中, *this* 意味著封閉執行上下文的 *這個值*。基本上,透過使用箭頭函數,在函數中調用函數之前,你不需要去使用像是 "that = this" 這樣的用法。 ```js function myFunc() { this.myVar = 0; setTimeout(() => { this.myVar++; console.log(this.myVar) // 1 }, 0); } ``` #### 詳細說明 ##### 簡潔性 箭頭函數在諸多方面都較傳統函數來的更為簡潔。讓我們來看看所有可能的情況: - 隱式回傳 VS 顯式回傳 **顯式回傳 (explicit return)** 是指在函數中明確的使用 *return* 這個關鍵字。 ```js function double(x) { return x * 2; // 這個函數顯式回傳了 x * 2,並且使用了 return 這個關鍵字 } ``` 以傳統的作法撰寫,return 永遠都會是顯式的。但是如果是使用箭頭函數,你可以執行隱式回傳,這同時代表著你不需要使用關鍵字 return 去取得回傳值。 要做隱式回傳,程式碼必須用一行句子撰寫。 ```js const double = (x) => { return x * 2; // 此處顯示 return 值 } ``` 由於這裡只有一個回傳值,我們可以做一個隱式回傳。 ```js const double = (x) => x * 2; ``` 做到上述的轉換,我們只需要 **移除括號** 以及 **return** 這個關鍵字。這就是為什麼它會被稱為 *隱式* 回傳,*return* 關鍵字不在了,但是這個函數確實會回傳 ```x * 2```。 > **注意:** 如果你的函數沒有回傳一個值 (這種作法有 *副作用*),那麼它將不屬於顯式或是隱式返回中的任一種。 - 只有一個參數 如果你的函數只接受一個參數,你可以省略它周圍的括號。如果我們拿上述的 *double* 程式碼做為舉例: ```js const double = (x) => x * 2; // 這個箭頭函數只接受一個參數 ``` 括號是可以被省略的: ```js const double = x => x * 2; // 這個箭頭函數只接受一個參數 ``` - 沒有參數 當沒有為箭頭函數提供任何參數時,你就必須加上括號,否則語法將會出錯。 ```js () => { // 有加上括號,一切都正常運作 const x = 2; return x; } ``` ```js => { // 沒有括號,這樣的語法是行不通的! const x = 2; return x; } ``` ##### *this* 關鍵字參照 要理解箭頭函數的精妙之處,你一定要清楚 [this](#this_def) 在 JavaScript 中是如何運作的。 在一個箭頭函數當中,*this* 等同於封閉執行上下文的 *這個值* 。意思就是說,一個箭頭函數並不會創造一個新的 *this*,而是從它的外圍作用域一併抓起。 沒有箭頭函數的這項功能,如果你想要取得位於函數的函數內部由 *this* 參照的變數,你就只能使用 *that = this* 或者是 *self = this* 這樣的技巧。 舉例來說,你在 myFunc 函數中使用 setTimeout 函數: ```js function myFunc() { this.myVar = 0; var that = this; // 使用 that = this 這個技巧 setTimeout( function() { // 創造了一個新的 this that.myVar++; console.log(that.myVar) // 1 console.log(this.myVar) // undefined -- 詳見上述的函數宣告 }, 0 ); } ``` 但如果你使用了箭頭函數,*this* 的範圍將會是它的外圍作用域: ```js function myFunc() { this.myVar = 0; setTimeout( () => { // this 的值來自於它的外圍作用域,也就是 myFunc 函數 this.myVar++; console.log(this.myVar) // 1 }, 0 ); } ``` #### 有用資源 - [Arrow functions introduction - WesBos](http://wesbos.com/arrow-functions/) - [JavaScript arrow function - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - [Arrow function and lexical *this*](https://hackernoon.com/javascript-es6-arrow-functions-and-lexical-this-f2a3e2a5e8c4) ### 函數預設值 從 ES2015 JavaScript 更新之後,你可以透過下列的語法為函數中的參數設定預設值: ```js function myFunc(x = 10) { return x; } console.log(myFunc()) // 10 -- 沒有提供任何值,所以 10 在 myFunc 中做為預設值指派給 x console.log(myFunc(5)) // 5 -- 有提供一個參數值,所以 x 在 myFunc 中等於 5 console.log(myFunc(undefined)) // 10 -- 未定義的值,所以預設值被指派給 x console.log(myFunc(null)) // null -- 提供一個值 (null),詳細資料請見下文 ``` 預設值若且為若應用在兩種情況: - 沒有傳入任何參數 - 傳入 *undefined* 這個參數 換句話說,如果你傳入的是 *null* ,那麼預設值的機制是不會被觸發的。 > **注意:** 預設值的指派可以搭配解構參數一同使用 (參照下一個概念的實際例子) #### 外部資源 - [Default parameter value - ES6 Features](http://es6-features.org/#DefaultParameterValues) - [Default parameters - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) ### objects 和 arrays 的解構 *解構 (Destructuring)* 的概念是從 objects 或是 arrays 當中提取部分用值一種相當方便的方法。 舉個簡單的實例,*destructuring* 可以被用來解構函數中的參數或者像是 React 專案中 *this.props* 這樣的用法。 #### 說明和範例程式碼 - Object 試著想想以下這個 object: ```js const person = { firstName: "Nick", lastName: "Anderson", age: 35, sex: "M" } ``` 沒有解構的作法,你只能這樣做: ```js const first = person.firstName; const age = person.age; const city = person.city || "Paris"; ``` 使用解構,你只需要一行: ```js const { firstName: first, age, city = "Paris" } = person; // 這樣就搞定了! console.log(age) // 35 -- 一個名為 age 的新變數被創建出來了,其值等同於 person.age console.log(first) // "Nick" -- 一個名為 first 的新變數被創建出來了,其值等同於person.firstName console.log(firstName) // ReferenceError -- person.firstName 雖然存在,但其值是存在名叫 first 的新變數 console.log(city) // "Paris" -- 一個名為 city 的新變數被創建出來了,同時因為 person.city 是未被定義的,所以 city 將等同於預設值也就是 "Paris"。 ``` **注意:** 在 ```const { age } = person;```當中, *const* 後的括號並不是用來宣告 object 或者是區塊,僅僅是 *解構 (destructuring)* 的使用語法。 - 帶有參數的函數用法 *解構 (Destructuring)* 經常被用來解 objects 中的參數。 沒有解構的作法,你只能這樣做: ```js function joinFirstLastName(person) { const firstName = person.firstName; const lastName = person.lastName; return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` 在解構 obejct 當中 *person* 這個參數時,我們可以得到一個更簡潔的函數: ```js function joinFirstLastName({ firstName, lastName }) { // 我們透過解構 person 分別創造了 firstName 和 lastName 這兩個變數 return firstName + '-' + lastName; } joinFirstLastName(person); // "Nick-Anderson" ``` 解構搭配[箭頭函數](#arrow_func_concept)使得開發過程更加愉快: ```js const joinFirstLastName = ({ firstName, lastName }) => firstName + '-' + lastName; joinFirstLastName(person); // "Nick-Anderson" ``` - Array 讓我們來想想下列這個 array: ```js const myArray = ["a", "b", "c"]; ``` 沒有解構的作法,你只能這樣做: ```js const x = myArray[0]; const y = myArray[1]; ``` 使用解構的作法: ```js const [x, y] = myArray; // 就是這麼簡單! console.log(x) // "a" console.log(y) // "b" ``` #### 有用資源 - [ES6 Features - Destructuring Assignment](http://es6-features.org/#ArrayMatching) - [Destructuring Objects - WesBos](http://wesbos.com/destructuring-objects/) - [ExploringJS - Destructuring](http://exploringjs.com/es6/ch_destructuring.html) ### Array 的操作方法 - map / filter / reduce *Map*,*filter* 和 *reduce* 都是 array 提供的方法,它們源自於 [*functional programming*](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0) 開發範式。 總結一下: - **Array.prototype.map()** 接受一組 array,針對其中的元素進行某些操作和轉換的動作。 - **Array.prototype.filter()** 接受一組 array,依照元素本身決定是否保留,並且將會回傳一個僅含有保留元素的 array - **Array.prototype.reduce()** 接受一組 array,將這些元素合併成一個值並回傳 我會建議在開發時盡可能的遵循函數式編程 (functional programming) 的原則,因為它們是可組合的,簡潔且優雅的。 透過這三種方法,你將可以避免在大多數情況下使用 *for* 和 *forEach*。當你想做一個 *for* 迴圈時,試著用 *map*,*filter* 和 *reduce* 組合看看。起初你可能會覺得窒礙難行,因為它需要你學習一種新的思維方式,但一旦你掌握它了,事情也將變得更加容易。 #### 範例程式碼 ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; const doubledNumbers = numbers.map(n => n * 2); // [0, 2, 4, 6, 8, 10, 12] const evenNumbers = numbers.filter(n => n % 2 === 0); // [0, 2, 4, 6] const sum = numbers.reduce((prev, next) => prev + next, 0); // 21 ``` 透過 map,filter 和 reduce 這幾種組合技去計算出學生成績 >= 10 的總和: ```js const students = [ { name: "Nick", grade: 10 }, { name: "John", grade: 15 }, { name: "Julia", grade: 19 }, { name: "Nathalie", grade: 9 }, ]; const aboveTenSum = students .map(student => student.grade) // map the students array to an array of their grades .filter(grade => grade >= 10) // we filter the grades array to keep those 10 or above .reduce((prev, next) => prev + next, 0); // we sum all the grades 10 or above one by one console.log(aboveTenSum) // 44 -- 10 (Nick) + 15 (John) + 19 (Julia), Nathalie below 10 is ignored ``` #### 說明 讓我們來思考下列這個 array: ```js const numbers = [0, 1, 2, 3, 4, 5, 6]; ``` ##### Array.prototype.map() ```js const doubledNumbers = numbers.map(function(n) { return n * 2; }); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` 發生了什麼事?我們在 *numbers* 這個 array 中使用了 .map 方法,map 將會去迭代 array 中的每一個元素並且回傳給我們的函數。該函數的目標是生成並回傳一個新的值使得 map 可以替換掉原本的 array。 讓我們提取這個函數以便讓解釋更清楚: ```js const doubleN = function(n) { return n * 2; }; const doubledNumbers = numbers.map(doubleN); console.log(doubledNumbers); // [0, 2, 4, 6, 8, 10, 12] ``` ```numbers.map(doubleN)``` 將會產生 ```[doubleN(0), doubleN(1), doubleN(2), doubleN(3), doubleN(4), doubleN(5), doubleN(6)]``` ,而它們分別等同於 ```[0, 2, 4, 6, 8, 10, 12]```。 > **注意:** 如果你不需要回傳一個新的 array 且只想實作一個帶有副作用的迴圈,使用 for / forEach 迴圈會更為符合你所需。 ##### Array.prototype.filter() ```js const evenNumbers = numbers.filter(function(n) { return n % 2 === 0; // true if "n" is par, false if "n" isn't }); console.log(evenNumbers); // [0, 2, 4, 6] ``` 我們在這個充滿 *numbers* 的 array 上使用 .filter 方法,過濾器將會遍歷當中的每一個元素並回傳給我們的函數。函數的目標是回傳一個布林值,它將會確定當前值是否被保留。過濾之後回傳的是一個僅保留所需值的 array。 ##### Array.prototype.reduce() reduce 方法的目標是將進行迭代的 array 中的所有元素 *減少* 到只留下單一值。計算這些元素的方式將取決於你的需求。 ```js const sum = numbers.reduce( function(acc, n) { return acc + n; }, 0 // 進行迭代計算的初始值 ); console.log(sum) //21 ``` 就像 .map 和 .filter 方法一樣, .reduce 方法被應用在 array 上並將函數做為第一個參數。 這次有些變化了: - .reduce 接受兩個參數 第一個參數是在每個迭代步驟中調用的函數。 第二個參數是在第一個迭代步驟(讀取下一個之用)的累加器變數的值(此處是 *acc*)。 - 帶有參數的函數用法 做為 .reduce 的第一個參數所傳遞的函數需要兩個參數。第一個(此處是 *acc*)是累加器變數,而第二個參數(*n*)則是當前元素。 累加器變數的值等於 **上一次** 迭代步驟中函數的回傳值。在迭代過程的第一步,*acc* 等於你做為 .reduce 時第二個參數所傳遞的值。 ###### 進行第一次迭代 ```acc = 0``` 因為我們把 0 做為 reduce 的第二個參數 ```n = 0``` *number* array 的第一個元素 函數回傳 *acc* + *n* --> 0 + 0 --> 0 ###### 進行第二次迭代 ```acc = 0``` 因為它是上次迭代所回傳的值 ```n = 1``` *number* array 的第二個元素 函數回傳 *acc* + *n* --> 0 + 1 --> 1 ###### 進行第三次迭代 ```acc = 1``` 因為它是上次迭代所回傳的值 ```n = 2``` *number* array 的第三個元素 函數回傳 *acc* + *n* --> 1 + 2 --> 3 ###### 進行第四次迭代 ```acc = 3``` 因為它是上次迭代所回傳的值 ```n = 3``` *number* array 的第四個元素 函數回傳 *acc* + *n* --> 3 + 3 --> 6 ###### [...] 進行最後一次迭代 ```acc = 15``` 因為它是上次迭代所回傳的值 ```n = 6``` *number* array 的最後一個元素 函數回傳 *acc* + *n* --> 15 + 6 --> 21 因為它是最後一個迭代步驟了, **.reduce** 將回傳 21。 #### 外部資源 - [Understanding map / filter / reduce in JS](https://hackernoon.com/understanding-map-filter-and-reduce-in-javascript-5df1c7eee464) ### 展開運算子 "..." 展開運算子 ```...``` 的語法在 ES2015 之下已經支援了,而它將會被用於把可迭代的元素 (像是 array) 擴展到容納更多元素。 #### 範例程式碼 ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ```js function myFunc(x, y, ...params) { console.log(x); console.log(y); console.log(params) } myFunc("a", "b", "c", "d", "e", "f") // "a" // "b" // ["c", "d", "e", "f"] ``` ```js const { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } ``` #### 說明 ##### 迭代用法 (如同 array) 如果我們有以下兩個 arrays: ```js const arr1 = ["a", "b", "c"]; const arr2 = [arr1, "d", "e", "f"]; // [["a", "b", "c"], "d", "e", "f"] ``` *arr2* 中的第一個元素是 array ,因為 *arr1* 是被注入到 *arr2* 之中的。但我們真正想要得到的 *arr2* 是一個純字母的 array。為了做到這點,我們可以將 *arr1* *擴展 (spread)* 到 *arr2*。 透過展開運算子 ```js const arr1 = ["a", "b", "c"]; const arr2 = [...arr1, "d", "e", "f"]; // ["a", "b", "c", "d", "e", "f"] ``` ##### 不定參數 在有著不定參數的函數當中,我們可以使用 rest 運算子將參數注入到我們可以進行迴圈操作的 array。這裡已經有一個名為 **arguments** 的 object 被綁定在函數上,等同於把 array 中的所有參數都傳遞給函數。 ```js function myFunc() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } myFunc("Nick", "Anderson", 10, 12, 6); // "Nick" // "Anderson" // 10 // 12 // 6 ``` 但是如果說我們希望創造的是一個包含他的各科成績和平均成績的新學生,提取前兩個參數 (firstName 和 lastName)並把剩下的元素迭代生成一個 array 的作法是否會更有效率呢? 這正是 rest 運算子允許我們做的事! ```js function createStudent(firstName, lastName, ...grades) { // firstName = "Nick" // lastName = "Anderson" // [10, 12, 6] -- "..." 運算子會把 firstName 和 lastName 以外的參數傳入,同時創造一個包含這些元素,叫做 "grades" 的 array const avgGrade = grades.reduce((acc, curr) => acc + curr, 0) / grades.length; // 計算平均成績 return { firstName: firstName, lastName: lastName, grades: grades, avgGrade: avgGrade } } const student = createStudent("Nick", "Anderson", 10, 12, 6); console.log(student); // { // firstName: "Nick", // lastName: "Anderson", // grades: [10, 12, 6], // avgGrade: 9,33 // } ``` > **注意:** createStudent 這個函數的舉例其實並不太好,因為我們並沒有去檢查 grades.length 是否存在又或者它根本等於 0。但是這個例子的確能夠幫助我們更為容易理解其中運作,所以我並沒有花額外的時間處理這個情況,請見諒。 ##### Object 屬性擴展 關於這點,我建議你去閱讀先前有關 rest 運算子,迭代運作和帶有不定參數的函數等相關說明。 ```js const myObj = { x: 1, y: 2, a: 3, b: 4 }; const { x, y, ...z } = myObj; // object 在此處被解構 console.log(x); // 1 console.log(y); // 2 console.log(z); // { a: 3, b: 4 } // 解構後剩餘的部分都放在 z : 也就是 myObj 這個物件經過解構後鎖剩下的東西 const n = { x, y, ...z }; console.log(n); // { x: 1, y: 2, a: 3, b: 4 } // 把 z 所包含的屬性擴展到 n 當中 ``` #### 外部資源 - [TC39 - Object rest/spread](https://github.com/tc39/proposal-object-rest-spread) - [Spread operator introduction - WesBos](https://github.com/wesbos/es6-articles/blob/master/28%20-%20Spread%20Operator%20Introduction.md) - [JavaScript & the spread operator](https://codeburst.io/javascript-the-spread-operator-a867a71668ca) - [6 Great uses of the spread operator](https://davidwalsh.name/spread-operator) ### Object 屬性簡寫 當我們想要把某個物件屬性指派給變數,如果變數名稱等同於屬性名稱,你可以試著執行以下操作: ```js const x = 10; const myObj = { x }; console.log(myObj.x) // 10 ``` #### 說明 通常 (pre-ES2015) 當你宣告一個新的 *物件實體語法 (object literal)* 並且想要使用變數做為物件屬性的值時,你可能會寫出以下類似的程式碼: ```js const x = 10; const y = 20; const myObj = { x: x, // 將變數 x 賦值給 myObj.x y: y // 將變數 y 賦值給 myObj.y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` 你可以發現,這樣的作法其實相當繁瑣,因為 myObj 的屬性名和要指派給這些屬性的變數名稱都是相同的。 透過使用 ES2015,當變數名稱和屬性名稱相同時,你可以把程式碼這樣簡寫: ```js const x = 10; const y = 20; const myObj = { x, y }; console.log(myObj.x) // 10 console.log(myObj.y) // 20 ``` #### 外部資源 - [Property shorthand - ES6 Features](http://es6-features.org/#PropertyShorthand) ### Promises promise 是一個可以從異步函數 ([參考](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#3cd0)) 同步回傳的函數。 Promises 可以被用來避開 [回調地獄 (callback hell)](http://callbackhell.com/),而且它們在現代 JavaScript 專案中也越來越常被使用到。 #### 範例程式碼 ```js const fetchingPosts = new Promise((res, rej) => { $.get("/posts") .done(posts => res(posts)) .fail(err => rej(err)); }); fetchingPosts .then(posts => console.log(posts)) .catch(err => console.log(err)); ``` #### 說明 當你在進行 *Ajax 請求* 時,回傳絕對是非同步的,因為資源請求需要時間。如果你要的資源由於某些原因 (404) 而不能使用,請求的資源可能永遠都不會出現。 為了處理這類情況,ES2015 為我們提供了 *promises*。Promises 可以有三種不同的狀態: - 等待中 (Pending) - 達成 (Fulfilled) - 拒絕 (Rejected) 假設我們希望使用 promises 去進行 Ajax 請求以獲取 X 這項資源。 ##### 創造 promise 首先要創造一個 promise。我們將會使用 jQuery 的 get 方法去進行資源 X 的 Ajax 請求。 ```js const xFetcherPromise = new Promise( // 使用 "new" 這個關鍵字並把它存至一個變數 function(resolve, reject) { // Promise 建構子需要一個有著 resolve 和 reject 這兩個參數的函數作為參數 $.get("X") // 執行 Ajax 請求 .done(function(X) { // 一旦請求完成... resolve(X); // ... 把 X 做為參數去 resolve promise }) .fail(function(error) { // 如果請求失敗... reject(error); // ... 把 error 做為參數去 reject promise }); } ) ``` 如上所示,Promise 物件需要一個帶有兩個參數 ( **resolve** 以及 **reject** ) 的函數。這兩個參數會把 *pending* 狀態的 promise 分別進行 *fulfilled* 和 *rejected* 的處理。 但在此時此刻,promise 尚未被使用,它僅僅是被宣告並且儲存到 *xFetcherPromise* 這個變數當中!所以它並不存在當前的狀態。 ##### 使用 promise 為了使用 promise,我們可以進行以下的實作: ```js xFetcherPromise .then(function(X) { console.log(X); }) .catch(function(err) { console.log(err) }) ``` ```.then``` 是一種方法,一旦被調用將會把 xFetcherPromise 調整至 **pending** 狀態。當被調用時,promise 本體會運行,在這個範例當中,Ajax 請求正在進行中。 如果成功,將會調用 *resolve*,並且 ```.then``` 將會執行做為參數傳遞的函數。 如果失敗,將會調用 *reject*,並且 ```.catch``` 將會執行做為參數傳遞的函數。 #### 外部資源 - [JavaScript Promises for dummies - Jecelyn Yeen](https://scotch.io/tutorials/javascript-promises-for-dummies) - [JavaScript Promise API - David Walsh](https://davidwalsh.name/promises) - [Using promises - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) - [What is a promise - Eric Elliott](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261) - [JavaScript Promises: an Introduction - Jake Archibald](https://developers.google.com/web/fundamentals/getting-started/primers/promises) - [Promise documentation - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) ### 模板字符串 模板字符串是一種單行和多行字符串的 [*表達式差值 (expression interpolation)*](https://en.wikipedia.org/wiki/String_interpolation)。 換句話說,它是一種新的字符串語法,你可以更方便地在 JavaScript 表達式中使用 (例如變數)。 #### 範例程式碼 ```js const name = "Nick"; `Hello ${name}, the following expression is equal to four : ${2+2}`; // Hello Nick, the following expression is equal to four: 4 ``` #### 外部資源 - [String interpolation - ES6 Features](http://es6-features.org/#StringInterpolation) - [ES6 Template Strings - Addy Osmani](https://developers.google.com/web/updates/2015/01/ES6-Template-Strings) ### Imports / Exports ES6 模組被用來存取顯式輸出 (explicitly export)的變數或是函數。 我強烈建議你去瀏覽 MDN 上有關 import/export (請參考下面的外部資源) 的文章,它們寫的既簡潔又完整。 #### 說明與範例程式碼 - Named exports Named exports 被用於從模組中輸出多個值的情況。你只能命名將要輸出的變數 (不能是函數或是類別),所以當你想要輸出一個函數時,你必須先把它儲存在一個變數中。 ```js // mathConstants.js export const pi = 3.14; export const exp = 2.7; export const alpha = 0.35; // ------------- // myFile.js import { pi, exp } from './mathConstants.js'; // 對 import 進行解構 console.log(pi) // 3.14 console.log(exp) // 2.7 // ------------- // mySecondFile.js import * as constants from './mathConstants.js'; // 把所有的值輸出到 constants 這個變數 console.log(constants.pi) // 3.14 console.log(constants.exp) // 2.7 ``` - 預設 import / export 關於輸出,每個模組在預設下只能有一個輸出。一個預設的輸出可以是函數,類別,物件又或者是任何東西。這個值被認為是 "主要的" 輸出值,因為它將會是最簡單純粹的輸出。[參考: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Description) ```js // coolNumber.js const ultimateNumber = 42; export default ultimateNumber; // ------------ // myFile.js import number from './coolNumber.js'; // 預設輸出將獨立於其名稱, 將被自動注入到 number 這個變數; console.log(number) // 42 ``` 函數輸出: ```js // sum.js export default function sum(x, y) { return x + y; } // ------------- // myFile.js import sum from './sum.js'; const result = sum(1, 2); console.log(result) // 3 ``` #### 外部資源 - [Export - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) - [Import - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) - [Understanding ES6 Modules](https://www.sitepoint.com/understanding-es6-modules/) - [Modules in JavaScript](http://exploringjs.com/es6/ch_modules.html#sec_modules-in-javascript) ### JavaScript *this* *this* 這個運算子的行為和其他語言是不太一樣的,在大多數情況之下是由函數的調用方式決定。([參考: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)). 這個概念有很多精妙之處,並不是那麼容易理解,我強烈建議你好好研讀下面的外部資源。因此,我將會提供我個人對於 *this* 的一點理解和想法。我是從 [Yehuda Katz 寫的這篇文章](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/) 學到了這個技巧。 ```js function myFunc() { ... } // 在每個述句後頭,你都可以在 myFunc 中找到 this 的值 myFunc.call("myString", "hello") // "myString" -- 首先, .call 參數的值被注入到 this // 非嚴格模式下 myFunc("hello") // window -- myFunc() 是 myFunc.call(window, "hello") 的語法糖 // 嚴格模式下 myFunc("hello") // undefined -- myFunc() 是 myFunc.call(undefined, "hello") 的語法糖 ``` ```js var person = { myFunc: function() { ... } } person.myFunc.call(person, "test") // person 物件 -- 調用參數注入 this person.myFunc("test") // person Object -- person.myFunc() 是 person.myFunc.call(person, "test") 的語法糖 var myBoundFunc = person.myFunc.bind("hello") // 創造了一個函數,並且把 "hello" 注入到 this person.myFunc("test") // person Object -- 綁定方法對原有方法並無造成影響 myBoundFunc("test") // "hello" -- myBoundFunc 是把帶有 "hello" 的 person.myFunc 綁定到 this ``` #### 外部資源 - [Understanding JavaScript Function Invocation and "this" - Yehuda Katz](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/) - [JavaScript this - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) ### Class JavaScript 是一個 [基於原型](https://en.wikipedia.org/wiki/Prototype-based_programming) 的語言 (然而 Java 是 [基於類別](https://en.wikipedia.org/wiki/Class-based_programming) 的語言)。 ES6 引入了 JavaScript 類別,它們是基於原型繼承的語法糖,而 **不是** 真正意義上基於類別的繼承模型。([參考](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)). *類別 (class)* 一詞的確容易出錯,尤其是你同時也熟悉其他語言的情況下。如果真的有此困擾,請避免在這樣的認知下思考 JavaScript 的類別行為,並把它當作一個完全不同的新概念。 由於此份文件的目標不在於從頭教會你 JavaScript,我相信你早已知道什麼是原型,以及它們的行為模式。不過這裡還是有一些參考連結,以方便你去理解這些概念: - [Understanding Prototypes in JS - Yehuda Katz](http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/) - [A plain English guide to JS prototypes - Sebastian Porto](http://sporto.github.io/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/) - [Inheritance and the prototype chain - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) #### 範例 ES6 之前的原型語法: ```js var Person = function(name, age) { this.name = name; this.age = age; } Person.prototype.stringSentence = function() { return "Hello, my name is " + this.name + " and I'm " + this.age; } ``` ES6 之後的類型語法: ```js class Person { constructor(name, age) { this.name = name; this.age = age; } stringSentence() { return "Hello, my name is " + this.name + " and I'm " + this.age; } } const myPerson = new Person("Manu", 23); console.log(myPerson.age) // 23 console.log(myPerson.stringSentence()) // "Hello, my name is Manu and I'm 23 ``` #### 外部資源 更好的理解原型: - [Understanding Prototypes in JS - Yehuda Katz](http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/) - [A plain English guide to JS prototypes - Sebastian Porto](http://sporto.github.io/blog/2013/02/22/a-plain-english-guide-to-javascript-prototypes/) - [Inheritance and the prototype chain - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) 更好的理解類別: - [ES6 Classes in Depth - Nicolas Bevacqua](https://ponyfoo.com/articles/es6-classes-in-depth) - [ES6 Features - Classes](http://es6-features.org/#ClassDefinition) - [JavaScript Classes - MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) ### Async Await 除了 [Promises](#promises) 以外,還有一種新語法你可能會遇到,那就是被稱作非同步的 *async / await*。 async/await 的目的在於簡化同步使用 promise 的行為,並對一組 promise 執行一些處理。正如同Promises 類似於結構化之後的回調 (callback),async/await 同樣類似於組合生成器 (combining generators) 和 promises。 ([參考: MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)) > **注意:** 你必須先行了解到什麼是 promises 和它們是如何運作的,然後再去嘗試理解 async / await 的概念,因為後者是基於前者的進一步延伸。 > **注意:** [*await* must be used in an *async* function](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9#f3f0) 意味著你不能程式碼的頂部使用 await,因為它並不在異步函數之內。 #### 說明與範例程式碼 *Async / Await* 是基於 promises 之上的新概念,但它們更允許你使用命令式風格 (imperative style)去撰寫程式。 `await` 表達式使 `async` 函數暫停執行,直到 promise 被成功解析才會繼續執行。任何 `async` 函數堆將回傳 `Promise`,並將其解析為回傳值。 ```js async function getGithubUser(handle) { // async 這個關鍵字允許在函數中使用 await,並且意味著函數將回傳一個 promise try { // 這是 async / await 使用的方式 const url = `https://api.github.com/users/${handle}`; const response = await fetch(url); // "同步" 等待 fetch 去解析 promise,然後才會跳轉到下一行 return response.json(); } catch (err) { alert(err); } } getGithubUser('mbeaudru').then(user => console.log(user)); // 印出 user 的值 - 不能使用 await 語法,因為此段程式碼並不在 async 函數當中 ``` #### 外部資源 - [Async/Await - JavaScript.Info](https://javascript.info/async-await) - [ES7 Async/Await](http://rossboucher.com/await/#/) - [6 Reasons Why JavaScript’s Async/Await Blows Promises Away](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9) - [JavaScript awaits](https://dev.to/kayis/javascript-awaits) - [Using Async Await in Express with Node 8](https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016) - [Async Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) - [Await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) ## 術語詞彙 ### 作用域範圍 (scope) 在上下文之中有著 "明顯可見的 (visible)" 值和表達式,又或者是可以被參照的。如果變數或是表達式並不在 "當前作用域和範圍",那麼它將會是不能用的。 資料來源: [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Scope) ### 變數變異 (Variable mutation) 一個變數在被宣告之後發生初始值變化的過程。 ```js var myArray = []; myArray.push("firstEl") // myArray 正在變化 ``` 如果變數不能被改變的話,我們會說這個變數是 *不可變的 (immutable)* 。 [查看 MDN Mutable 文章](https://developer.mozilla.org/en-US/docs/Glossary/Mutable) 了解更多詳細資料。 ================================================ FILE: Kotlin/README.md ================================================ # Introduction Kotlin is a new programming language for the JVM. It produces Java bytecode, supports Android and generates JavaScript. The latest version of the language is [Kotlin M5.3]("http://blog.jetbrains.com/kotlin/2013/06/kotlin-m5-3-idea-13-delegated-properties-and-more/") Kotlin project website is at [kotlin.jetbrains.org](http://kotlin.jetbrains.org). All the codes here can be copied and run on [Kotlin online editor](http://kotlin-demo.jetbrains.com/). Let's get started. # Basics - You do not need `;` to break statements. - Comments are similar to Java or C#, `/* This is comment */` for multi line comments and `// for single line comment`. - Unlike Java, you do not need to match your file name to your class name. - Like JavaScript, you can create functions outside classes. So there is no need to stuff your functions as static members of classes like what you do in C# or Java. - Kotlin has string templates, which is awesome. e.g. `"$firstName $lastName"` for simple variable name or `"${person.name} is ${1 * 2}"` for any expressions. You can still do the string concatenation if you like e.g. `"hello " + "world"`, but that means being stupid. - It has no tuple although Kotlin's data classes is an option to use in place of tuple. ## Variables - There are two keywords for variable declaration, **var** and **val**. - Use **var** when the variable value is to be modified and **val** where the variable value will not change after first assigned. - This **val** is similar to **readonly** keyword in C# or **final** keyword in Java. - **val** variable must be initialized at declaration. - Unlike Java or C#, you declare the type of a variable after the name, e.g. `var firstName : String` - Number primitive types are as follows: Double, Float, Long, Int, Short, Byte. There is no automatic conversion between types. You have to explicitly convert them. - More primitive types: Char, String, Boolean. - All variable declarations in Kotlin must be initialized. - The keyword `void` common in Java or C# is called `Unit` in Kotlin. ### Null In Kotlin you have to decide whether a variable can be assigned null or not. This applies to both primitives or class types. A nullable variable is marked by assigning ? after the type, e.g. `var firstName: String?` You can assign a value from not-nullable to nullable type without any problem. ```kotlin fun main(args : Array) { val firstName : String = "Adam" val name : String? = firstName print("$name") } ``` The other way around though requires that you declare that this nullable variable does not contain null at the point of assignment with !! operator (which pretty much declares : "I am sure this nullable variable is not null at this point") ```kotlin fun main(args : Array) { val name : String? = "Adam" val firstName : String = name!! print("$firstName") } ``` ### Type inference Kotlin is pretty smart about inferring what type a variable is, whether it is primitives or class. This is similar to the var keyword in C#. ```kotlin fun main(args : Array) { val firstName = "Adam" val middle = 'c' val lastName = "Brown" val age = 15 println("$firstName $middle $lastNameis $age") } ``` You will encounter in further examples of more capabilities of Kotlin's type inference. # Functions We are going to spend a considerable time in discussing function because it has many different forms and subtleties. Here is a list of facilities that Kotlin provides for functions - Single expression function. - Optional parameter. - Positional argument and named argument. - Variable argument. - Single expression function. - Function type. - Function literals. - Callable references. - Extension functions. - Infix function call. - Local function. - Closure. - Generic function. - Operator overloading. Below is an example of functions ```kotlin fun main(args : Array) { greet(englishGreeting()) greet(italianGreeting()) } fun greet(msg : String){ println(msg) } fun englishGreeting() : String = "Hello world" fun italianGreeting() : String{ return "bon giorno" } ``` - Functions can exists on their own. - It is marked by **fun** keyword. - If a function returns value, you declare it after the function name. - `englishGreeting()` is a *single expression function*. - A void function such as `greet()` returns Unit type but you are not required to declare it. - All parameters in a Kotlin function are read only. You are actually not allowed to mark it with either `val` or `var` keyword. ## Single expression function This is a shorthand form in defining a function when you only have a single expression to be executed. ```kotlin fun main(args : Array) { val res = add(1,1) show("$res") } fun add(a : Int, b : Int) = a + b fun show(msg : String) = println("$msg") ``` As you can see above, in a single expression function, the function return type is inferred. You can declare the return type if you want to such as below. ```kotlin fun main(args : Array) { val res = add(1,1) show("$res") } fun add(a : Int, b : Int) : Int = a + b fun show(msg : String) : Unit = println("$msg") ``` ## Optional parameters Kotlin allows you to assign default values for your parameters, making them optional. ```kotlin fun main(args : Array) { show() show("Good morning") } fun show (msg : String = "Hello World"){ println("$msg") } ``` If you are mixing mandatory parameter and optional parameter, the mandatory parameters must be listed first. ## Arguments ```kotlin fun main(args : Array) { greet(firstName = "Frasensco", lastName = "Merini") greet(lastName = "John", firstName = "Stamos") greet("Borat", "Ismail") greet("Crystal", lastName = "Stamos") call("Xavier", age = 20, location = "Portugal") } fun greet(firstName : String, lastName : String){ println("Good morning $firstName $lastName") } fun call(name : String, location : String, age : Int){ println("Call $name who lives at $location and he is $age old") } ``` Kotlin allows positional argument, named argument and the mix between the two. When you mix named and positional argument, you must start with positional argument. ### Variable arguments Use the keyword **vararg**. ```kotlin fun main(args : Array) { names("John", "Adam", "Joy") } fun names(vararg names : String){ for(n in names){ println("$n") } } ``` If **vararg** parameter is not the last parameter, named argument must be used to supply the function argument. ```kotlin fun main(args : Array) { names("John", "Adam", "Joy", age = 20) } fun names(vararg names : String, age : Int){ for(n in names){ println("$n is $age old") } } ``` ### vararg produces array of argument ```kotlin fun main(args : Array) { names("John", "Adam", "Joy") } fun names(vararg names : String){ println("Argument length is ${names.size}") println("${names[0]}") val nns : Array = names println("${nns[1]}") } ``` ### Using array to supply variable arguments Use the * operator in front of the array variable ```kotlin fun main(args : Array) { val n = array("John", "Adam", "Joy") names(*n) } fun names(vararg names : String){ println("Argument length is ${names.size}") println("${names[0]}") val nns : Array = names println("${nns[1]}") } ``` ### Passing one varargs argument to another ```kotlin fun main(args : Array) { val n = array("John", "Adam", "Joy") fugitives(*n) } , fun fugitives(vararg escapees: String){ names(*escapees) } fun names(vararg names : String){ println("Argument length is ${names.size}") println("${names[0]}") val nns : Array = names println("${nns[1]}") } ``` Since **vararg** creates an array, you simply use the * operator to pass one **vararg** to another. ##Function Types and Function Literals A function type is a type consisted of a function signature and function return type that are separated by -> operator. In its simplest form, it looks as follows: `() -> Unit` Above is a type for a function that takes no parameter and returns a Unit (void in other language parlance) `() -> String` Above is a type for a function that takes no parameter and return a String `(String) -> Unit` Above is a type for a function that takes a string and returns nothing. `(String, Float) -> Unit` Above is a type for a function that takes two parameters (String and Float) and returns nothing. Because a function type is just a type, it means that you can assign it to a variable, you can pass it as a function argument and you can return it from a function. ### Different ways to write function literals ```kotlin val m = { (x : String) -> println("$x") } val n : (String) -> Unit = { x -> println("$x") } val o : (String) -> Unit = { (x : String) -> println("$x") } fun main(args : Array) { m("good morning") n("good morning") o("good morning") } ``` Above code is an example of function literals. All `m`, `n` and `o` represent the same function. Below is a function that returns a function type ```kotlin fun main(args : Array) { val greet = greetingFrom("Cairo, Egypt") greet("Brown") } fun greetingFrom(location : String) : (String) -> Unit{ return { name -> println ("Hello $name from $location")} } ``` Below shows that you can specify a function type as an argument and supply it with function literal with corresponding function signature and return type. ```kotlin fun evening(): String = "Good Evening" fun main(args : Array){ say({ "good morning"}) say { val msg = "good afternoon" msg } say({evening()}) } fun say(greet : () -> String){ println("${greet()}") } ``` ## Callable references How about if you already have a function that you want to pass as a parameter? You prefix the function name with '::' ```kotlin fun main(args : Array) { calcAndShow(10,10, ::add) //20 calcAndShow(10,10, ::multiply) /100 calcAndShow(10,19, { x, y -> x - y }) //-9 } fun calcAndShow(a : Int, b : Int, func : (a : Int, b : Int) -> Int){ val result = func (a, b) println("$result") } fun add(a : Int, b : Int) : Int = a + b fun multiply (a : Int, b : Int) : Int = a * b ``` ## Function expansion When you call a function which has a function type as the last argument, you can expand it by { } ```kotlin fun main(args : Array) { val a = calculate(1) { x -> 10 + x } //11 val b = calculate(2) { x -> 20 * x } //40 println("a = $a, b = $b") } fun calculate(a : Int, calc : (Int) -> Int) : Int{ return calc(a) } ``` ## Closure Kotlin support Closure as highlighted by the example below ```kotlin fun main(args : Array) { val total = add(1)(2) println("Total value is $total") } fun add(a : Int) : (Int) -> Int{ return { x -> a + x } } ``` ## Local function You can declare a function inside a function. It will have access to the local variable at the parent function. ```kotlin fun main(args : Array){ accumulate() } fun accumulate(){ var i = 0 fun add(){ i++ } for (i in 1..10){ add() } println("i is now $i") } //It prints "i is now 10" ``` ## Extension function Extension function enables a function to be accessed from the type function. It works in the form of __type.function__ Inside the function, the keyword `this` refers to the instance. For example ```kotlin fun Int.show(){ println("This number is $this") } fun main(args : Array){ 3.show() } ``` Above example shows how the `Int` built in type has been enriched by `show` extension function. Notice the use of `this` keyword that refers to the `3` number. **Notice** You can extend a function on a nullable type and it will be accessible for both nullable and non nullable type. The reverse though does not apply. ```kotlin fun Int?.show(){ println("This number is $this") } fun Int.show2(){ println("This number is $this") } fun main(args : Array){ var number : Int? = null number.show() 5.show() //number.show2() will not compile } ``` ### Extension function expressed in function literals ```kotlin val show = { Int.() -> println("This is number $this") } val add = { Int.(number : Int) : Int -> val now = this + number now } fun main(args : Array){ 5.add(10).show() } ``` Both `show` and `add` extension functions are expressed in literal format. Please notice that `add` function returns an `Int`. ### Extension function in infix form ```kotlin fun main(args : Array) { val res = 1 add 2 println("$res") } fun Int.add (one : Int) : Int = this + one ``` If the extension function only takes one argument, you can call them in infix form (you drop the . between the type and the function). So instead of `1.add(2)`, you can call it in the form of `1 add 2`. This makes certain constructs looks natural (more like an operator than a function call) and especially useful in construction DSL in Kotlin. ## Variable arguments and function type argument `vararg` parameter can also be naturally combined with a function type parameter. ```kotlin fun main(args : Array) { names("John", "Adam", "Joy"){ name -> println ("$name") } } fun names(vararg names : String, print : (String) -> Unit){ for(n in names){ print(n) } } ``` above code can also be expressed in this matter (using named argument) ```kotlin fun main(args : Array) { names("John", "Adam", "Joy", print = {name -> println ("$name")}) } fun names(vararg names : String, print : (String) -> Unit){ for(n in names){ print(n) } } ``` # Control Structures ## If statement Kotlin **if** statement should look familiar with other language ```kotlin fun main(args : Array) { val total = 10 if (total > 5){ println("$total is greater than 5") }else if (total > 10){ println("$total is greater than 10") }else{ println("$total is less than 6") } } ``` ================================================ FILE: MATLAB/README.md ================================================ # MATLAB Cheat Sheet Based off of [Learn X in Y Minutes](http://learnxinyminutes.com/docs/matlab/). MATLAB stands for MATrix LABoratory. It is a powerful numerical computing language commonly used in engineering and mathematics. ## Quick Access Links 1. [Basics](#basics) 1. [Comments and Code Sections](#comments) 2. [Helper Commands](#commands) 3. [Variables and Expressions](#vars) 2. [Matrices and Vectors](#matrices) 1. [Declarations](#declarations) 2. [Splicing and Dicing](#splice) 3. [Arithmetic and Operations](#arith) 3. [Plots](#plots) 4. [Functions and Scripts](#functions) 5. [Programming Logic](#logic) 6. [Math/Engineering](#math) 1. [Common Math Functions](#common) 2. [Transfer Functions](#transfer) 7. [Vectorization](#vectorization) 8. [Optimization](#optimization) 9. [Machine Learning](#ML) 10. [Simulink](#simulink) ## 1. Basics ### i. Comments and Code Sections ```matlab %% Code sections start with two percent signs. Section titles go on the same line. % Comments start with a percent sign. %{ Multi line comments look something like this %} % Two percent signs denote the start of a new code section % Individual code sections can be run by moving the cursor to the section followed by % either clicking the "Run Section" button % or using Ctrl+Shift+Enter (Windows) or Cmd+Shift+Return (OS X) %% This is the start of a code section % One way of using sections is to separate expensive but unchanging start-up code like loading data load myFile.mat y %% This is another code section % This section can be edited and run repeatedly on its own, and is helpful for exploratory programming and demos A = A * 2; plot(A); % commands can span multiple lines, using '...': a = 1 + 2 + ... + 4 ``` ### ii. Helper Commands ```matlab % commands can be passed to the operating system !ping google.com who % Displays all variables in memory whos % Displays all variables in memory, with their types clear % Erases all your variables from memory clear('A') % Erases a particular variable openvar('A') % Open variable in variable editor clc % Erases the writing on your Command Window diary % Toggle writing Command Window text to file ctrl-c % Abort current computation close all % Closes all figures edit('myfunction.m') % Open function/script in editor type('myfunction.m') % Print the source of function/script to Command Window profile on % turns on the code profiler profile off % turns off the code profiler profile viewer % Open profiler help command % Displays documentation for command in Command Window doc command % Displays documentation for command in Help Window lookfor command % Searches for command in the first commented line of all functions lookfor command -all % searches for command in all functions % Output formatting format short % 4 decimals in a floating number format long % 15 decimals format bank % only two digits after decimal point - for financial calculations fprintf('text') % print "text" to the screen disp('text') % print "text" to the screen % pressing the up key shows you a history of previous commands ``` ### iii. Variables and Expressions ```matlab % Variables & Expressions myVariable = 4 % Notice Workspace pane shows newly created variable myVariable = 4; % Semi colon suppresses output to the Command Window 4 + 6 % ans = 10 8 * myVariable % ans = 32 2 ^ 3 % ans = 8 a = 2; b = 3; c = exp(a)*sin(pi/2) % c = 7.3891 % Logicals 1 > 5 % ans = 0 10 >= 10 % ans = 1 3 ~= 4 % Not equal to -> ans = 1 3 == 3 % equal to -> ans = 1 3 > 1 && 4 > 1 % AND -> ans = 1 3 > 1 || 4 > 1 % OR -> ans = 1 ~1 % NOT -> ans = 0 % Logicals can be applied to matrices: A > 5 % for each element, if condition is true, that element is 1 in returned matrix A( A > 5 ) % returns a vector containing the elements in A for which condition is true % Strings a = 'MyString' length(a) % ans = 8 a(2) % ans = y [a,a] % ans = MyStringMyString % Cells a = {'one', 'two', 'three'} a(1) % ans = 'one' - returns a cell char(a(1)) % ans = one - returns a string % Structures A.b = {'one','two'}; A.c = [1 2]; A.d.e = false; % Variables can be saved to .mat files save('myFileName.mat') % Save the variables in your Workspace load('myFileName.mat') % Load saved variables into Workspace ``` ##2. Matrices and Vectors **IMPORTANT: Indices in Matlab start at 1, not 0** ### i. Declarations ```matlab % Vectors x = [4 32 53 7 1] x(2) % ans = 32 x(2:3) % ans = 32 53 x(2:end) % ans = 32 53 7 1 x = [4; 32; 53; 7; 1] % Column vector x = [1:10] % x = 1 2 3 4 5 6 7 8 9 10 x = [1:2:10] % Increment by 2, i.e. x = 1 3 5 7 9 % Matrices A = [1 2 3; 4 5 6; 7 8 9] % Rows are separated by a semicolon; elements are separated with space or comma % A = % 1 2 3 % 4 5 6 % 7 8 9 A(2,3) % ans = 6, A(row, column) A(6) % ans = 8 % (implicitly concatenates columns into vector, then indexes into that) A(2,3) = 42 % Update row 2 col 3 with 42 % A = % 1 2 3 % 4 5 42 % 7 8 9 ``` ### ii. Splicing and Dicing ```matlab A(2:3,2:3) % Creates a new matrix from the old one %ans = % 5 42 % 8 9 A(:,1) % All rows in column 1 %ans = % 1 % 4 % 7 A(1,:) % All columns in row 1 %ans = % 1 2 3 [A ; A] % Concatenation of matrices (vertically) %ans = % 1 2 3 % 4 5 42 % 7 8 9 % 1 2 3 % 4 5 42 % 7 8 9 % this is the same as vertcat(A,A); [A , A] % Concatenation of matrices (horizontally) %ans = % 1 2 3 1 2 3 % 4 5 42 4 5 42 % 7 8 9 7 8 9 % this is the same as horzcat(A,A); A(:, [3 1 2]) % Rearrange the columns of original matrix %ans = % 3 1 2 % 42 4 5 % 9 7 8 A(1, :) =[] % Delete the first row of the matrix A(:, 1) =[] % Delete the first column of the matrix squeeze(A); % Removes singular dimensions ie. 2x1x3 -> 2x3 ``` ### iii. Arithmetic and Operations ```matlab transpose(A) % Transpose the matrix, which is the same as: A one A' % Concise version of complex transpose A.' % Concise version of transpose (without taking complex conjugate) size(A) % ans = 3 3 % Element by Element Arithmetic vs. Matrix Arithmetic % On their own, the arithmetic operators act on whole matrices. When preceded % by a period, they act on each element instead. For example: A * B % Matrix multiplication A .* B % Multiple each element in A by its corresponding element in B % There are several pairs of functions, where one acts on each element, and % the other (whose name ends in m) acts on the whole matrix. exp(A) % exponentiate each element expm(A) % calculate the matrix exponential sqrt(A) % take the square root of each element sqrtm(A) % find the matrix whose square is A % Solving matrix equations (if no solution, returns a least squares solution) % The \ and / operators are equivalent to the functions mldivide and mrdivide x=A\b % Solves Ax=b. Faster and more numerically accurate than using inv(A)*b. x=b/A % Solves xA=b inv(A) % calculate the inverse matrix pinv(A) % calculate the pseudo-inverse % Common matrix functions zeros(m,n) % m x n matrix of 0's ones(m,n) % m x n matrix of 1's diag(A) % Extracts the diagonal elements of a matrix A diag(x) % Construct a matrix with diagonal elements listed in x, and zeroes elsewhere eye(m,n) % Identity matrix linspace(x1, x2, n) % Return n equally spaced points, with min x1 and max x2 inv(A) % Inverse of matrix A det(A) % Determinant of A eig(A) % Eigenvalues and eigenvectors of A trace(A) % Trace of matrix - equivalent to sum(diag(A)) isempty(A) % Tests if array is empty all(A) % Tests if all elements are nonzero or true any(A) % Tests if any elements are nonzero or true isequal(A, B) % Tests equality of two arrays numel(A) % Number of elements in matrix triu(x) % Returns the upper triangular part of x tril(x) % Returns the lower triangular part of x cross(A,B) % Returns the cross product of the vectors A and B dot(A,B) % Returns scalar product of two vectors (must have the same length) transpose(A) % Returns the transpose of A fliplr(A) % Flip matrix left to right flipud(A) % Flip matrix up to down % Matrix Factorisations [L, U, P] = lu(A) % LU decomposition: PA = LU,L is lower triangular, U is upper triangular, P is permutation matrix [P, D] = eig(A) % eigen-decomposition: AP = PD, P's columns are eigenvectors and D's diagonals are eigenvalues [U,S,V] = svd(X) % SVD: XV = US, U and V are unitary matrices, S has non-negative diagonal elements in decreasing order [Q, R] = qr(A) % if A is mxn, Q is mxm and R is mxn upper triangular % Common vector functions max % largest component min % smallest component length % length of a vector sort % sort in ascending order sum % sum of elements prod % product of elements mode % modal value median % median value mean % mean value std % standard deviation perms(x) % list all permutations of elements of x find(x) % Finds all non-zero elements of x and returns their indexes, can use comparison operators, % i.e. find( x == 3 ) returns indexes of elements that are equal to 3 % i.e. find( x >= 3 ) returns indexes of elements greater than or equal to 3 ``` ## 3. Plots ```matlab % Plotting x = 0:.10:2*pi; % Creates a vector that starts at 0 and ends at 2*pi with increments of .1 y = sin(x); plot(x,y) xlabel('x axis') ylabel('y axis') title('Plot of y = sin(x)') axis([0 2*pi -1 1]) % x range from 0 to 2*pi, y range from -1 to 1 plot(x,y1,'-',x,y2,'--',x,y3,':') % For multiple functions on one plot legend('Line 1 label', 'Line 2 label') % Label curves with a legend % Alternative method to plot multiple functions in one plot. % while 'hold' is on, commands add to existing graph rather than replacing it plot(x, y) hold on plot(x, z) hold off loglog(x, y) % A log-log plot semilogx(x, y) % A plot with logarithmic x-axis semilogy(x, y) % A plot with logarithmic y-axis fplot (@(x) x^2, [2,5]) % plot the function x^2 from x=2 to x=5 % Creates a meshgrid (2D grid) to calculate a function for every point in the grid [X, Y] = meshgrid(x_min:step:x_max, y_min:step:y_max) grid on % Show grid; turn off with 'grid off' axis square % Makes the current axes region square axis equal % Set aspect ratio so data units are the same in every direction scatter(x, y); % Scatter-plot hist(x); % Histogram stem(x); % Plot values as stems, useful for displaying discrete data bar(x); % Plot bar graph z = sin(x); plot3(x,y,z); % 3D line plot pcolor(A) % Heat-map of matrix: plot as grid of rectangles, coloured by value contour(A) % Contour plot of matrix contourf(A) % Filled contour plot of matrix mesh(A) % Plot as a mesh surface h = figure % Create new figure object, with handle h figure(h) % Makes the figure corresponding to handle h the current figure close(h) % close figure with handle h close all % close all open figure windows close % close current figure window shg % bring an existing graphics window forward, or create new one if needed clf clear % clear current figure window, and reset most figure properties % Properties can be set and changed through a figure handle. % You can save a handle to a figure when you create it. % The function get returns a handle to the current figure h = plot(x, y); % you can save a handle to a figure when you create it set(h, 'Color', 'r') % 'y' yellow; 'm' magenta, 'c' cyan, 'r' red, 'g' green, 'b' blue, 'w' white, 'k' black set(h, 'LineStyle', '--') % '--' is solid line, '---' dashed, ':' dotted, '-.' dash-dot, 'none' is no line get(h, 'LineStyle') % The function gca returns a handle to the axes for the current figure set(gca, 'XDir', 'reverse'); % reverse the direction of the x-axis % To create a figure that contains several axes in tiled positions, use subplot subplot(2,3,1); % select the first position in a 2-by-3 grid of subplots plot(x1); title('First Plot') % plot something in this position subplot(2,3,2); % select second position in the grid plot(x2); title('Second Plot') % plot something there % Given x1 = [-3:0.5:3]; x2 = x1; y = randi(500, length(x1), length(x1)); % Show a 3-D plot figure subplot(2,1,1); surf(x1,x2,y); xlabel(’x_1’); ylabel(’x_2’); % Show contours subplot(2,1,2); contour(x1,x2,y); xlabel(’x_{1}’); ylabel(’x_{2}’); axis equal % Show a colour map figure imagesc(x1,x2,y) xlabel(’x_{1}’); ylabel(’x_{2}’); ``` ## 4. Functions and Scripts ```matlab % Calling Functions % Standard function syntax: load('myFile.mat', 'y') % Command syntax: load myFile.mat y % no parentheses, and spaces instead of commas % Calling a function from a script % [arguments out] = function_name(arguments in) [V,D] = eig(A); [~,D] = eig(A); % if you only want D and not V % To use functions or scripts, they must be on your path or current directory path % displays current path addpath /path/to/dir % add to path rmpath /path/to/dir % remove from path cd /path/to/move/into % change directory % M-file Scripts % A script file is an external file that contains a sequence of statements. % They let you avoid repeatedly typing the same code in the Command Window % Have .m extensions % M-file Functions % Like scripts, and have the same .m extension % But can accept input arguments and return an output % Also, they have their own workspace (ie. different variable scope). % Function name should match file name (so save this example as double_input.m). % 'help double_input.m' returns the comments under line beginning function function output = double_input(x) %double_input(x) returns twice the value of x output = 2*x; end double_input(6) % ans = 12 % If you want to create a function without creating a new file you can use an % anonymous function. % Example that returns the square of it's input, assigned to the handle sqr: sqr = @(x) x.^2; sqr(10) % ans = 100 doc function_handle % find out more ``` ## 5. Programming Logic ```matlab % User input a = input('Enter the value: ') % Stops execution of file and gives control to the keyboard: user can examine % or change variables. Type 'return' to continue execution, or 'dbquit' to exit keyboard % Reading in data (also xlsread/importdata/imread for excel/CSV/image files) fopen(filename) % Output disp(a) % Print out the value of variable a disp('Hello World') % Print out a string fprintf % Print to Command Window with more control % Conditional statements (the parentheses are optional, but good style) if (a > 15) disp('Greater than 15') elseif (a == 23) disp('a is 23') else disp('neither condition met') end % Looping % NB. looping over elements of a vector/matrix is slow! % Where possible, use functions that act on whole vector/matrix at once for k = 1:5 disp(k) end k = 0; while (k < 5) k = k + 1; end % Timing code execution: 'toc' prints the time since 'tic' was called tic A = rand(1000); A*A*A*A*A*A*A; toc ``` ## 6. Math/Engineering ### i. Common Math Functions ```matlab sin(x) cos(x) tan(x) asin(x) acos(x) atan(x) exp(x) sqrt(x) log(x) log10(x) abs(x) %If x is complex, returns magnitude min(x) max(x) ceil(x) floor(x) round(x) rem(x) rand % Uniformly distributed pseudorandom numbers randi % Uniformly distributed pseudorandom integers randn % Normally distributed pseudorandom numbers %Complex math operations abs(x) % Magnitude of complex variable x phase(x) % Phase (or angle) of complex variable x real(x) % Returns the real part of x (i.e returns a if x = a +jb) imag(x) % Returns the imaginary part of x (i.e returns b if x = a+jb) conj(x) % Returns the complex conjugate % Common constants pi NaN inf % Given a meshgrid X,Y and a function defined on the meshgrid like Gauss, interpolates the value of the function at the point u1,u2 interp2(X,Y,Gauss,u1,u2) ``` ### ii. Transfer Functions ```matlab % Transfer functions s = tf('s'); G = s^2/(s^3 + 100*s^2 + 30*s + 50); pole(G); % Returns the location(s) of the pole(s) in rad/s zero(G); % Returns the location(s) of the zero(s) in rad/s pzmap(G); % Plots the locations of both the pole(s) and zero(s) bandwidth(closed_loop_system); % Returns bandwidth of a closed loop transfer function in rad/s bode(closed_loop_system) % Creates bode plot of system rlocus(closed_loop_system) % Plots a root locus of the specified system margin(open_loop_system); % Creates a bode plot, displaying the gain and phase margins of an open loop transfer function ``` ## 7. Vectorization Tips to vectorize your code to get rid of loops and make it run more efficiently. ```matlab ``` ## 8. Optimization ```matlab % fmincon ``` ## 9. Machine Learning ```matlab ``` ## 10. Simulink ```matlab simulink % starts Simulink ``` ================================================ FILE: Markdown/README.md ================================================ Markdown Cheatsheet =================== - - - - # Heading 1 # Markup : # Heading 1 # -OR- Markup : ============= (below H1 text) ## Heading 2 ## Markup : ## Heading 2 ## -OR- Markup: --------------- (below H2 text) ### Heading 3 ### Markup : ### Heading 3 ### #### Heading 4 #### Markup : #### Heading 4 #### Common text Markup : Common text _Emphasized text_ Markup : _Emphasized text_ or *Emphasized text* ~~Strikethrough text~~ Markup : ~~Strikethrough text~~ __Strong text__ Markup : __Strong text__ or **Strong text** ___Strong emphasized text___ Markup : ___Strong emphasized text___ or ***Strong emphasized text*** [Named Link](http://www.google.fr/) and http://www.google.fr/ or Markup : [Named Link](http://www.google.fr/) and http://www.google.fr/ or Table, like this one : First Header | Second Header ------------- | ------------- Content Cell | Content Cell Content Cell | Content Cell ``` First Header | Second Header ------------- | ------------- Content Cell | Content Cell Content Cell | Content Cell ``` `code()` Markup : `code()` ```javascript var specificLanguage_code = { "data": { "lookedUpPlatform": 1, "query": "Kasabian+Test+Transmission", "lookedUpItem": { "name": "Test Transmission", "artist": "Kasabian", "album": "Kasabian", "picture": null, "link": "http://open.spotify.com/track/5jhJur5n4fasblLSCOcrTp" } } } ``` Markup : ```javascript ``` * Bullet list * Nested bullet * Sub-nested bullet etc * Bullet list item 2 ~~~ Markup : * Bullet list * Nested bullet * Sub-nested bullet etc * Bullet list item 2 ~~~ 1. A numbered list 1. A nested numbered list 2. Which is numbered 2. Which is numbered ~~~ Markup : 1. A numbered list 1. A nested numbered list 2. Which is numbered 2. Which is numbered ~~~ - [ ] An uncompleted task - [x] A completed task ~~~ Markup : - [ ] An uncompleted task - [x] A completed task ~~~ > Blockquote >> Nested blockquote Markup : > Blockquote >> Nested Blockquote _Horizontal line :_ - - - - Markup : - - - - _Image with alt :_ ![picture alt](http://www.brightlightpictures.com/assets/images/portfolio/thethaw_header.jpg "Title is optional") Markup : ![picture alt](http://www.brightlightpictures.com/assets/images/portfolio/thethaw_header.jpg "Title is optional") Foldable text:
Title 1

Content 1 Content 1 Content 1 Content 1 Content 1

Title 2

Content 2 Content 2 Content 2 Content 2 Content 2

Markup :
Title 1

Content 1 Content 1 Content 1 Content 1 Content 1

```html

HTML

Some HTML code here

``` Hotkey: ⌘F ⇧⌘F Markup : ⌘F Hotkey list: | Key | Symbol | | --- | --- | | Option | ⌥ | | Control | ⌃ | | Command | ⌘ | | Shift | ⇧ | | Caps Lock | ⇪ | | Tab | ⇥ | | Esc | ⎋ | | Power | ⌽ | | Return | ↩ | | Delete | ⌫ | | Up | ↑ | | Down | ↓ | | Left | ← | | Right | → | Emoji: :exclamation: Use emoji icons to enhance text. :+1: Look up emoji codes at [emoji-cheat-sheet.com](http://emoji-cheat-sheet.com/) Markup : Code appears between colons :EMOJICODE: ================================================ FILE: MongoDB/README.md ================================================ # MongoDB Cheat Sheet ## Show All Databases ``` show dbs ``` ## Show Current Database ``` db ``` ## Create Or Switch Database ``` use acme ``` ## Drop ``` db.dropDatabase() ``` ## Create Collection ``` db.createCollection('posts') ``` ## Show Collections ``` show collections ``` ## Insert Row ``` db.posts.insert({ title: 'Post One', body: 'Body of post one', category: 'News', tags: ['news', 'events'], user: { name: 'John Doe', status: 'author' }, date: Date() }) ``` ## Insert Multiple Rows ``` db.posts.insertMany([ { title: 'Post Two', body: 'Body of post two', category: 'Technology', date: Date() }, { title: 'Post Three', body: 'Body of post three', category: 'News', date: Date() }, { title: 'Post Four', body: 'Body of post three', category: 'Entertainment', date: Date() } ]) ``` ## Get All Rows ``` db.posts.find() ``` ## Get All Rows Formatted ``` db.posts.find().pretty() ``` ## Find Rows ``` db.posts.find({ category: 'News' }) ``` ## Sort Rows ``` # asc db.posts.find().sort({ title: 1 }).pretty() # desc db.posts.find().sort({ title: -1 }).pretty() ``` ## Count Rows ``` db.posts.find().count() db.posts.find({ category: 'news' }).count() ``` ## Limit Rows ``` db.posts.find().limit(2).pretty() ``` ## Chaining ``` db.posts.find().limit(2).sort({ title: 1 }).pretty() ``` ## Foreach ``` db.posts.find().forEach(function(doc) { print("Blog Post: " + doc.title) }) ``` ## Find One Row ``` db.posts.findOne({ category: 'News' }) ``` ## Find Specific Fields ``` db.posts.find({ title: 'Post One' }, { title: 1, author: 1 }) ``` ## Update Row ``` db.posts.update({ title: 'Post Two' }, { title: 'Post Two', body: 'New body for post 2', date: Date() }, { upsert: true }) ``` ## Update Specific Field ``` db.posts.update({ title: 'Post Two' }, { $set: { body: 'Body for post 2', category: 'Technology' } }) ``` ## Increment Field (\$inc) ``` db.posts.update({ title: 'Post Two' }, { $inc: { likes: 5 } }) ``` ## Rename Field ``` db.posts.update({ title: 'Post Two' }, { $rename: { likes: 'views' } }) ``` ## Delete Row ``` db.posts.remove({ title: 'Post Four' }) ``` ## Sub-Documents ``` db.posts.update({ title: 'Post One' }, { $set: { comments: [ { body: 'Comment One', user: 'Mary Williams', date: Date() }, { body: 'Comment Two', user: 'Harry White', date: Date() } ] } }) ``` ## Find By Element in Array (\$elemMatch) ``` db.posts.find({ comments: { $elemMatch: { user: 'Mary Williams' } } } ) ``` ## Add Index ``` db.posts.createIndex({ title: 'text' }) ``` ## Text Search ``` db.posts.find({ $text: { $search: "\"Post O\"" } }) ``` ## Greater & Less Than ``` db.posts.find({ views: { $gt: 2 } }) db.posts.find({ views: { $gte: 7 } }) db.posts.find({ views: { $lt: 7 } }) db.posts.find({ views: { $lte: 7 } }) ``` ================================================ FILE: MongoDB/sql_mongo_comparison.md ================================================ [SQL to MongoDB Mapping Chart](http://docs.mongodb.org/manual/reference/sql-comparison/#sql-to-mongodb-mapping-chart)

SQL to MongoDB Mapping Chart

In addition to the charts that follow, you might want to consider the Frequently Asked Questions section for a selection of common questions about MongoDB.

Executables

The following table presents the MySQL/Oracle executables and the corresponding MongoDB executables.

  MySQL/Oracle MongoDB
Database Server mysqld/oracle mongod
Database Client mysql/sqlplus mongo

Terminology and Concepts

The following table presents the various SQL terminology and concepts and the corresponding MongoDB terminology and concepts.

SQL Terms/Concepts MongoDB Terms/Concepts
database database
table collection
row document or BSON document
column field
index index
table joins embedded documents and linking

primary key

Specify any unique column or column combination as primary key.

primary key

In MongoDB, the primary key is automatically set to the _id field.

aggregation (e.g. group by)

aggregation framework

See the SQL to Aggregation Framework Mapping Chart.

Examples

The following table presents the various SQL statements and the corresponding MongoDB statements. The examples in the table assume the following conditions:

  • The SQL examples assume a table named users.

  • The MongoDB examples assume a collection named users that contain documents of the following prototype:

    {
      _id: ObjectID("509a8fb2f3f4948bd2f983a0"),
      user_id: "abc123",
      age: 55,
      status: 'A'
    }
    

Create and Alter

The following table presents the various SQL statements related to table-level actions and the corresponding MongoDB statements.

SQL Schema Statements MongoDB Schema Statements Reference
CREATE TABLE users (
    id MEDIUMINT NOT NULL
        AUTO_INCREMENT,
    user_id Varchar(30),
    age Number,
    status char(1),
    PRIMARY KEY (id)
)

Implicitly created on first insert operation. The primary key _id is automatically added if _id field is not specified.

db.users.insert( {
    user_id: "abc123",
    age: 55,
    status: "A"
 } )

However, you can also explicitly create a collection:

db.createCollection("users")
See insert() and createCollection() for more information.
ALTER TABLE users
ADD join_date DATETIME
Collections do not describe or enforce the structure of the constituent documents. See the Schema Design wiki page for more information. See update() and $set for more information on changing the structure of documents in a collection.
ALTER TABLE users
DROP COLUMN join_date
Collections do not describe or enforce the structure of the constituent documents. See the Schema Design wiki page for more information. See update() and $set for more information on changing the structure of documents in a collection.
CREATE INDEX idx_user_id_asc
ON users(user_id)
db.users.ensureIndex( { user_id: 1 } )
See ensureIndex() and indexes for more information.
CREATE INDEX
       idx_user_id_asc_age_desc
ON users(user_id, age DESC)
db.users.ensureIndex( { user_id: 1, age: -1 } )
See ensureIndex() and indexes for more information.
DROP TABLE users
db.users.drop()
See drop() for more information.

Insert

The following table presents the various SQL statements related to inserting records into tables and the corresponding MongoDB statements.

SQL INSERT Statements MongoDB insert() Statements Reference
INSERT INTO users(user_id,
                  age,
                  status)
VALUES ("bcd001",
        45,
        "A")
db.users.insert( {
       user_id: "bcd001",
       age: 45,
       status: "A"
} )
See insert() for more information.

Select

The following table presents the various SQL statements related to reading records from tables and the corresponding MongoDB statements.

SQL SELECT Statements MongoDB find() Statements Reference
SELECT *
FROM users
db.users.find()
See find() for more information.
SELECT id, user_id, status
FROM users
db.users.find(
    { },
    { user_id: 1, status: 1 }
)
See find() for more information.
SELECT user_id, status
FROM users
db.users.find(
    { },
    { user_id: 1, status: 1, _id: 0 }
)
See find() for more information.
SELECT *
FROM users
WHERE status = "A"
db.users.find(
    { status: "A" }
)
See find() for more information.
SELECT user_id, status
FROM users
WHERE status = "A"
db.users.find(
    { status: "A" },
    { user_id: 1, status: 1, _id: 0 }
)
See find() for more information.
SELECT *
FROM users
WHERE status != "A"
db.users.find(
    { status: { $ne: "A" } }
)
See find() and $ne for more information.
SELECT *
FROM users
WHERE status = "A"
AND age = 50
db.users.find(
    { status: "A",
      age: 50 }
)
See find() and $and for more information.
SELECT *
FROM users
WHERE status = "A"
OR age = 50
db.users.find(
    { $or: [ { status: "A" } ,
             { age: 50 } ] }
)
See find() and $or for more information.
SELECT *
FROM users
WHERE age > 25
db.users.find(
    { age: { $gt: 25 } }
)
See find() and $gt for more information.
SELECT *
FROM users
WHERE age < 25
db.users.find(
   { age: { $lt: 25 } }
)
See find() and $lt for more information.
SELECT *
FROM users
WHERE age > 25
AND   age <= 50
db.users.find(
   { age: { $gt: 25, $lte: 50 } }
)
See find(), $gt, and $lte for more information.
SELECT *
FROM users
WHERE user_id like "%bc%"
db.users.find(
   { user_id: /bc/ }
)
See find() and $regex for more information.
SELECT *
FROM users
WHERE user_id like "bc%"
db.users.find(
   { user_id: /^bc/ }
)
See find() and $regex for more information.
SELECT *
FROM users
WHERE status = "A"
ORDER BY user_id ASC
db.users.find( { status: "A" } ).sort( { user_id: 1 } )
See find() and sort() for more information.
SELECT *
FROM users
WHERE status = "A"
ORDER BY user_id DESC
db.users.find( { status: "A" } ).sort( { user_id: -1 } )
See find() and sort() for more information.
SELECT COUNT(*)
FROM users
db.users.count()

or

db.users.find().count()
See find() and count() for more information.
SELECT COUNT(user_id)
FROM users
db.users.count( { user_id: { $exists: true } } )

or

db.users.find( { user_id: { $exists: true } } ).count()
See find(), count(), and $exists for more information.
SELECT COUNT(*)
FROM users
WHERE age > 30
db.users.count( { age: { $gt: 30 } } )

or

db.users.find( { age: { $gt: 30 } } ).count()
See find(), count(), and $gt for more information.
SELECT DISTINCT(status)
FROM users
db.users.distinct( "status" )
See find() and distinct() for more information.
SELECT *
FROM users
LIMIT 1
db.users.findOne()

or

db.users.find().limit(1)
See find(), findOne(), and limit() for more information.
SELECT *
FROM users
LIMIT 5
SKIP 10
db.users.find().limit(5).skip(10)
See find(), limit(), and skip() for more information.
EXPLAIN SELECT *
FROM users
WHERE status = "A"
db.users.find( { status: "A" } ).explain()
See find() and explain() for more information.

Update Records

The following table presents the various SQL statements related to updating existing records in tables and the corresponding MongoDB statements.

SQL Update Statements MongoDB update() Statements Reference
UPDATE users
SET status = "C"
WHERE age > 25
db.users.update(
   { age: { $gt: 25 } },
   { $set: { status: "C" } },
   { multi: true }
)
See update(), $gt, and $set for more information.
UPDATE users
SET age = age + 3
WHERE status = "A"
db.users.update(
   { status: "A" } ,
   { $inc: { age: 3 } },
   { multi: true }
)
See update(), $inc, and $set for more information.

Delete Records

The following table presents the various SQL statements related to deleting records from tables and the corresponding MongoDB statements.

SQL Delete Statements MongoDB remove() Statements Reference
DELETE FROM users
WHERE status = "D"
db.users.remove( { status: "D" } )
See remove() for more information.
DELETE FROM users
db.users.remove( )
See remove() for more information.
================================================ FILE: Oracle SQL/README.md ================================================ # SQL cheatsheet #### This is note taken from the [SQL course on Codecademy](https://www.codecademy.com/learn/learn-sql). ## Manipulation ```sql CREATE TABLE celebs (id INTEGER, name TEXT, age INTEGER); ``` This `CREATE` statement creates a new table in the database named `celebs`. You can use the `CREATE` statement anytime you want to create a new table from scratch. 1. `CREATE TABLE` is a clause that tells SQL you want to create a new table. 2. `celebs` is the name of the table. 3. `(id INTEGER, name TEXT, age INTEGER)`is a list of parameters defining each column in the table and its data type. - `id` is the first column in the table. It stores values of data type `INTEGER` - `name` is the second column in the table. It stores values of data type `TEXT` - `age` is the third column in the table. It stores values of data type `INTEGER` Add a row to the table. In the code editor type ```sql INSERT INTO celebs (id, name, age) VALUES (1, 'Justin Bieber', 21); ``` To view the row you just created, under the `INSERT` statement type `SELECT * FROM celebs;`. This `INSERT` statement inserts new rows into a table. You can use the `INSERT` statement when you want to add new records. 1. `INSERT INTO` is a clause that adds the specified row or rows. 2. `celebs` is the name of the table the row is added to. 3. `(id, name, age)` is a parameter identifying the columns that data will be inserted into. 4. `VALUES` is a clause that indicates the data being inserted. `(1, 'Justin Bieber', 21)` is a parameter identifying the values being inserted. - `1` is an integer that will be inserted into the `id` column - `'Justin Bieber'` is text that will be inserted into the `name` column - `21` is an integer that will be inserted into the `age` column ```sql SELECT name FROM celebs; ``` `SELECT` statements are used to fetch data from a database. Here, `SELECT` returns all data in the `name` column of the `celebs` table. 1. `SELECT` is a clause that indicates that the statement is a query. You will use `SELECT` every time you query data from a database. 2. `name` specifies the column to query data from. 3. `FROM celebs` specifies the name of the table to query data from. In this statement, data is queried from the `celebs` table. You can also query data from all columns in a table with `SELECT`. ```sql SELECT * FROM celebs; ``` `*` is a special wildcard character that we have been using. It allows you to select every column in a table without having to name each one individually. Here, the result set contains every column in the `celebs` table. `SELECT` statements always return a new table called the *result set*. ```sql UPDATE celebs SET age = 22 WHERE id = 1; ``` The `UPDATE` statement edits a row in the table. You can use the `UPDATE` statement when you want to change existing records. 1. `UPDATE` is a clause that edits a row in the table. 2. `celebs` is the name of the table. 3. `SET` is a clause that indicates the column to edit. - `age` is the name of the column that is going to be updated - `22` is the new value that is going to be inserted into the `age` column. 4. `WHERE` is a clause that indicates which row(s) to update with the new column value. Here the row with a `1` in the `id` column is the row that will have the `age` updated to `22`. ```sql ALTER TABLE celebs ADD COLUMN twitter_handle TEXT; ``` The `ALTER TABLE` statement added a new column to the table. You can use this command when you want to add columns to a table. 1. `ALTER TABLE` is a clause that lets you make the specified changes. 2. `celebs` is the name of the table that is being changed. 3. `ADD COLUMN` is a clause that lets you add a new column to a table. - `twitter_handle` is the name of the new column being added - `TEXT` is the data type for the new column 4. `NULL` is a special value in SQL that represents missing or unknown data. Here, the rows that existed before the column was added have `NULL`values for `twitter_handle`. ```sql DELETE FROM celebs WHERE twitter_handle IS NULL; ``` The `DELETE FROM` statement deletes one or more rows from a table. You can use the statement when you want to delete existing records. 1. `DELETE FROM` is a clause that lets you delete rows from a table. 2. `celebs` is the name of the table we want to delete rows from. 3. `WHERE` is a clause that lets you select which rows you want to delete. Here we want to delete all of the rows where the twitter_handle column `IS NULL`. 4. `IS NULL` is a condition in SQL that returns true when the value is `NULL` and false otherwise. ## Queries ### Database Schema | movies220 rows | | | -------------- | ------- | | id | INTEGER | | name | TEXT | | genre | TEXT | | year | INTEGER | | imdb_rating | REAL | ```sql SELECT name, imdb_rating FROM movies; ``` In Lesson 1 you learned that `SELECT` is used every time you want to query data from a database. Multiple columns can be queried at once by separating column names with a comma. By specifying `name, imdb_rating`, the result set contains a `name` and `imdb_rating` column. ```sql SELECT DISTINCT genre FROM movies; ``` `SELECT DISTINCT` is used to return unique values in the result set. It filters out all duplicate values. Here, the result set lists each genre in the `movies` table exactly once. 1. `SELECT DISTINCT` specifies that the statement is going to be a query that returns unique values in the specified column(s) 2. `genre` is the name of the column to display in the result set. 3. `FROM movies` indicates the table name to query from. Filtering the results of a query is an important skill in SQL. It is easier to see the different possible genres a movie can have after the data has been filtered, than to scan every row in the table. The rest of this lesson will teach you different commands in SQL to filter the results of a query. ```sql SELECT * FROM movies WHERE imdb_rating > 8; ``` This statement filters the result set to only include movies with IMDb ratings greater than 8. How does it work? 1. `WHERE` is a clause that indicates you want to filter the result set to include only rows where the following *condition* is true. 2. `imdb_rating > 8` is a condition that filters the result set. Here, only rows with a value greater than 8 in the `imdb_rating` column will be returned in the result set. 3. `>` is an *operator*. Operators create a condition that can be evaluated as either true or false. Common operators used with the `WHERE` clause are: - `=` equals - `!=` not equals - `>` greater than - `<` less than - `>=` greater than or equal to - `<=` less than or equal to There are also some special operators that we will learn more about in the upcoming exercises. ```sql SELECT * FROM movies WHERE name LIKE 'Se_en'; ``` `LIKE` can be a useful operator when you want to compare similar values. Here, we are comparing two movies with the same name but are spelled differently. 1. `LIKE` is a special operator used with the `WHERE` clause to search for a specific pattern in a column. 2. `name LIKE Se_en` is a condition evaluating the `name` column for a specific pattern. 3. `Se_en` represents a pattern with a *wildcard* character. The `_` means you can substitute any individual character here without breaking the pattern. The names `Seven` and `Se7en` both match this pattern. `%` is another wildcard character that can be used with `LIKE`. We will learn more about `%` in the next exercise. ```sql SELECT * FROM movies WHERE name LIKE 'A%'; ``` This statement filters the result set to only include movies with names that begin with the letter "A" `%` is a wildcard character that matches zero or more missing letters in the pattern. - `A%` matches all movies with names that begin with "A" - `%a` matches all movies that end with "a" ```sql SELECT * FROM movies WHERE name LIKE '%man%'; ``` You can use `%` both before and after a pattern. Here, any movie that contains the word "man" in its name will be returned in the result set. Notice, that `LIKE` is not case sensitive. "Batman" and "Man Of Steel" both appear in the result set. The `BETWEEN` operator is used to filter the result set within a certain range. The values can be numbers, text or dates. ```sql SELECT * FROM movies WHERE name BETWEEN 'A' AND 'J'; ``` This statement filters the result set to only include movies with `name`s that begin with letters "A" up to but not including "J". ```sql SELECT * FROM movies WHERE year BETWEEN 1990 AND 2000; ``` In this statement, the `BETWEEN` operator is being used to filter the result set to only include movies with `year`s between 1990 up to and including 2000. ```sql SELECT * FROM movies WHERE year BETWEEN 1990 and 2000 AND genre = 'comedy'; ``` Sometimes you want to combine multiple conditions in a `WHERE` clause to make the result set more specific and useful. One way of doing this is to use the `AND` operator. 1. `year BETWEEN 1990 and 2000` is the first condition in the `WHERE` clause. 2. `AND genre = 'comedy'` is the second condition in the `WHERE` clause. 3. `AND` is an operator that combines two conditions. Both conditions must be true for the row to be included in the result set. Here, we use the `AND` operator to only return movies made between 1990 and 2000 that are also comedies. ```sql SELECT * FROM movies WHERE genre = 'comedy' OR year < 1980; ``` The `OR` operator can also be used to combine more than one condition in a `WHERE` clause. The `OR` operator evaluates each condition separately and if any of the conditions are true then the row is added to the result set. 1. `WHERE genre = 'comedy'` is the first condition in the `WHERE` clause. 2. `OR year < 1980` is the second condition in the `WHERE` clause. 3. `OR` is an operator that filters the result set to only include rows where either condition is true. Here, we return movies that either have a genre of comedy or were released before 1980. ```sql SELECT * FROM movies ORDER BY imdb_rating DESC; ``` You can sort the results of your query using `ORDER BY`. Sorting the results often makes the data more useful and easier to analyze. 1. `ORDER BY` is a clause that indicates you want to sort the result set by a particular column either alphabetically or numerically. 2. `imdb_rating` is the name of the column that will be sorted. 3. `DESC` is a keyword in SQL that is used with `ORDER BY` to sort the results in *descending order* (high to low or Z-A). Here, it sorts all of the movies from highest to lowest by their IMDb rating. It is also possible to sort the results in *ascending order*. `ASC` is a keyword in SQL that is used with `ORDER BY` to sort the results in ascending order (low to high or A-Z). ```sql SELECT * FROM movies ORDER BY imdb_rating DESC LIMIT 3; ``` Sometimes even filtered results can return thousands of rows in large databases. In these situations it becomes important to cap the number of rows in a result set. `LIMIT` is a clause that lets you specify the maximum number of rows the result set will have. Here, we specify that the result set can not have more than three rows. ## Aggregrate Functions ### Database Schema | fake_apps200 rows | | | ----------------- | ------- | | id | INTEGER | | name | TEXT | | category | TEXT | | downloads | INTEGER | | price | REAL | ```sql SELECT COUNT(*) FROM fake_apps; ``` The fastest way to calculate the number of rows in a table is to use the `COUNT()` function. `COUNT()` is a function that takes the name of a column as an argument and counts the number of rows where the column is not `NULL`. Here, we want to count every row so we pass `*` as an argument. ```sql SELECT price, COUNT(*) FROM fake_apps GROUP BY price; ``` Aggregate functions are more useful when they organize data into groups. `GROUP BY` is a clause in SQL that is only used with aggregate functions. It is used in collaboration with the `SELECT` statement to arrange identical data into groups. Here, our aggregate function is `COUNT()` and we are passing `price` as an argument to `GROUP BY`. SQL will count the total number of apps for each `price` in the table. It is usually helpful to `SELECT` the column you pass as an argument to `GROUP BY`. Here we select `price` and `COUNT(*)`. You can see that the result set is organized into two columns making it easy to see the number of apps at each price. Count the total number of apps at each price that have been downloaded more than 20,000 times. ```sql SELECT price, COUNT(*) FROM fake_apps WHERE downloads > 20000 GROUP BY price; ``` ```sql SELECT SUM(downloads) FROM fake_apps; ``` SQL makes it easy to add all values in a particular column using `SUM()`. `SUM()` is a function that takes the name of a column as an argument and returns the sum of all the values in that column. Here, it adds all the values in the `downloads` column. ```sql SELECT MAX(downloads) FROM fake_apps; ``` You can find the largest value in a column by using `MAX()`. `MAX()` is a function that takes the name of a column as an argument and returns the largest value in that column. Here, we pass `downloads`as an argument so it will return the largest value in the `downloads` column. Return the names of the most downloaded apps in each category. ```sql SELECT name, category, MAX(downloads) FROM fake_apps GROUP BY category; ``` ```sql SELECT MIN(downloads) FROM fake_apps; ``` Similar to `MAX()`, SQL also makes it easy to return the smallest value in a column by using the `MIN()` function. `MIN()` is a function that takes the name of a column as an argument and returns the smallest value in that column. Here, we pass `downloads`as an argument so it will return the smallest value in the `downloads` column. ```sql SELECT AVG(downloads) FROM fake_apps; ``` This statement returns the average number of downloads for an app in our database. SQL uses the `AVG()` function to quickly calculate the average value of a particular column. The `AVG()` function works by taking a column name as an argument and returns the average value for that column. ```sql SELECT price, ROUND(AVG(downloads), 2) FROM fake_apps GROUP BY price; ``` By default, SQL tries to be as precise as possible without rounding. We can make the result set easier to read using the `ROUND()` function. `ROUND()` is a function that takes a column name and an integer as an argument. It rounds the values in the column to the number of decimal places specified by the integer. Here, we pass the column `AVG(downloads)` and `2` as arguments. SQL first calculates the average for each price and then rounds the result to two decimal places in the result set. Round the average number of downloads to the nearest integer for each price. ```sql SELECT price, ROUND(AVG(downloads)) FROM fake_apps GROUP BY price; ``` ## Multiple Tables So far we have learned how to build tables, write queries, and perform calculations using one table. In this lesson we will learn to query multiple tables that have relationships with each other. Most of the time, data is distributed across multiple tables in the database. Imagine a database with two tables, `artists` and `albums`. An artist can produce many different albums, and an album is produced by an artist. The data in these tables are related to each other. Through SQL, we can write queries that combine data from multiple tables that are related to one another. This is one of the most powerful features of relational databases. ### Database Schema | albums14 rows | | | ------------- | ------- | | id | INTEGER | | name | TEXT | | artist_id | INTEGER | | year | INTEGER | | artists0 rows | | | ------------- | ------- | | id | INTEGER | | name | TEXT | We have created a table named `albums`for you. Create a second table named `artists`. ```sql CREATE TABLE artists(id INTEGER PRIMARY KEY, name TEXT); ``` ```sql CREATE TABLE artists(id INTEGER PRIMARY KEY, name TEXT) ``` Using the `CREATE TABLE` statement we added a `PRIMARY KEY` to the `id` column. A **primary key** serves as a unique identifier for each row or record in a given table. The primary key is literally an `id` value for a record. We're going to use this value to connect `artists` to the `albums` they have produced. By specifying that the `id` column is the `PRIMARY KEY`, SQL makes sure that: - None of the values in this column are `NULL` - Each value in this column is unique A table can not have more than one `PRIMARY KEY` column. ```sql SELECT * FROM albums WHERE artist_id = 3; SELECT * FROM artists WHERE id = 3; ``` A *foreign key* is a column that contains the primary key of another table in the database. We use foreign keys and primary keys to connect rows in two different tables. One table's foreign key holds the value of another table's primary key. Unlike primary keys, foreign keys do not need to be unique and can be `NULL`. Here, `artist_id` is a foreign key in the `albums`table. We can see that Michael Jackson has an `id`of 3 in the `artists` table. All of the albums by Michael Jackson also have a 3 in the `artist_id`column in the `albums` table. This is how SQL is linking data between the two tables. The *relationship* between the `artists`table and the `albums` table is the `id` value of the artists. ```sql SELECT albums.name, albums.year, artists.name FROM albums, artists ``` One way to query multiple tables is to write a `SELECT` statement with multiple table names separated by a comma. This is also known as a *cross join*. Here, `albums` and `artists` are the different tables we are querying. When querying more than one table, column names need to be specified by `table_name.column_name`. Here, the result set includes the `name` and `year` columns from the `albums` table and the `name` column from the `artists` table. **Unfortunately the result of this cross join is not very useful. It combines every row of the `artists` table with every row of the `albums`table. It would be more useful to only combine the rows where the album was created by the artist.** ```sql SELECT * FROM albums JOIN artists ON albums.artist_id = artists.id; ``` In SQL, joins are used to combine rows from two or more tables. The most common type of join in SQL is an *inner join*. An inner join will combine rows from different tables if the *join condition* is true. Let's look at the syntax to see how it works. 1. `SELECT *` specifies the columns our result set will have. Here, we want to include every column in both tables. 2. `FROM albums` specifies the first table we are querying. 3. `JOIN artists ON` specifies the type of join we are going to use as well as the name of the second table. Here, we want to do an inner join and the second table we want to query is `artists`. 4. `albums.artist_id = artists.id` is the join condition that describes how the two tables are related to each other. Here, SQL uses the foreign key column `artist_id` in the `albums` table to match it with exactly one row in the `artists` table with the same value in the `id` column. We know it will only match one row in the `artists` table because `id` is the `PRIMARY KEY` of `artists`. ```sql SELECT * FROM albums LEFT JOIN artists ON albums.artist_id = artists.id; ``` Outer joins also combine rows from two or more tables, but unlike inner joins, they do not require the join condition to be met. Instead, every row in the *left* table is returned in the result set, and if the join condition is not met, then `NULL` values are used to fill in the columns from the *right* table. The left table is simply the first table that appears in the statement. Here, the left table is `albums`. Likewise, the right table is the second table that appears. Here, `artists` is the right table. ```sql SELECT albums.name AS 'Album', albums.year, artists.name AS 'Artist' FROM albums JOIN artists ON albums.artist_id = artists.id WHERE albums.year > 1980; ``` `AS` is a keyword in SQL that allows you to rename a column or table using an *alias*. The new name can be anything you want as long as you put it inside of single quotes. Here we want to rename the `albums.name` column as `'Album'`, and the `artists.name` column as `'Artist'`. It is important to note that the columns have not been renamed in either table. The aliases only appear in the result set. ## Some other commands: The `SUBSTR` functions return a portion of `char`, beginning at character `position`, `substring_length` characters long. `SUBSTR` calculates lengths using characters as defined by the input character set. `SUBSTRB` uses bytes instead of characters. `SUBSTRC` uses Unicode complete characters. `SUBSTR2` uses UCS2 code points. `SUBSTR4`uses UCS4 code points. - If `position` is 0, then it is treated as 1. - If `position` is positive, then Oracle Database counts from the beginning of `char` to find the first character. - If `position` is negative, then Oracle counts backward from the end of `char`. - If `substring_length` is omitted, then Oracle returns all characters to the end of `char`. If `substring_length` is less than 1, then Oracle returns null. - Examples The following example returns several specified substrings of "ABCDEFG": ```sql SELECT SUBSTR('ABCDEFG',3,4) "Substring" FROM DUAL; Substring --------- CDEF SELECT SUBSTR('ABCDEFG',-5,4) "Substring" FROM DUAL; Substring --------- CDEF ``` ================================================ FILE: Oracle SQL/SQL_commands.md ================================================ ## COMMANDS ### ALTER TABLE ``` ALTER TABLE table_name ADD column datatype; ``` `ALTER TABLE` lets you add columns to a table in a database. ### AND ``` SELECT column_name(s) FROM table_name WHERE column_1 = value_1 AND column_2 = value_2; ``` `AND` is an operator that combines two conditions. Both conditions must be true for the row to be included in the result set. ### AS ``` SELECT column_name AS 'Alias' FROM table_name; ``` `AS` is a keyword in SQL that allows you to rename a column or table using an *alias*. ### AVG ``` SELECT AVG(column_name) FROM table_name; ``` `AVG()` is an aggregate function that returns the average value for a numeric column. ### BETWEEN ``` SELECT column_name(s) FROM table_name WHERE column_name BETWEEN value_1 AND value_2; ``` The `BETWEEN` operator is used to filter the result set within a certain range. The values can be numbers, text or dates. ### COUNT ``` SELECT COUNT(column_name) FROM table_name; ``` `COUNT()` is a function that takes the name of a column as an argument and counts the number of rows where the column is not `NULL`. ### CREATE TABLE ``` CREATE TABLE table_name (column_1 datatype, column_2 datatype, column_3 datatype); ``` `CREATE TABLE` creates a new table in the database. It allows you to specify the name of the table and the name of each column in the table. ### DELETE ``` DELETE FROM table_name WHERE some_column = some_value; ``` `DELETE` statements are used to remove rows from a table. ### GROUP BY ``` SELECT COUNT(*) FROM table_name GROUP BY column_name; ``` `GROUP BY` is a clause in SQL that is only used with aggregate functions. It is used in collaboration with the `SELECT` statement to arrange identical data into groups. ### INNER JOIN ``` SELECT column_name(s) FROM table_1 JOIN table_2 ON table_1.column_name = table_2.column_name; ``` An inner join will combine rows from different tables if the *join condition* is true. ### INSERT ``` INSERT INTO table_name (column_1, column_2, column_3) VALUES (value_1, 'value_2', value_3); ``` `INSERT` statements are used to add a new row to a table. ### LIKE ``` SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern; ``` `LIKE` is a special operator used with the `WHERE` clause to search for a specific pattern in a column. ### LIMIT ``` SELECT column_name(s) FROM table_name LIMIT number; ``` `LIMIT` is a clause that lets you specify the maximum number of rows the result set will have. ### MAX ``` SELECT MAX(column_name) FROM table_name; ``` `MAX()` is a function that takes the name of a column as an argument and returns the largest value in that column. ### MIN ``` SELECT MIN(column_name) FROM table_name; ``` `MIN()` is a function that takes the name of a column as an argument and returns the smallest value in that column. ### OR ``` SELECT column_name FROM table_name WHERE column_name = value_1 OR column_name = value_2; ``` `OR` is an operator that filters the result set to only include rows where either condition is true. ### ORDER BY ``` SELECT column_name FROM table_name ORDER BY column_name ASC|DESC; ``` `ORDER BY` is a clause that indicates you want to sort the result set by a particular column either alphabetically or numerically. ### OUTER JOIN ``` SELECT column_name(s) FROM table_1 LEFT JOIN table_2 ON table_1.column_name = table_2.column_name; ``` An outer join will combine rows from different tables even if the the join condition is not met. Every row in the *left* table is returned in the result set, and if the join condition is not met, then `NULL` values are used to fill in the columns from the *right* table. ### ROUND ``` SELECT ROUND(column_name, integer) FROM table_name; ``` `ROUND()` is a function that takes a column name and an integer as an argument. It rounds the values in the column to the number of decimal places specified by the integer. ### SELECT ``` SELECT column_name FROM table_name; ``` `SELECT` statements are used to fetch data from a database. Every query will begin with SELECT. ### SELECT DISTINCT ``` SELECT DISTINCT column_name FROM table_name; ``` `SELECT DISTINCT` specifies that the statement is going to be a query that returns unique values in the specified column(s). ### SUM ``` SELECT SUM(column_name) FROM table_name; ``` `SUM()` is a function that takes the name of a column as an argument and returns the sum of all the values in that column. ### UPDATE ``` UPDATE table_name SET some_column = some_value WHERE some_column = some_value; ``` `UPDATE` statments allow you to edit rows in a table. ### WHERE ``` SELECT column_name(s) FROM table_name WHERE column_name operator value; ``` `WHERE` is a clause that indicates you want to filter the result set to include only rows where the following *condition* is true. ================================================ FILE: PHP/README.md ================================================ # PHP Help Sheet ## Treehouse PHP Classes > PHP OOP > classes > recipe.php > cookbook.php ```php // recipe.php title . "by" . $this->source; } public function addIngredient($item, $amount = null, $measure=null) { if ($amount != null && !is_float($amount) && !is_int($amount)) { exit("The amount must be a float: ") . gettype($amount) . " $amount given"); } if ($measure != null && !in_array(strtolower($measure), $this->measurements)) { exit("Please enter a valid measurement: " . implode(", ", $this->measurements)); } $this->ingredients[] = array ( "item" => ucwords($item), "amount" => $amount, "measure" => strtolower($measure) ); } public function getIngredients() { return $this->ingredients; } public function setTitle($title) { $this->title = ucword($title); } public function getTitle() { return $this->title; } } ?> // cookbook.php source; $recipe1->source("Grandma Holligan"); echo $recipe1->source; $recipe1->setTitle("My first recipe"); $recipe1->getTitle(); $recipe1->addIngredient("egg",1); $recipe1->addIngredient("flour",2,"cup"); $recipe2 = new Recipe(); $recipe2->source = "Betty Crocker"; $recipe1->setTitle = "My second recipe"; echo $recipe1->source; echo $recipe2->source; echo $recipe1->displayRecipe(); echo $recipe2->displayRecipe(); foreach ($recipe1->getIngredients() as $ing) { echo "\n" . $ing["amount"] . " " . $ing["measure"] . " " . $ing["item"]; } var_dump($recipe1); ?> ``` ## PHP Access Modifiers ```php getDimensions()); } } ?> ``` ## PHP Magic Methods and Constants Some magic constants: __CLASS__ __FILE__ ```php setTitle($title); } public function __toString() { $output = "You are calling a " . __CLASS__ . " object with the title \""; $output .= $this->getTitle() . "\""; $output .= "\nIt is stored in " . basename(__FILE__) . " at " . __DIR__ . "."; $output .= "\nThis display is from line " . __LINE__ . " in method " . __METHOD__; $output .= "\nThe following methods are available for objects of this class: \n"; $output .= implode("\n", get_class_methods(__CLASS__)); return $output; } } class Render { public function __toString() { $output = "The following methods are available for " . __CLASS__ . " objects: \n"; $output .= implode("\n", get_class_methods(__CLASS__)); return $output; } } $example = new Example("Name"); echo $example; ?> common_name = $name; $this->flavor = $flavor; $this->record_weight = $record; } public function getInfo() { return "A {$this->common_name} is an {$this->flavor} flavored fish. The world record weight is {$this->record_weight}."; } } $bass = new Fish("Largemouth Bass", "Excellent", "22 pounds 5 ounces"); ?> ``` ## PHP Collections recipecollection.php ```php recipes[] = $recipe; } public function getRecipe() { return $this->recipes; } } ?> ``` ## PHP Arrays Create $myArray = array(); Push into $myArray[] = "­Som­eth­ing­"; Push to associ­ative $myArr­ay[­'key'] = "­Val­ue"; Create numeric $myArray = array(­'va­lue', 'value2'); Create associ­ative $a = array(­'ke­y'=­>'v­al'); Print from numeric echo $myArr­ay[0]; Print from associ­ative echo $myArr­ay[­'key']; Associ­ative arrays Keys are strings Numeric arrays Keys are numbers: 0,1,2,3,4 ## PHP Array Functions array_diff (arr1, arr2 ...) array_filter (arr, function) array_flip (arr) array_intersect (arr1, arr2 ...) array_merge (arr1, arr2 ...) array_pop (arr) array_push (arr, var1, var2 ...) array_reverse (arr) array_keys(array $array [, mixed $search_value = null [, bool $strict = false ]] ) array_search (needle, arr) array_walk (arr, function) count (count) in_array (needle, haystack) // ARRAY EXAMPLES ```php houses as $house) { if ($house->roof_color == $color || $house->wall_color == $color) { $return[] = $house; } } return $return; } } ?> recipes as $recipe) { foreach($recipe->getIngredients() as $ing) { $item = $ing["item"]; if (strpos($item, ",")) { $item = strstr($item, ",", true); } if (in_array($item."s", $ingredients)) { $item.="s"; } else if (in_array(substr($item, 0, -1), $ingredients)) { $item = substr($item, 0, -1); } $ingredients[$item] = array ( $ing["amount"], $ing["measure"] ); } } return $ingredients; } ?> ``` ## PHP Control Flow Logic if (condi­tion) { ... } elseif (condi­tion) { ... } else { ... } FOR loop for (initi­alize; condition; update) { ... } WHILE loop while (condi­tion) { ... } FOREACH loop foreach ($array as $value) { ... } DO WHILE do { ... ;} while (condi­tion) SWITCH ($s) { case 1: ... break; case 2: ... break; default: ... } ## PHP if/elseif statements within a web document ```php

``` ## PHP General Functions isset() test for variable exists empty() test for empty variable mail($to, $subject, $msg, 'From: ' . $email) mail function mysqli­_fe­tch­_ar­ray­($r­esult) fetch each row of a query (in $result) header() send a header from the server is_num­eric() test to see if a value is number exit() causes script to stop immedi­ately trim($­string) trims leading and trailing spaces mysqli­_re­al_­esc­ape­_st­rin­g($­string) escapes special characters str_re­pla­ce('a', 'b', $string) replace a with b in a string explode(', ' , $string) make string into array implode(', " $string) make array into string substr ($string, start, len) grabs a substring preg_m­atc­h('­regex', $string) matches regular expres­sions preg_r­epl­ace­('r­egex', $replace, $string) replaces characters in a string by regex ## PHP Regex Functions ereg (pattern, str) split (pattern, str) ereg_replace (pattern, replace, str) preg_grep (pattern, arr) preg_match (pattern, str) preg_match_all (pattern, str, arr) preg_replace (pattern, replace, str) preg_split (pattern, str) ## PHP String Functions crypt (str, salt) explode (sep, str) implode (glue, arr) nl2br (str) sprintf (frmt, args) strip_tags (str, allowed_tags) str_replace (search, replace, str) strpos (str, needle) strrev (str) strstr (str, needle) strtolower (str) strtoupper (str) substr (string, start, len) ## PHP File System Functions clearstatcache () copy (source, dest) fclose (handle) fgets (handle, len) file (file) filemtime (file) filesize (file) file_exists (file) fopen (file, mode) fread (handle, len) fwrite (handle, str) readfile (file)clearstatcache () copy (source, dest) fclose (handle) fgets (handle, len) file (file) filemtime (file) filesize (file) file_exists (file) fopen (file, mode) fread (handle, len) fwrite (handle, str) readfile (file) ## PHP Date/Time Functions checkdate (month, day, year) date (format, timestamp) getdate (timestamp) mktime (hr, min, sec, month, day, yr) strftime (formatstring, timestamp) strtotime (str) time () ## PHP Date Formatting Y 4 digit year (2008) y 2 digit year (08) F Long month (January) M Short month (Jan) m Month ⁴ (01 to 12) n Month (1 to 12) D Short day name (Mon) l Long day name (Monday) (lowercase L) d Day ⁴ (01 to 31) j Day (1 to 31) h 12 Hour ⁴ (01 to 12) g 12 Hour (1 to 12) H 24 Hour ⁴ (00 to 23) G 24 Hour (0 to 23) i Minutes ⁴ (00 to 59) s Seconds ⁴ (00 to 59) w Day of week ¹ (0 to 6) z Day of year (0 to 365) W Week of year ² (1 to 53) t Days in month (28 to 31) a am or pm A AM or PM B Swatch Internet Time (000 to 999) S Ordinal Suffix (st, nd, rd, th) T Timezone of machine (GMT) Z Timezone offset (seconds) O GMT offset (hours) (+0200) I Daylight saving (1 or 0) L Leap year (1 or 0) U Seconds since Epoch ³ c ISO 8601 (PHP 5) (2008-­07-­31T­18:­30:­13+­01:00) r RFC 2822 (Thu, 31 Jul 2008 18:30:13 +0100) ## Accessing deep arrays to find values ```php $locations = Timber::get_terms('locations'); $data = []; $exclusion = []; foreach($locations as $location) { $data[] = [ "location" => $location, "posts" => Locations::getPostsForLocation($location,$count,$exclusion) ]; // add posts with current ids to array to check against foreach ($data as $key => $value) { if ($value["posts"]) { $posts = $value["posts"]; foreach($posts as $key => $value) { if (in_array($value->id, $exclusion)) { unset($posts[$key]); } else { array_push($exclusion, $value->id); } } } } } ``` ================================================ FILE: Perl/README.md ================================================ # Perl 5 Cheatsheet ## Table of Contents - [General](#general) - [Strings and Numbers 1](#strings-and-numbers-1) - [Strings and Numbers 2](#strings-and-numbers-2) - [Subroutines 1](#subroutines-1) ## General ```perl # Tell the compiler to generate errors if variables are not declared use strict; # Tell the compiler to show warnings use warnings; # my creates block scoped variables my $value = 0; # Print the Perl version # It prints something like 5.018002, which means 5.18.2 print("$]\n"); # Print the operating sysyem # It prints something like darwin, linux, MSWin32, etc. print("$^O\n"); ``` References: - http://www.perlmonks.org/?node_id=185675 ## Strings and Numbers 1 ```perl use strict; use warnings; my $scalar1 = 8; my $scalar2 = 42; my $scalar3 = "8"; # Numeric Comparison: # ==, !=, <, >, <=, >=, <=> my $result1 = $scalar1 == $scalar2; # undef my $result2 = $scalar1 < $scalar2; # 1 my $result3 = $scalar1 <=> $scalar2; # -1 # String Comparison: # eq, ne, lt, gt, le, ge, cmp my $result4 = $scalar1 eq $scalar3; # 1 my $result5 = $scalar1 lt $scalar2; # undef my $result6 = $scalar1 cmp $scalar2; # 1 # Arithmetic Operators # $scalar3 behaves like a number print($scalar2 + $scalar3, "\n"); # Addition: 50 print($scalar2 - $scalar3, "\n"); # Subtraction: 34 print($scalar2 * $scalar3, "\n"); # Multiplication: 336 print($scalar2 / $scalar3, "\n"); # Division: 5.25 print($scalar2 % $scalar3, "\n"); # Remainder: 2 print($scalar2 ** $scalar3, "\n"); # Exponentiation: 9682651996416 print("\n"); print($scalar2++, "\n"); # Post-Increment: 42 print($scalar2, "\n"); # 43 print(++$scalar2, "\n"); # Pre-Increment: 44 print("\n"); # String Operators # $scalar1 behaves like a string print($scalar1 . $scalar3, "\n"); # Concatenation: 88 print($scalar1 x $scalar3, "\n"); # Repetition: 88888888 print("\n"); # Single Quotes and Double Quotes print('$scalar1, $scalar2', "\n"); # $scalar1, $scalar2 print("$scalar1, $scalar2\n"); # 8, 44 ``` References: - `man perlop` ## Strings and Numbers 2 ```perl use strict; use warnings; my $scalar1 = 8; my $scalar4 = "foo"; my $scalar5 = "bar"; # $scalar4 behaves like zero print($scalar4 + $scalar1, "\n"); # 8, Warning: Argument "foo" isn't numeric in addition (+) print($scalar4 - $scalar1, "\n"); # -8 print($scalar4 * $scalar1, "\n"); # 0 print($scalar4 / $scalar1, "\n"); # 0 print($scalar4 % $scalar1, "\n"); # 0 print($scalar4 ** $scalar1, "\n"); # 0 print("\n"); print($scalar1 + $scalar4, "\n"); # 8 print($scalar1 - $scalar4, "\n"); # 8 print($scalar1 * $scalar4, "\n"); # 0 # print($scalar1 / $scalar4, "\n"); # Error: Illegal division by zero # print($scalar1 % $scalar4, "\n"); # Error: Illegal modulus zero print($scalar1 ** $scalar4, "\n"); # 1 print("\n"); # String Increment print($scalar5++, "\n"); # Post-Increment: bar print($scalar5, "\n"); # bas print(++$scalar5, "\n"); # Pre-Increment: bat print("\n"); # String Increment (Weird Behaviour) # $scalar4 becomes a number after the warning above # Tested on: # - Perl v5.18.2 on darwin # - Perl v5.24.2 on linux print($scalar4++, "\n"); # Post-Increment: foo print($scalar4, "\n"); # 1 print(++$scalar4, "\n"); # Pre-Increment: 2 print("\n"); ``` ## Subroutines 1 ```perl use strict; use warnings; # Subroutine Forward Declaration sub print_first_three_arguments; # This prints: Amy Bob Cody print_first_three_arguments("Amy", "Bob", "Cody", "Dan"); # Parentheses are optional print_first_three_arguments "Amy", "Bob", "Cody", "Dan"; sub print_first_three_arguments { my $first = shift; my $second = shift; my $third = shift; print($first, " ", $second, " ", $third, "\n"); } # Subroutine Reference (Function Pointer) my $p3ptr = \&print_first_three_arguments; $p3ptr->("Amy", "Bob", "Cody", "Dan"); # Old syntax, same result &$p3ptr("Amy", "Bob", "Cody", "Dan"); # Anonymous Subroutine my $p3anon = sub { my $first = shift; my $second = shift; my $third = shift; print($first, " ", $second, " ", $third, "\n"); }; $p3anon->("Amy", "Bob", "Cody", "Dan"); # Old syntax, same result &$p3anon("Amy", "Bob", "Cody", "Dan"); ``` ================================================ FILE: Python/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at carlos.w.montecinos@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: Python/CONTRIBUTING.md ================================================ ## Contributing 🎉 First off, thank you for taking the time to contribute! The following is a set of guidelines for contributing to the 🐍 cheatsheet. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to [this document](https://github.com/wilfredinni/python-cheatsheet/blob/master/CONTRIBUTING.md) in a pull request. ### Code of Conduct This project and everyone who participates in it is governed by the [Contributor Covenant Code of Conduct](https://github.com/wilfredinni/python-cheatsheet/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to services@github.com. ### You Can * Propose changes to the cheatsheet. * Improve existing topics and examples. * Add new topics or resources. * Ask for new topics by creating an [Issue](https://github.com/wilfredinni/python-cheatsheet/issues). * Read the issues, Fork the project and do a [Pull Request](https://github.com/wilfredinni/python-cheatsheet/pulls). * Report any kind of error or typo by creating an [Issue](https://github.com/wilfredinni/python-cheatsheet/issues) or fix it with a [Pull Request](https://github.com/wilfredinni/python-cheatsheet/pulls). * **Write an article** that *could* be published in the [Blog](https://www.pythoncheatsheet.org/blog) and used in the [webpage](https://www.pythoncheatsheet.org) as reference. ### Styling **Important!** Edit only the README.md and if you can, use [Notedown](https://github.com/aaren/notedown) to convert it to a Jupyter Notebook (no problem if you can't). * Use `##` headers for titles. * Use `###` for the sub categories. * Add a link to your section to the table of contents. * Make sure to include examples and keep explanations short. * At the end of your section or sub category, add a [*Return to the Top*](#python-cheatsheet) link. ### What you need to Know If you don't know were to start, please check this out: * [Mastering Markdown](https://guides.github.com/features/mastering-markdown/). * [Mastering Issues](https://guides.github.com/features/issues/). * [Forking Projects](https://guides.github.com/activities/forking/). * And read the rest of the [GitHub Guides](https://guides.github.com/). That is all! thank you again for taking the time to check how to contribute. ================================================ FILE: Python/README.md ================================================ # Python Cheat Sheet Basic cheatsheet for Python mostly based on the book written by Al Sweigart, [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/) under the [Creative Commons license](https://creativecommons.org/licenses/by-nc-sa/3.0/) and many other sources. ## Contribute All contributions are welcome: - Read the issues, Fork the project and do a Pull Request. - Request a new topic creating a `New issue` with the `enhancement` tag. - Find any kind of errors in the cheat sheet and create a `New issue` with the details or fork the project and do a Pull Request. - Suggest a better or more pythonic way for existing examples. ## Read It - [Website](https://www.pythoncheatsheet.org) - [Github](https://github.com/wilfredinni/python-cheatsheet) - [PDF](https://github.com/wilfredinni/Python-cheatsheet/raw/master/python_cheat_sheet.pdf) - [Jupyter Notebook](https://mybinder.org/v2/gh/wilfredinni/python-cheatsheet/master?filepath=python_cheat_sheet.ipynb) ## Python Cheatsheet - [The Zen of Python](#the-zen-of-python) - [Python Basics](#python-basics) - [Math Operators](#math-operators) - [Data Types](#data-types) - [String Concatenation and Replication](#string-concatenation-and-replication) - [Variables](#variables) - [Comments](#comments) - [The print() Function](#the-print-function) - [The input() Function](#the-input-function) - [The len() Function](#the-len-function) - [The str(), int(), and float() Functions](#the-str-int-and-float-functions) - [Flow Control](#flow-control) - [Comparison Operators](#comparison-operators) - [Boolean evaluation](#boolean-evaluation) - [Boolean Operators](#boolean-operators) - [Mixing Boolean and Comparison Operators](#mixing-boolean-and-comparison-operators) - [if Statements](#if-statements) - [else Statements](#else-statements) - [elif Statements](#elif-statements) - [while Loop Statements](#while-loop-statements) - [break Statements](#break-statements) - [continue Statements](#continue-statements) - [for Loops and the range() Function](#for-loops-and-the-range-function) - [For else statement](#for-else-statement) - [Importing Modules](#importing-modules) - [Ending a Program Early with sys.exit()](#ending-a-program-early-with-sysexit) - [Functions](#functions) - [Return Values and return Statements](#return-values-and-return-statements) - [The None Value](#the-none-value) - [Keyword Arguments and print()](#keyword-arguments-and-print) - [Local and Global Scope](#local-and-global-scope) - [The global Statement](#the-global-statement) - [Exception Handling](#exception-handling) - [Basic exception handling](#basic-exception-handling) - [Final code in exception handling](#final-code-in-exception-handling) - [Lists](#lists) - [Getting Individual Values in a List with Indexes](#getting-individual-values-in-a-list-with-indexes) - [Negative Indexes](#negative-indexes) - [Getting Sublists with Slices](#getting-sublists-with-slices) - [Getting a List’s Length with len()](#getting-a-list%E2%80%99s-length-with-len) - [Changing Values in a List with Indexes](#changing-values-in-a-list-with-indexes) - [List Concatenation and List Replication](#list-concatenation-and-list-replication) - [Removing Values from Lists with del Statements](#removing-values-from-lists-with-del-statements) - [Using for Loops with Lists](#using-for-loops-with-lists) - [Looping Through Multiple Lists with zip()](#looping-through-multiple-lists-with-zip) - [The in and not in Operators](#the-in-and-not-in-operators) - [The Multiple Assignment Trick](#the-multiple-assignment-trick) - [Augmented Assignment Operators](#augmented-assignment-operators) - [Finding a Value in a List with the index() Method](#finding-a-value-in-a-list-with-the-index-method) - [Adding Values to Lists with the append() and insert() Methods](#adding-values-to-lists-with-the-append-and-insert-methods) - [Removing Values from Lists with remove()](#removing-values-from-lists-with-remove) - [Sorting the Values in a List with the sort() Method](#sorting-the-values-in-a-list-with-the-sort-method) - [Tuple Data Type](#tuple-data-type) - [Converting Types with the list() and tuple() Functions](#converting-types-with-the-list-and-tuple-functions) - [Dictionaries and Structuring Data](#dictionaries-and-structuring-data) - [The keys(), values(), and items() Methods](#the-keys-values-and-items-methods) - [Checking Whether a Key or Value Exists in a Dictionary](#checking-whether-a-key-or-value-exists-in-a-dictionary) - [The get() Method](#the-get-method) - [The setdefault() Method](#the-setdefault-method) - [Pretty Printing](#pretty-printing) - [Merge two dictionaries](#merge-two-dictionaries) - [sets](#sets) - [Initializing a set](#initializing-a-set) - [sets: unordered collections of unique elements](#sets-unordered-collections-of-unique-elements) - [set add() and update()](#set-add-and-update) - [set remove() and discard()](#set-remove-and-discard) - [set union()](#set-union) - [set intersection](#set-intersection) - [set difference](#set-difference) - [set symetric_difference](#set-symetricdifference) - [itertools Module](#itertools-module) - [accumulate()](#accumulate) - [combinations()](#combinations) - [combinations_with_replacement()](#combinationswithreplacement) - [count()](#count) - [cycle()](#cycle) - [chain()](#chain) - [compress()](#compress) - [dropwhile()](#dropwhile) - [filterfalse()](#filterfalse) - [groupby()](#groupby) - [islice()](#islice) - [permutations()](#permutations) - [product()](#product) - [repeat()](#repeat) - [starmap()](#starmap) - [takewhile()](#takewhile) - [tee()](#tee) - [zip_longest()](#ziplongest) - [Comprehensions](#comprehensions) - [List comprehension](#list-comprehension) - [Set comprehension](#set-comprehension) - [Dict comprehension](#dict-comprehension) - [Manipulating Strings](#manipulating-strings) - [Escape Characters](#escape-characters) - [Raw Strings](#raw-strings) - [Multiline Strings with Triple Quotes](#multiline-strings-with-triple-quotes) - [Indexing and Slicing Strings](#indexing-and-slicing-strings) - [The in and not in Operators with Strings](#the-in-and-not-in-operators-with-strings) - [The in and not in Operators with list](#the-in-and-not-in-operators-with-list) - [The upper(), lower(), isupper(), and islower() String Methods](#the-upper-lower-isupper-and-islower-string-methods) - [The isX String Methods](#the-isx-string-methods) - [The startswith() and endswith() String Methods](#the-startswith-and-endswith-string-methods) - [The join() and split() String Methods](#the-join-and-split-string-methods) - [Justifying Text with rjust(), ljust(), and center()](#justifying-text-with-rjust-ljust-and-center) - [Removing Whitespace with strip(), rstrip(), and lstrip()](#removing-whitespace-with-strip-rstrip-and-lstrip) - [Copying and Pasting Strings with the pyperclip Module (need pip install)](#copying-and-pasting-strings-with-the-pyperclip-module-need-pip-install) - [String Formatting](#string-formatting) - [% operator](#operator) - [String Formatting (str.format)](#string-formatting-strformat) - [Lazy string formatting](#lazy-string-formatting) - [Formatted String Literals or f-strings (Python 3.6+)](#formatted-string-literals-or-f-strings-python-36) - [Template Strings](#template-strings) - [Regular Expressions](#regular-expressions) - [Matching Regex Objects](#matching-regex-objects) - [Grouping with Parentheses](#grouping-with-parentheses) - [Matching Multiple Groups with the Pipe](#matching-multiple-groups-with-the-pipe) - [Optional Matching with the Question Mark](#optional-matching-with-the-question-mark) - [Matching Zero or More with the Star](#matching-zero-or-more-with-the-star) - [Matching One or More with the Plus](#matching-one-or-more-with-the-plus) - [Matching Specific Repetitions with Curly Brackets](#matching-specific-repetitions-with-curly-brackets) - [Greedy and Nongreedy Matching](#greedy-and-nongreedy-matching) - [The findall() Method](#the-findall-method) - [Making Your Own Character Classes](#making-your-own-character-classes) - [The Caret and Dollar Sign Characters](#the-caret-and-dollar-sign-characters) - [The Wildcard Character](#the-wildcard-character) - [Matching Everything with Dot-Star](#matching-everything-with-dot-star) - [Matching Newlines with the Dot Character](#matching-newlines-with-the-dot-character) - [Review of Regex Symbols](#review-of-regex-symbols) - [Case-Insensitive Matching](#case-insensitive-matching) - [Substituting Strings with the sub() Method](#substituting-strings-with-the-sub-method) - [Managing Complex Regexes](#managing-complex-regexes) - [Handling File and Directory Paths](#handling-file-and-directory-paths) - [Backslash on Windows and Forward Slash on OS X and Linux](#backslash-on-windows-and-forward-slash-on-os-x-and-linux) - [The Current Working Directory](#the-current-working-directory) - [Creating New Folders](#creating-new-folders) - [Absolute vs. Relative Paths](#absolute-vs-relative-paths) - [Handling Absolute and Relative Paths](#handling-absolute-and-relative-paths) - [Checking Path Validity](#checking-path-validity) - [Finding File Sizes and Folder Contents](#finding-file-sizes-and-folder-contents) - [Copying Files and Folders](#copying-files-and-folders) - [Moving and Renaming Files and Folders](#moving-and-renaming-files-and-folders) - [Permanently Deleting Files and Folders](#permanently-deleting-files-and-folders) - [Safe Deletes with the send2trash Module](#safe-deletes-with-the-send2trash-module) - [Walking a Directory Tree](#walking-a-directory-tree) - [Reading and Writing Files](#reading-and-writing-files) - [The File Reading/Writing Process](#the-file-readingwriting-process) - [Opening and reading files with the open() function](#opening-and-reading-files-with-the-open-function) - [Writing to Files](#writing-to-files) - [Saving Variables with the shelve Module](#saving-variables-with-the-shelve-module) - [Saving Variables with the pprint.pformat() Function](#saving-variables-with-the-pprintpformat-function) - [Reading ZIP Files](#reading-zip-files) - [Extracting from ZIP Files](#extracting-from-zip-files) - [Creating and Adding to ZIP Files](#creating-and-adding-to-zip-files) - [JSON, YAML and configuration files](#json-yaml-and-configuration-files) - [JSON](#json) - [YAML](#yaml) - [Anyconfig](#anyconfig) - [Debugging](#debugging) - [Raising Exceptions](#raising-exceptions) - [Getting the Traceback as a String](#getting-the-traceback-as-a-string) - [Assertions](#assertions) - [Logging](#logging) - [Logging Levels](#logging-levels) - [Disabling Logging](#disabling-logging) - [Logging to a File](#logging-to-a-file) - [Lambda Functions](#lambda-functions) - [Ternary Conditional Operator](#ternary-conditional-operator) - [args and kwargs](#args-and-kwargs) - [Thinks to Remember(args)](#thinks-to-rememberargs) - [Thinks to remember(kwargs)](#thinks-to-rememberkwargs) - [Context Manager](#context-manager) - [with statement](#with-statement) - [Writing your own contextmanager using generator syntax](#writing-your-own-contextmanager-using-generator-syntax) - [`__main__` Top-level script environment](#main-top-level-script-environment) - [Advantages](#advantages) - [setup.py](#setuppy) - [Dataclasses](#dataclasses) - [Features](#features) - [Default values](#default-values) - [Type hints](#type-hints) - [Virtual Environment](#virtual-environment) - [virtualenv](#virtualenv) - [pipenv](#pipenv) - [anaconda](#anaconda) ## The Zen of Python From the [PEP 20 -- The Zen of Python](https://www.python.org/dev/peps/pep-0020/): > Long time Pythoneer Tim Peters succinctly channels the BDFL's guiding principles for Python's design into 20 aphorisms, only 19 of which have been written down. ```python >>> import this The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those! ``` [*Return to the Top*](#python-cheatsheet) ## Python Basics ### Math Operators From **Highest** to **Lowest** precedence: | Operators | Operation | Example | | --------- | ---------------- | --------------- | | ** | Exponent | `2 ** 3 = 8` | | % | Modulus/Remaider | `22 % 8 = 6` | | // | Integer division | `22 // 8 = 2` | | / | Division | `22 / 8 = 2.75` | | * | Multiplication | `3 * 3 = 9` | | - | Subtraction | `5 - 2 = 3` | | + | Addition | `2 + 2 = 4` | Examples of expressions in the interactive shell: ```python >>> 2 + 3 * 6 20 ``` ```python >>> (2 + 3) * 6 30 ``` ```python >>> 2 ** 8 256 ``` ```python >>> 23 // 7 3 ``` ```python >>> 23 % 7 2 ``` ```python >>> (5 - 1) * ((7 + 1) / (3 - 1)) 16.0 ``` [*Return to the Top*](#python-cheatsheet) ### Data Types | Data Type | Examples | | ---------------------- | ----------------------------------------- | | Integers | `-2, -1, 0, 1, 2, 3, 4, 5` | | Floating-point numbers | `-1.25, -1.0, --0.5, 0.0, 0.5, 1.0, 1.25` | | Strings | `'a', 'aa', 'aaa', 'Hello!', '11 cats'` | [*Return to the Top*](#python-cheatsheet) ### String Concatenation and Replication String concatenation: ```python >>> 'Alice' 'Bob' 'AliceBob' ``` Note: Avoid `+` operator for string concatenation. Prefer string formatting. String Replication: ```python >>> 'Alice' * 5 'AliceAliceAliceAliceAlice' ``` [*Return to the Top*](#python-cheatsheet) ### Variables You can name a variable anything as long as it obeys the following three rules: 1. It can be only one word. 1. It can use only letters, numbers, and the underscore (`_`) character. 1. It can’t begin with a number. 1. Variable name starting with an underscore (`_`) are considered as "unuseful`. Example: ```python >>> spam = 'Hello' >>> spam 'Hello' ``` ```python >>> _spam = 'Hello' ``` `_spam` should not be used again in the code. [*Return to the Top*](#python-cheatsheet) ### Comments Inline comment: ```python # This is a comment ``` Multiline comment: ```Python # This is a # multiline comment ``` Code with a comment: ```python a = 1 # initialization ``` Please note the two spaces in front of the comment. Function docstring: ```python def foo(): """ This is a function docstring You can also use: ''' Function Docstring ''' """ ``` [*Return to the Top*](#python-cheatsheet) ### The print() Function ```python >>> print('Hello world!') Hello world! ``` ```python >>> a = 1 >>> print('Hello world!', a) Hello world! 1 ``` [*Return to the Top*](#python-cheatsheet) ### The input() Function Example Code: ```python >>> print('What is your name?') # ask for their name >>> myName = input() >>> print('It is good to meet you, {}'.format(myName)) What is your name? Al It is good to meet you, Al ``` [*Return to the Top*](#python-cheatsheet) ### The len() Function Evaluates to the integer value of the number of characters in a string: ```python >>> len('hello') 5 ``` Note: test of emptiness of strings, lists, dictionary, etc, should **not** use len, but prefer direct boolean evaluation. ```python >>> a = [1, 2, 3] >>> if a: >>> print("the list is not empty!") ``` [*Return to the Top*](#python-cheatsheet) ### The str(), int(), and float() Functions Integer to String or Float: ```python >>> str(29) '29' ``` ```python >>> print('I am {} years old.'.format(str(29))) I am 29 years old. ``` ```python >>> str(-3.14) '-3.14' ``` Float to Integer: ```python >>> int(7.7) 7 ``` ```python >>> int(7.7) + 1 8 ``` [*Return to the Top*](#python-cheatsheet) ## Flow Control ### Comparison Operators | Operator | Meaning | | -------- | ------------------------ | | `==` | Equal to | | `!=` | Not equal to | | `<` | Less than | | `>` | Greater Than | | `<=` | Less than or Equal to | | `>=` | Greater than or Equal to | These operators evaluate to True or False depending on the values you give them. Examples: ```python >>> 42 == 42 True ``` ```python >>> 40 == 42 False ``` ```python >>> 'hello' == 'hello' True ``` ```python >>> 'hello' == 'Hello' False ``` ```python >>> 'dog' != 'cat' True ``` ```python >>> 42 == 42.0 True ``` ```python >>> 42 == '42' False ``` ### Boolean evaluation Never use `==` or `!=` operator to evaluate boolean operation. Use the `is` or `is not` operators, or use implicit boolean evaluation. NO (even if they are valid Python): ```python >>> True == True True ``` ```python >>> True != False True ``` YES (even if they are valid Python): ```python >>> True is True True ``` ```python >>> True is not False True ``` These statements are equivalent: ```Python >>> if a is True: >>> pass >>> if a is not False: >>> pass >>> if a: >>> pass ``` And these as well: ```Python >>> if a is False: >>> pass >>> if a is not True: >>> pass >>> if not a: >>> pass ``` [*Return to the Top*](#python-cheatsheet) ### Boolean Operators There are three Boolean operators: and, or, and not. The *and* Operator’s *Truth* Table: | Expression | Evaluates to | | ----------------- | ------------ | | `True and True` | `True` | | `True and False` | `False` | | `False and True` | `False` | | `False and False` | `False` | The *or* Operator’s *Truth* Table: | Expression | Evaluates to | | ---------------- | ------------ | | `True or True` | `True` | | `True or False` | `True` | | `False or True` | `True` | | `False or False` | `False` | The *not* Operator’s *Truth* Table: | Expression | Evaluates to | | ----------- | ------------ | | `not True` | `False` | | `not False` | `True` | [*Return to the Top*](#python-cheatsheet) ### Mixing Boolean and Comparison Operators ```python >>> (4 < 5) and (5 < 6) True ``` ```python >>> (4 < 5) and (9 < 6) False ``` ```python >>> (1 == 2) or (2 == 2) True ``` You can also use multiple Boolean operators in an expression, along with the comparison operators: ```python >>> 2 + 2 == 4 and not 2 + 2 == 5 and 2 * 2 == 2 + 2 True ``` [*Return to the Top*](#python-cheatsheet) ### if Statements ```python if name == 'Alice': print('Hi, Alice.') ``` [*Return to the Top*](#python-cheatsheet) ### else Statements ```python name = 'Bob' if name == 'Alice': print('Hi, Alice.') else: print('Hello, stranger.') ``` [*Return to the Top*](#python-cheatsheet) ### elif Statements ```python name = 'Bob' age = 5 if name == 'Alice': print('Hi, Alice.') elif age < 12: print('You are not Alice, kiddo.') ``` ```python name = 'Bob' age = 30 if name == 'Alice': print('Hi, Alice.') elif age < 12: print('You are not Alice, kiddo.') else: print('You are neither Alice nor a little kid.') ``` [*Return to the Top*](#python-cheatsheet) ### while Loop Statements ```python spam = 0 while spam < 5: print('Hello, world.') spam = spam + 1 ``` [*Return to the Top*](#python-cheatsheet) ### break Statements If the execution reaches a break statement, it immediately exits the while loop’s clause: ```python while True: print('Please type your name.') name = input() if name == 'your name': break print('Thank you!') ``` [*Return to the Top*](#python-cheatsheet) ### continue Statements When the program execution reaches a continue statement, the program execution immediately jumps back to the start of the loop. ```python while True: print('Who are you?') name = input() if name != 'Joe': continue print('Hello, Joe. What is the password? (It is a fish.)') password = input() if password == 'swordfish': break print('Access granted.') ``` [*Return to the Top*](#python-cheatsheet) ### for Loops and the range() Function ```python >>> print('My name is') >>> for i in range(5): >>> print('Jimmy Five Times ({})'.format(str(i))) My name is Jimmy Five Times (0) Jimmy Five Times (1) Jimmy Five Times (2) Jimmy Five Times (3) Jimmy Five Times (4) ``` The *range()* function can also be called with three arguments. The first two arguments will be the start and stop values, and the third will be the step argument. The step is the amount that the variable is increased by after each iteration. ```python >>> for i in range(0, 10, 2): >>> print(i) 0 2 4 6 8 ``` You can even use a negative number for the step argument to make the for loop count down instead of up. ```python >>> for i in range(5, -1, -1): >>> print(i) 5 4 3 2 1 0 ``` ### For else statement This allows to specify a statement to execute in case of the full loop has been executed. Only useful when a `break` condition can occur in the loop: ```python >>> for i in [1, 2, 3, 4, 5]: >>> if i == 3: >>> break >>> else: >>> print("only executed when no item of the list is equal to 3") ``` [*Return to the Top*](#python-cheatsheet) ### Importing Modules ```python import random for i in range(5): print(random.randint(1, 10)) ``` ```python import random, sys, os, math ``` ```python from random import *. ``` [*Return to the Top*](#python-cheatsheet) ### Ending a Program Early with sys.exit() ```python import sys while True: print('Type exit to exit.') response = input() if response == 'exit': sys.exit() print('You typed {}.'.format(response)) ``` [*Return to the Top*](#python-cheatsheet) ## Functions ```python >>> def hello(name): >>> print('Hello {}'.format(name)) >>> >>> hello('Alice') >>> hello('Bob') Hello Alice Hello Bob ``` [*Return to the Top*](#python-cheatsheet) ### Return Values and return Statements When creating a function using the def statement, you can specify what the return value should be with a return statement. A return statement consists of the following: - The return keyword. - The value or expression that the function should return. ```python import random def getAnswer(answerNumber): if answerNumber == 1: return 'It is certain' elif answerNumber == 2: return 'It is decidedly so' elif answerNumber == 3: return 'Yes' elif answerNumber == 4: return 'Reply hazy try again' elif answerNumber == 5: return 'Ask again later' elif answerNumber == 6: return 'Concentrate and ask again' elif answerNumber == 7: return 'My reply is no' elif answerNumber == 8: return 'Outlook not so good' elif answerNumber == 9: return 'Very doubtful' r = random.randint(1, 9) fortune = getAnswer(r) print(fortune) ``` [*Return to the Top*](#python-cheatsheet) ### The None Value ```python >>> spam = print('Hello!') Hello! ``` ```python >>> spam is None True ``` Note: never compare to `None` with the `==` operator. Always use `is`. [*Return to the Top*](#python-cheatsheet) ### Keyword Arguments and print() ```python >>> print('Hello', end='') >>> print('World') HelloWorld ``` ```python >>> print('cats', 'dogs', 'mice') cats dogs mice ``` ```python >>> print('cats', 'dogs', 'mice', sep=',') cats,dogs,mice ``` [*Return to the Top*](#python-cheatsheet) ### Local and Global Scope - Code in the global scope cannot use any local variables. - However, a local scope can access global variables. - Code in a function’s local scope cannot use variables in any other local scope. - You can use the same name for different variables if they are in different scopes. That is, there can be a local variable named spam and a global variable also named spam. [*Return to the Top*](#python-cheatsheet) ### The global Statement If you need to modify a global variable from within a function, use the global statement: ```python >>> def spam(): >>> global eggs >>> eggs = 'spam' >>> >>> eggs = 'global' >>> spam() >>> print(eggs) spam ``` There are four rules to tell whether a variable is in a local scope or global scope: 1. If a variable is being used in the global scope (that is, outside of all functions), then it is always a global variable. 1. If there is a global statement for that variable in a function, it is a global variable. 1. Otherwise, if the variable is used in an assignment statement in the function, it is a local variable. 1. But if the variable is not used in an assignment statement, it is a global variable. [*Return to the Top*](#python-cheatsheet) ## Exception Handling ### Basic exception handling ```python >>> def spam(divideBy): >>> try: >>> return 42 / divideBy >>> except ZeroDivisionError as e: >>> print('Error: Invalid argument: {}'.format(e)) >>> >>> print(spam(2)) >>> print(spam(12)) >>> print(spam(0)) >>> print(spam(1)) 21.0 3.5 Error: Invalid argument: division by zero None 42.0 ``` [*Return to the Top*](#python-cheatsheet) ### Final code in exception handling Code inside the `finally` section is always executed, no matter if an exception has been raised or not, and even if an exception is not caught. ```python >>> def spam(divideBy): >>> try: >>> return 42 / divideBy >>> except ZeroDivisionError as e: >>> print('Error: Invalid argument: {}'.format(e)) >>> finally: >>> print("-- division finished --") >>> print(spam(12)) >>> print(spam(0)) 21.0 -- division finished -- 3.5 -- division finished -- Error: Invalid argument: division by zero -- division finished -- None -- division finished -- 42.0 -- division finished -- ``` [*Return to the Top*](#python-cheatsheet) ## Lists ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam ['cat', 'bat', 'rat', 'elephant'] ``` [*Return to the Top*](#python-cheatsheet) ### Getting Individual Values in a List with Indexes ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[0] 'cat' ``` ```python >>> spam[1] 'bat' ``` ```python >>> spam[2] 'rat' ``` ```python >>> spam[3] 'elephant' ``` [*Return to the Top*](#python-cheatsheet) ### Negative Indexes ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[-1] 'elephant' ``` ```python >>> spam[-3] 'bat' ``` ```python >>> 'The {} is afraid of the {}.'.format(spam[-1], spam[-3]) 'The elephant is afraid of the bat.' ``` [*Return to the Top*](#python-cheatsheet) ### Getting Sublists with Slices ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[0:4] ['cat', 'bat', 'rat', 'elephant'] ``` ```python >>> spam[1:3] ['bat', 'rat'] ``` ```python >>> spam[0:-1] ['cat', 'bat', 'rat'] ``` ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[:2] ['cat', 'bat'] ``` ```python >>> spam[1:] ['bat', 'rat', 'elephant'] ``` Slicing the complete list will perform a copy: ```python >>> spam2 = spam[:] ['cat', 'bat', 'rat', 'elephant'] >>> spam.append('dog') >>> spam ['cat', 'bat', 'rat', 'elephant', 'dog'] >>> spam2 ['cat', 'bat', 'rat', 'elephant'] ``` [*Return to the Top*](#python-cheatsheet) ### Getting a List’s Length with len() ```python >>> spam = ['cat', 'dog', 'moose'] >>> len(spam) 3 ``` [*Return to the Top*](#python-cheatsheet) ### Changing Values in a List with Indexes ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[1] = 'aardvark' >>> spam ['cat', 'aardvark', 'rat', 'elephant'] >>> spam[2] = spam[1] >>> spam ['cat', 'aardvark', 'aardvark', 'elephant'] >>> spam[-1] = 12345 >>> spam ['cat', 'aardvark', 'aardvark', 12345] ``` [*Return to the Top*](#python-cheatsheet) ### List Concatenation and List Replication ```python >>> [1, 2, 3] + ['A', 'B', 'C'] [1, 2, 3, 'A', 'B', 'C'] >>> ['X', 'Y', 'Z'] * 3 ['X', 'Y', 'Z', 'X', 'Y', 'Z', 'X', 'Y', 'Z'] >>> spam = [1, 2, 3] >>> spam = spam + ['A', 'B', 'C'] >>> spam [1, 2, 3, 'A', 'B', 'C'] ``` [*Return to the Top*](#python-cheatsheet) ### Removing Values from Lists with del Statements ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> del spam[2] >>> spam ['cat', 'bat', 'elephant'] ``` ```python >>> del spam[2] >>> spam ['cat', 'bat'] ``` [*Return to the Top*](#python-cheatsheet) ### Using for Loops with Lists ```python >>> supplies = ['pens', 'staplers', 'flame-throwers', 'binders'] >>> for i, supply in enumerate(supplies): >>> print('Index {} in supplies is: {}'.format(str(i), supply)) Index 0 in supplies is: pens Index 1 in supplies is: staplers Index 2 in supplies is: flame-throwers Index 3 in supplies is: binders ``` [*Return to the Top*](#python-cheatsheet) ### Looping Through Multiple Lists with zip() ```python >>> name = ['Pete', 'John', 'Elizabeth'] >>> age = [6, 23, 44] >>> for n, a in zip(name, age): >>> print('{} is {} years old'.format(n, a)) Pete is 6 years old John is 23 years old Elizabeth is 44 years old ``` ### The in and not in Operators ```python >>> 'howdy' in ['hello', 'hi', 'howdy', 'heyas'] True ``` ```python >>> spam = ['hello', 'hi', 'howdy', 'heyas'] >>> 'cat' in spam False ``` ```python >>> 'howdy' not in spam False ``` ```python >>> 'cat' not in spam True ``` [*Return to the Top*](#python-cheatsheet) ### The Multiple Assignment Trick The multiple assignment trick is a shortcut that lets you assign multiple variables with the values in a list in one line of code. So instead of doing this: ```python >>> cat = ['fat', 'orange', 'loud'] >>> size = cat[0] >>> color = cat[1] >>> disposition = cat[2] ``` You could type this line of code: ```python >>> cat = ['fat', 'orange', 'loud'] >>> size, color, disposition = cat ``` The multiple assignment trick can also be used to swap the values in two variables: ```python >>> a, b = 'Alice', 'Bob' >>> a, b = b, a >>> print(a) 'Bob' ``` ```python >>> print(b) 'Alice' ``` [*Return to the Top*](#python-cheatsheet) ### Augmented Assignment Operators | Operator | Equivalent | | ----------- | ----------------- | | `spam += 1` | `spam = spam + 1` | | `spam -= 1` | `spam = spam - 1` | | `spam *= 1` | `spam = spam * 1` | | `spam /= 1` | `spam = spam / 1` | | `spam %= 1` | `spam = spam % 1` | Examples: ```python >>> spam = 'Hello' >>> spam += ' world!' >>> spam 'Hello world!' >>> bacon = ['Zophie'] >>> bacon *= 3 >>> bacon ['Zophie', 'Zophie', 'Zophie'] ``` [*Return to the Top*](#python-cheatsheet) ### Finding a Value in a List with the index() Method ```python >>> spam = ['Zophie', 'Pooka', 'Fat-tail', 'Pooka'] >>> spam.index('Pooka') 1 ``` [*Return to the Top*](#python-cheatsheet) ### Adding Values to Lists with the append() and insert() Methods **append()**: ```python >>> spam = ['cat', 'dog', 'bat'] >>> spam.append('moose') >>> spam ['cat', 'dog', 'bat', 'moose'] ``` **insert()**: ```python >>> spam = ['cat', 'dog', 'bat'] >>> spam.insert(1, 'chicken') >>> spam ['cat', 'chicken', 'dog', 'bat'] ``` [*Return to the Top*](#python-cheatsheet) ### Removing Values from Lists with remove() ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam.remove('bat') >>> spam ['cat', 'rat', 'elephant'] ``` If the value appears multiple times in the list, only the first instance of the value will be removed. [*Return to the Top*](#python-cheatsheet) ### Sorting the Values in a List with the sort() Method ```python >>> spam = [2, 5, 3.14, 1, -7] >>> spam.sort() >>> spam [-7, 1, 2, 3.14, 5] ``` ```python >>> spam = ['ants', 'cats', 'dogs', 'badgers', 'elephants'] >>> spam.sort() >>> spam ['ants', 'badgers', 'cats', 'dogs', 'elephants'] ``` You can also pass True for the reverse keyword argument to have sort() sort the values in reverse order: ```python >>> spam.sort(reverse=True) >>> spam ['elephants', 'dogs', 'cats', 'badgers', 'ants'] ``` If you need to sort the values in regular alphabetical order, pass str. lower for the key keyword argument in the sort() method call: ```python >>> spam = ['a', 'z', 'A', 'Z'] >>> spam.sort(key=str.lower) >>> spam ['a', 'A', 'z', 'Z'] ``` You can use the built-in function `sorted` to return a new list: ```python >>> spam = ['ants', 'cats', 'dogs', 'badgers', 'elephants'] >>> sorted(spam) ['ants', 'badgers', 'cats', 'dogs', 'elephants'] ``` [*Return to the Top*](#python-cheatsheet) ### Tuple Data Type ```python >>> eggs = ('hello', 42, 0.5) >>> eggs[0] 'hello' ``` ```python >>> eggs[1:3] (42, 0.5) ``` ```python >>> len(eggs) 3 ``` The main way that tuples are different from lists is that tuples, like strings, are immutable. [*Return to the Top*](#python-cheatsheet) ### Converting Types with the list() and tuple() Functions ```python >>> tuple(['cat', 'dog', 5]) ('cat', 'dog', 5) ``` ```python >>> list(('cat', 'dog', 5)) ['cat', 'dog', 5] ``` ```python >>> list('hello') ['h', 'e', 'l', 'l', 'o'] ``` [*Return to the Top*](#python-cheatsheet) ## Dictionaries and Structuring Data Example Dictionary: ```python myCat = {'size': 'fat', 'color': 'gray', 'disposition': 'loud'} ``` [*Return to the Top*](#python-cheatsheet) ### The keys(), values(), and items() Methods values(): ```python >>> spam = {'color': 'red', 'age': 42} >>> for v in spam.values(): >>> print(v) red 42 ``` keys(): ```python >>> for k in spam.keys(): >>> print(k) color age ``` items(): ```python >>> for i in spam.items(): >>> print(i) ('color', 'red') ('age', 42) ``` Using the keys(), values(), and items() methods, a for loop can iterate over the keys, values, or key-value pairs in a dictionary, respectively. ```python >>> spam = {'color': 'red', 'age': 42} >>> >>> for k, v in spam.items(): >>> print('Key: {} Value: {}'.format(k, str(v))) Key: age Value: 42 Key: color Value: red ``` [*Return to the Top*](#python-cheatsheet) ### Checking Whether a Key or Value Exists in a Dictionary ```python >>> spam = {'name': 'Zophie', 'age': 7} ``` ```python >>> 'name' in spam.keys() True ``` ```python >>> 'Zophie' in spam.values() True ``` ```python >>> # You can omit the call to keys() when checking for a key >>> 'color' in spam False ``` ```python >>> 'color' not in spam True ``` ```python >>> 'color' in spam False ``` [*Return to the Top*](#python-cheatsheet) ### The get() Method ```python >>> picnic_items = {'apples': 5, 'cups': 2} >>> 'I am bringing {} cups.'.format(str(picnic_items.get('cups', 0))) 'I am bringing 2 cups.' ``` ```python >>> 'I am bringing {} eggs.'.format(str(picnic_items.get('eggs', 0))) 'I am bringing 0 eggs.' ``` [*Return to the Top*](#python-cheatsheet) ### The setdefault() Method Let's consider this code: ```python spam = {'name': 'Pooka', 'age': 5} if 'color' not in spam: spam['color'] = 'black' ``` Using `setdefault` we could make the same code more shortly: ```python >>> spam = {'name': 'Pooka', 'age': 5} >>> spam.setdefault('color', 'black') 'black' ``` ```python >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'} ``` ```python >>> spam.setdefault('color', 'white') 'black' ``` ```python >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'} ``` [*Return to the Top*](#python-cheatsheet) ### Pretty Printing ```python >>> import pprint >>> >>> message = 'It was a bright cold day in April, and the clocks were striking >>> thirteen.' >>> count = {} >>> >>> for character in message: >>> count.setdefault(character, 0) >>> count[character] = count[character] + 1 >>> >>> pprint.pprint(count) {' ': 13, ',': 1, '.': 1, 'A': 1, 'I': 1, 'a': 4, 'b': 1, 'c': 3, 'd': 3, 'e': 5, 'g': 2, 'h': 3, 'i': 6, 'k': 2, 'l': 3, 'n': 4, 'o': 2, 'p': 1, 'r': 5, 's': 3, 't': 6, 'w': 2, 'y': 1} ``` [*Return to the Top*](#python-cheatsheet) ### Merge two dictionaries ```python # in Python 3.5+: >>> x = {'a': 1, 'b': 2} >>> y = {'b': 3, 'c': 4} >>> z = {**x, **y} >>> z {'c': 4, 'a': 1, 'b': 3} # in Python 2.7 >>> z = dict(x, **y) >>> z {'c': 4, 'a': 1, 'b': 3} ``` ## sets From the Python 3 [documentation](https://docs.python.org/3/tutorial/datastructures.html) > A set is an unordered collection with no duplicate elements. Basic uses include membership testing and eliminating duplicate entries. Set objects also support mathematical operations like union, intersection, difference, and symmetric difference. ### Initializing a set There are two ways to create sets: using curly braces `{}` and the bult-in function `set()` ```python >>> s = {1, 2, 3} >>> s = set([1, 2, 3]) ``` When creating an empty set, be sure to not use the curly braces `{}` or you will get an empty dictionary instead. ```python >>> s = {} >>> type(s) ``` ### sets: unordered collections of unique elements A set automatically remove all the duplicate values. ```python >>> s = {1, 2, 3, 2, 3, 4} >>> s {1, 2, 3, 4} ``` And as an unordered data type, they can't be indexed. ```python >>> s = {1, 2, 3} >>> s[0] Traceback (most recent call last): File "", line 1, in TypeError: 'set' object does not support indexing >>> ``` ### set add() and update() Using the `add()` method we can add a single element to the set. ```python >>> s = {1, 2, 3} >>> s.add(4) >>> s {1, 2, 3, 4} ``` And with `update()`, multiple ones . ```python >>> s = {1, 2, 3} >>> s.update([2, 3, 4, 5, 6]) >>> s {1, 2, 3, 4, 5, 6} # remember, sets automatically remove duplicates ``` ### set remove() and discard() Both methods will remove an element from the set, but `remove()` will raise a `key error` if the value doesn't exist. ```python >>> s = {1, 2, 3} >>> s.remove(3) >>> s {1, 2} >>> s.remove(3) Traceback (most recent call last): File "", line 1, in KeyError: 3 ``` `discard()` won't raise any errors. ```python >>> s = {1, 2, 3} >>> s.discard(3) >>> s {1, 2} >>> s.discard(3) >>> ``` ### set union() `union()` or `|` will create a new set that contains all the elements from the sets provided. ```python >>> s1 = {1, 2, 3} >>> s2 = {3, 4, 5} >>> s1.union(s2) # or 's1 | s2' {1, 2, 3, 4, 5} ``` ### set intersection `intersection` or `&` will return a set containing only the elements that are common to all of them. ```python >>> s1 = {1, 2, 3} >>> s2 = {2, 3, 4} >>> s3 = {3, 4, 5} >>> s1.intersection(s2, s3) # or 's1 & s2 & s3' {3} ``` ### set difference `difference` or `-` will return only the elements that are in one of the sets. ```python >>> s1 = {1, 2, 3} >>> s2 = {2, 3, 4} >>> s1.difference(s2) # or 's1 - s2' {1} ``` ### set symetric_difference `symetric_difference` or `^` will return all the elements that are not common between them. ```python >>> s1 = {1, 2, 3} >>> s2 = {2, 3, 4} >>> s1.symmetric_difference(s2) # or 's1 ^ s2' {1, 4} ``` [*Return to the Top*](#python-cheatsheet) ## itertools Module The *itertools* module is a colection of tools intented to be fast and use memory efficiently when handling iterators (like [lists](#lists) or [dictionaries](#dictionaries-and-structuring-data)). From the official [Python 3.x documentation](https://docs.python.org/3/library/itertools.html): > The module standardizes a core set of fast, memory efficient tools that are useful by themselves or in combination. Together, they form an “iterator algebra” making it possible to construct specialized tools succinctly and efficiently in pure Python. The *itertools* module comes in the standard library and must be imported. The [operator](https://docs.python.org/3/library/operator.html) module will also be used. This module is not necessary when using itertools, but needed for some of the examples below. [*Return to the Top*](#python-cheatsheet) ### accumulate() Makes an iterator that returns the results of a function. ```python itertools.accumulate(iterable[, func]) ``` Example: ```python >>> data = [1, 2, 3, 4, 5] >>> result = itertools.accumulate(data, operator.mul) >>> for each in result: >>> print(each) 1 2 6 24 120 ``` The operator.mul takes two numbers and multiplies them: ```python operator.mul(1, 2) 2 operator.mul(2, 3) 6 operator.mul(6, 4) 24 operator.mul(24, 5) 120 ``` Passing a function is optional: ```python >>> data = [5, 2, 6, 4, 5, 9, 1] >>> result = itertools.accumulate(data) >>> for each in result: >>> print(each) 5 7 13 17 22 31 32 ``` If no function is designated the items will be summed: ```python 5 5 + 2 = 7 7 + 6 = 13 13 + 4 = 17 17 + 5 = 22 22 + 9 = 31 31 + 1 = 32 ``` [*Return to the Top*](#python-cheatsheet) ### combinations() Takes an iterable and a integer. This will create all the unique combination that have r members. ```python itertools.combinations(iterable, r) ``` Example: ```python >>> shapes = ['circle', 'triangle', 'square',] >>> result = itertools.combinations(shapes, 2) >>> for each in result: >>> print(each) ('circle', 'triangle') ('circle', 'square') ('triangle', 'square') ``` [*Return to the Top*](#python-cheatsheet) ### combinations_with_replacement() Just like combinations(), but allows individual elements to be repeated more than once. ```python itertools.combinations_with_replacement(iterable, r) ``` Example: ```python >>> shapes = ['circle', 'triangle', 'square'] >>> result = itertools.combinations_with_replacement(shapes, 2) >>> for each in result: >>> print(each) ('circle', 'circle') ('circle', 'triangle') ('circle', 'square') ('triangle', 'triangle') ('triangle', 'square') ('square', 'square') ``` [*Return to the Top*](#python-cheatsheet) ### count() Makes an iterator that returns evenly spaced values starting with number start. ```python itertools.count(start=0, step=1) ``` Example: ```python >>> for i in itertools.count(10,3): >>> print(i) >>> if i > 20: >>> break 10 13 16 19 22 ``` [*Return to the Top*](#python-cheatsheet) ### cycle() This function cycles through an iterator endlessly. ```python itertools.cycle(iterable) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue', 'violet'] >>> for color in itertools.cycle(colors): >>> print(color) red orange yellow green blue violet red orange ``` When reached the end of the iterable it start over again from the beginning. [*Return to the Top*](#python-cheatsheet) ### chain() Take a series of iterables and return them as one long iterable. ```python itertools.chain(*iterables) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue'] >>> shapes = ['circle', 'triangle', 'square', 'pentagon'] >>> result = itertools.chain(colors, shapes) >>> for each in result: >>> print(each) red orange yellow green blue circle triangle square pentagon ``` [*Return to the Top*](#python-cheatsheet) ### compress() Filters one iterable with another. ```python itertools.compress(data, selectors) ``` Example: ```python >>> shapes = ['circle', 'triangle', 'square', 'pentagon'] >>> selections = [True, False, True, False] >>> result = itertools.compress(shapes, selections) >>> for each in result: >>> print(each) circle square ``` [*Return to the Top*](#python-cheatsheet) ### dropwhile() Make an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every element. ```python itertools.dropwhile(predicate, iterable) ``` Example: ```python >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1] >>> result = itertools.dropwhile(lambda x: x<5, data) >>> for each in result: >>> print(each) 5 6 7 8 9 10 1 ``` [*Return to the Top*](#python-cheatsheet) ### filterfalse() Makes an iterator that filters elements from iterable returning only those for which the predicate is False. ```python itertools.filterfalse(predicate, iterable) ``` Example: ```python >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> result = itertools.filterfalse(lambda x: x<5, data) >>> for each in result: >>> print(each) 5 6 7 8 9 10 ``` [*Return to the Top*](#python-cheatsheet) ### groupby() Simply put, this function groups things together. ```python itertools.groupby(iterable, key=None) ``` Example: ```python >>> robots = [{ 'name': 'blaster', 'faction': 'autobot' }, { 'name': 'galvatron', 'faction': 'decepticon' }, { 'name': 'jazz', 'faction': 'autobot' }, { 'name': 'metroplex', 'faction': 'autobot' }, { 'name': 'megatron', 'faction': 'decepticon' }, { 'name': 'starcream', 'faction': 'decepticon' }] >>> for key, group in itertools.groupby(robots, key=lambda x: x['faction']): >>> print(key) >>> print(list(group)) autobot [{'name': 'blaster', 'faction': 'autobot'}] decepticon [{'name': 'galvatron', 'faction': 'decepticon'}] autobot [{'name': 'jazz', 'faction': 'autobot'}, {'name': 'metroplex', 'faction': 'autobot'}] decepticon [{'name': 'megatron', 'faction': 'decepticon'}, {'name': 'starcream', 'faction': 'decepticon'}] ``` [*Return to the Top*](#python-cheatsheet) ### islice() This function is very much like slices. This allows you to cut out a piece of an iterable. ```python itertools.islice(iterable, start, stop[, step]) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue',] >>> few_colors = itertools.islice(colors, 2) >>> for each in few_colors: >>> print(each) red orange ``` [*Return to the Top*](#python-cheatsheet) ### permutations() ```python itertools.permutations(iterable, r=None) ``` Example: ```python >>> alpha_data = ['a', 'b', 'c'] >>> result = itertools.permutations(alpha_data) >>> for each in result: >>> print(each) ('a', 'b', 'c') ('a', 'c', 'b') ('b', 'a', 'c') ('b', 'c', 'a') ('c', 'a', 'b') ('c', 'b', 'a') ``` [*Return to the Top*](#python-cheatsheet) ### product() Creates the cartesian products from a series of iterables. ```python >>> num_data = [1, 2, 3] >>> alpha_data = ['a', 'b', 'c'] >>> result = itertools.product(num_data, alpha_data) >>> for each in result: print(each) (1, 'a') (1, 'b') (1, 'c') (2, 'a') (2, 'b') (2, 'c') (3, 'a') (3, 'b') (3, 'c') ``` [*Return to the Top*](#python-cheatsheet) ### repeat() This function will repeat an object over and over again. Unless, there is a times argument. ```python itertools.repeat(object[, times]) ``` Example: ```python >>> for i in itertools.repeat("spam", 3): print(i) spam spam spam ``` [*Return to the Top*](#python-cheatsheet) ### starmap() Makes an iterator that computes the function using arguments obtained from the iterable. ```python itertools.starmap(function, iterable) ``` Example: ```python >>> data = [(2, 6), (8, 4), (7, 3)] >>> result = itertools.starmap(operator.mul, data) >>> for each in result: >>> print(each) 12 32 21 ``` [*Return to the Top*](#python-cheatsheet) ### takewhile() The opposite of dropwhile(). Makes an iterator and returns elements from the iterable as long as the predicate is true. ```python itertools.takwwhile(predicate, iterable) ``` Example: ```python >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1] >>> result = itertools.takewhile(lambda x: x<5, data) >>> for each in result: >>> print(each) 1 2 3 4 ``` [*Return to the Top*](#python-cheatsheet) ### tee() Return n independent iterators from a single iterable. ```python itertools.tee(iterable, n=2) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue'] >>> alpha_colors, beta_colors = itertools.tee(colors) >>> for each in alpha_colors: >>> print(each) red orange yellow green blue ``` ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue'] >>> alpha_colors, beta_colors = itertools.tee(colors) >>> for each in beta_colors: >>> print(each) red orange yellow green blue ``` [*Return to the Top*](#python-cheatsheet) ### zip_longest() Makes an iterator that aggregates elements from each of the iterables. If the iterables are of uneven length, missing values are filled-in with fillvalue. Iteration continues until the longest iterable is exhausted. ```python itertools.zip_longest(*iterables, fillvalue=None) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue',] >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,] >>> for each in itertools.zip_longest(colors, data, fillvalue=None): >>> print(each) ('red', 1) ('orange', 2) ('yellow', 3) ('green', 4) ('blue', 5) (None, 6) (None, 7) (None, 8) (None, 9) (None, 10) ``` [*Return to the Top*](#python-cheatsheet) ## Comprehensions ### List comprehension ```python >>> a = [1, 3, 5, 7, 9, 11] >>> [i - 1 for i in a] [0, 2, 4, 6, 8, 10] ``` ### Set comprehension ```python >>> b = {"abc", "def"} >>> {s.upper() for s in b} {"ABC", "DEF} ``` ### Dict comprehension ```python >>> c = {'name': 'Pooka', 'age': 5} >>> {v, k for k, v in c.items()} {'Pooka': 'name', 5: 'age'} ``` A List comprehension can be generated from a dictionary: ```python >>> c = {'name': 'Pooka', 'first_name': 'Oooka'} >>> ["{}:{}".format(k.upper(), v.upper()) for k, v in c.items()] ['NAME:POOKA', 'FIRST_NAME:OOOKA'] ``` ## Manipulating Strings ### Escape Characters | Escape character | Prints as | | ---------------- | -------------------- | | `\'` | Single quote | | `\"` | Double quote | | `\t` | Tab | | `\n` | Newline (line break) | | `\\` | Backslash | Example: ```python >>> print("Hello there!\nHow are you?\nI\'m doing fine.") Hello there! How are you? I'm doing fine. ``` [*Return to the Top*](#python-cheatsheet) ### Raw Strings A raw string completely ignores all escape characters and prints any backslash that appears in the string. ```python >>> print(r'That is Carol\'s cat.') That is Carol\'s cat. ``` Note: mostly used for regular expression definition (see `re` package) [*Return to the Top*](#python-cheatsheet) ### Multiline Strings with Triple Quotes ```python >>> print('''Dear Alice, >>> >>> Eve's cat has been arrested for catnapping, cat burglary, and extortion. >>> >>> Sincerely, >>> Bob''') Dear Alice, Eve's cat has been arrested for catnapping, cat burglary, and extortion. Sincerely, Bob ``` To keep a nicer flow in your code, you can use the `dedent` function from the `textwrap` standard package. ```python >>> from textwrap import dedent >>> >>> def my_function(): >>> print(''' >>> Dear Alice, >>> >>> Eve's cat has been arrested for catnapping, cat burglary, and extortion. >>> >>> Sincerely, >>> Bob >>> ''').strip() ``` This generates the same string than before. [*Return to the Top*](#python-cheatsheet) ### Indexing and Slicing Strings H e l l o w o r l d ! 0 1 2 3 4 5 6 7 8 9 10 11 ```python >>> spam = 'Hello world!' >>> spam[0] 'H' ``` ```python >>> spam[4] 'o' ``` ```python >>> spam[-1] '!' ``` Slicing: ```python >>> spam[0:5] 'Hello' ``` ```python >>> spam[:5] 'Hello' ``` ```python >>> spam[6:] 'world!' ``` ```python >>> spam[6:-1] 'world' ``` ```python >>> spam[:-1] 'Hello world' ``` ```python >>> spam[::-1] '!dlrow olleH' ``` ```python >>> spam = 'Hello world!' >>> fizz = spam[0:5] >>> fizz 'Hello' ``` [*Return to the Top*](#python-cheatsheet) ### The in and not in Operators with Strings ```python >>> 'Hello' in 'Hello World' True ``` ```python >>> 'Hello' in 'Hello' True ``` ```python >>> 'HELLO' in 'Hello World' False ``` ```python >>> '' in 'spam' True ``` ```python >>> 'cats' not in 'cats and dogs' False ``` ### The in and not in Operators with list ```python >>> a = [1, 2, 3, 4] >>> 5 in a False ``` ```python >>> 2 in a True ``` [*Return to the Top*](#python-cheatsheet) ### The upper(), lower(), isupper(), and islower() String Methods `upper()` and `lower()`: ```python >>> spam = 'Hello world!' >>> spam = spam.upper() >>> spam 'HELLO WORLD!' ``` ```python >>> spam = spam.lower() >>> spam 'hello world!' ``` isupper() and islower(): ```python >>> spam = 'Hello world!' >>> spam.islower() False ``` ```python >>> spam.isupper() False ``` ```python >>> 'HELLO'.isupper() True ``` ```python >>> 'abc12345'.islower() True ``` ```python >>> '12345'.islower() False ``` ```python >>> '12345'.isupper() False ``` [*Return to the Top*](#python-cheatsheet) ### The isX String Methods - **isalpha()** returns True if the string consists only of letters and is not blank. - **isalnum()** returns True if the string consists only of lettersand numbers and is not blank. - **isdecimal()** returns True if the string consists only ofnumeric characters and is not blank. - **isspace()** returns True if the string consists only of spaces,tabs, and new-lines and is not blank. - **istitle()** returns True if the string consists only of wordsthat begin with an uppercase letter followed by onlylowercase letters. [*Return to the Top*](#python-cheatsheet) ### The startswith() and endswith() String Methods ```python >>> 'Hello world!'.startswith('Hello') True ``` ```python >>> 'Hello world!'.endswith('world!') True ``` ```python >>> 'abc123'.startswith('abcdef') False ``` ```python >>> 'abc123'.endswith('12') False ``` ```python >>> 'Hello world!'.startswith('Hello world!') True ``` ```python >>> 'Hello world!'.endswith('Hello world!') True ``` [*Return to the Top*](#python-cheatsheet) ### The join() and split() String Methods join(): ```python >>> ', '.join(['cats', 'rats', 'bats']) 'cats, rats, bats' ``` ```python >>> ' '.join(['My', 'name', 'is', 'Simon']) 'My name is Simon' ``` ```python >>> 'ABC'.join(['My', 'name', 'is', 'Simon']) 'MyABCnameABCisABCSimon' ``` split(): ```python >>> 'My name is Simon'.split() ['My', 'name', 'is', 'Simon'] ``` ```python >>> 'MyABCnameABCisABCSimon'.split('ABC') ['My', 'name', 'is', 'Simon'] ``` ```python >>> 'My name is Simon'.split('m') ['My na', 'e is Si', 'on'] ``` [*Return to the Top*](#python-cheatsheet) ### Justifying Text with rjust(), ljust(), and center() rjust() and ljust(): ```python >>> 'Hello'.rjust(10) ' Hello' ``` ```python >>> 'Hello'.rjust(20) ' Hello' ``` ```python >>> 'Hello World'.rjust(20) ' Hello World' ``` ```python >>> 'Hello'.ljust(10) 'Hello ' ``` An optional second argument to rjust() and ljust() will specify a fill character other than a space character. Enter the following into the interactive shell: ```python >>> 'Hello'.rjust(20, '*') '***************Hello' ``` ```python >>> 'Hello'.ljust(20, '-') 'Hello---------------' ``` center(): ```python >>> 'Hello'.center(20) ' Hello ' ``` ```python >>> 'Hello'.center(20, '=') '=======Hello========' ``` [*Return to the Top*](#python-cheatsheet) ### Removing Whitespace with strip(), rstrip(), and lstrip() ```python >>> spam = ' Hello World ' >>> spam.strip() 'Hello World' ``` ```python >>> spam.lstrip() 'Hello World ' ``` ```python >>> spam.rstrip() ' Hello World' ``` ```python >>> spam = 'SpamSpamBaconSpamEggsSpamSpam' >>> spam.strip('ampS') 'BaconSpamEggs' ``` [*Return to the Top*](#python-cheatsheet) ### Copying and Pasting Strings with the pyperclip Module (need pip install) ```python >>> import pyperclip >>> pyperclip.copy('Hello world!') >>> pyperclip.paste() 'Hello world!' ``` [*Return to the Top*](#python-cheatsheet) ## String Formatting ### % operator ```python >>> name = 'Pete' >>> 'Hello %s' % name "Hello Pete" ``` We can use the `%x` format specifier to convert an int value to a string: ```python >>> num = 5 >>> 'I have %x apples' % num "I have 5 apples" ``` Note: For new code, using [str.format](#string-formatting-strformat) or [f-strings](#formatted-string-literals-or-f-strings-python-36) (Python 3.6+) is strongly recommended over the `%` operator. [*Return to the Top*](#python-cheatsheet) ### String Formatting (str.format) Python 3 introduced a new way to do string formatting that was later back-ported to Python 2.7. This makes the syntax for string formatting more regular. ```python >>> name = 'John' >>> age = 20' >>> "Hello I'm {}, my age is {}".format(name, age) "Hello I'm John, my age is 20" ``` ```python >>> "Hello I'm {0}, my age is {1}".format(name, age) "Hello I'm John, my age is 20" ``` The official [Python 3.x documentation](https://docs.python.org/3/library/stdtypes.html?highlight=sprintf#printf-style-string-formatting) recommend `str.format` over the `%` operator: > The formatting operations described here exhibit a variety of quirks that lead to a number of common errors (such as failing to display tuples and dictionaries correctly). Using the newer formatted string literals or the str.format() interface helps avoid these errors. These alternatives also provide more powerful, flexible and extensible approaches to formatting text. [*Return to the Top*](#python-cheatsheet) ### Lazy string formatting You would only use `%s` string formatting on functions that can do lazy parameters evaluation, the most common being logging: Prefer: ```python >>> name = "alice" >>> logging.debug("User name: %s", name) ``` Over: ```python >>> logging.debug("User name: {}".format(name)) ``` Or: ```python >>> logging.debug("User name: " + name) ``` [*Return to the Top*](#python-cheatsheet) ### Formatted String Literals or f-strings (Python 3.6+) ```python >>> name = 'Elizabeth' >>> f'Hello {name}!' 'Hello Elizabeth! ``` It is even possible to do inline arithmetic with it: ```python >>> a = 5 >>> b = 10 >>> f'Five plus ten is {a + b} and not {2 * (a + b)}.' 'Five plus ten is 15 and not 30.' ``` [*Return to the Top*](#python-cheatsheet) ### Template Strings A simpler and less powerful mechanism, but it is recommended when handling format strings generated by users. Due to their reduced complexity template strings are a safer choice. ```python >>> from string import Template >>> name = 'Elizabeth' >>> t = Template('Hey $name!') >>> t.substitute(name=name) 'Hey Elizabeth!' ``` [*Return to the Top*](#python-cheatsheet) ## Regular Expressions 1. Import the regex module with `import re`. 1. Create a Regex object with the `re.compile()` function. (Remember to use a raw string.) 1. Pass the string you want to search into the Regex object’s `search()` method. This returns a `Match` object. 1. Call the Match object’s `group()` method to return a string of the actual matched text. All the regex functions in Python are in the re module: ```python >>> import re ``` [*Return to the Top*](#python-cheatsheet) ### Matching Regex Objects ```python >>> phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d') >>> mo = phone_num_regex.search('My number is 415-555-4242.') >>> print('Phone number found: {}'.format(mo.group())) Phone number found: 415-555-4242 ``` [*Return to the Top*](#python-cheatsheet) ### Grouping with Parentheses ```python >>> phone_num_regex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)') >>> mo = phone_num_regex.search('My number is 415-555-4242.') >>> mo.group(1) '415' >>> mo.group(2) '555-4242' >>> mo.group(0) '415-555-4242' >>> mo.group() '415-555-4242' ``` To retrieve all the groups at once: use the groups() method—note the plural form for the name. ```python >>> mo.groups() ('415', '555-4242') >>> area_code, main_number = mo.groups() >>> print(area_code) 415 >>> print(main_number) 555-4242 ``` [*Return to the Top*](#python-cheatsheet) ### Matching Multiple Groups with the Pipe The | character is called a pipe. You can use it anywhere you want to match one of many expressions. For example, the regular expression r'Batman|Tina Fey' will match either 'Batman' or 'Tina Fey'. ```python >>> hero_regex = re.compile (r'Batman|Tina Fey') >>> mo1 = hero_regex.search('Batman and Tina Fey.') >>> mo1.group() 'Batman' >>> mo2 = hero_regex.search('Tina Fey and Batman.') >>> mo2.group() 'Tina Fey' ``` You can also use the pipe to match one of several patterns as part of your regex: ```python >>> bat_regex = re.compile(r'Bat(man|mobile|copter|bat)') >>> mo = bat_regex.search('Batmobile lost a wheel') >>> mo.group() 'Batmobile' >>> mo.group(1) 'mobile' ``` [*Return to the Top*](#python-cheatsheet) ### Optional Matching with the Question Mark The ? character flags the group that precedes it as an optional part of the pattern. ```python >>> bat_regex = re.compile(r'Bat(wo)?man') >>> mo1 = bat_regex.search('The Adventures of Batman') >>> mo1.group() 'Batman' >>> mo2 = bat_regex.search('The Adventures of Batwoman') >>> mo2.group() 'Batwoman' ``` [*Return to the Top*](#python-cheatsheet) ### Matching Zero or More with the Star The * (called the star or asterisk) means “match zero or more”—the group that precedes the star can occur any number of times in the text. ```python >>> bat_regex = re.compile(r'Bat(wo)*man') >>> mo1 = bat_regex.search('The Adventures of Batman') >>> mo1.group() 'Batman' >>> mo2 = bat_regex.search('The Adventures of Batwoman') >>> mo2.group() 'Batwoman' >>> mo3 = bat_regex.search('The Adventures of Batwowowowoman') >>> mo3.group() 'Batwowowowoman' ``` [*Return to the Top*](#python-cheatsheet) ### Matching One or More with the Plus While * means “match zero or more,” the + (or plus) means “match one or more”. The group preceding a plus must appear at least once. It is not optional: ```python >>> bat_regex = re.compile(r'Bat(wo)+man') >>> mo1 = bat_regex.search('The Adventures of Batwoman') >>> mo1.group() 'Batwoman' ``` ```python >>> mo2 = bat_regex.search('The Adventures of Batwowowowoman') >>> mo2.group() 'Batwowowowoman' ``` ```python >>> mo3 = bat_regex.search('The Adventures of Batman') >>> mo3 is None True ``` [*Return to the Top*](#python-cheatsheet) ### Matching Specific Repetitions with Curly Brackets If you have a group that you want to repeat a specific number of times, follow the group in your regex with a number in curly brackets. For example, the regex (Ha){3} will match the string 'HaHaHa', but it will not match 'HaHa', since the latter has only two repeats of the (Ha) group. Instead of one number, you can specify a range by writing a minimum, a comma, and a maximum in between the curly brackets. For example, the regex (Ha){3,5} will match 'HaHaHa', 'HaHaHaHa', and 'HaHaHaHaHa'. ```python >>> ha_regex = re.compile(r'(Ha){3}') >>> mo1 = ha_regex.search('HaHaHa') >>> mo1.group() 'HaHaHa' ``` ```python >>> mo2 = ha_regex.search('Ha') >>> mo2 is None True ``` [*Return to the Top*](#python-cheatsheet) ### Greedy and Nongreedy Matching Python’s regular expressions are greedy by default, which means that in ambiguous situations they will match the longest string possible. The non-greedy version of the curly brackets, which matches the shortest string possible, has the closing curly bracket followed by a question mark. ```python >>> greedy_ha_regex = re.compile(r'(Ha){3,5}') >>> mo1 = greedy_ha_regex.search('HaHaHaHaHa') >>> mo1.group() 'HaHaHaHaHa' ``` ```python >>> nongreedy_ha_regex = re.compile(r'(Ha){3,5}?') >>> mo2 = nongreedy_ha_regex.search('HaHaHaHaHa') >>> mo2.group() 'HaHaHa' ``` [*Return to the Top*](#python-cheatsheet) ### The findall() Method In addition to the search() method, Regex objects also have a findall() method. While search() will return a Match object of the first matched text in the searched string, the findall() method will return the strings of every match in the searched string. ```python >>> phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d') # has no groups >>> phone_num_regex.findall('Cell: 415-555-9999 Work: 212-555-0000') ['415-555-9999', '212-555-0000'] ``` To summarize what the findall() method returns, remember the following: - When called on a regex with no groups, such as \d-\d\d\d-\d\d\d\d, the method findall() returns a list of ng matches, such as ['415-555-9999', '212-555-0000']. - When called on a regex that has groups, such as (\d\d\d)-d\d)-(\d\ d\d\d), the method findall() returns a list of es of strings (one string for each group), such as [('415', ', '9999'), ('212', '555', '0000')]. [*Return to the Top*](#python-cheatsheet) ### Making Your Own Character Classes There are times when you want to match a set of characters but the shorthand character classes (\d, \w, \s, and so on) are too broad. You can define your own character class using square brackets. For example, the character class [aeiouAEIOU] will match any vowel, both lowercase and uppercase. ```python >>> vowel_regex = re.compile(r'[aeiouAEIOU]') >>> vowel_regex.findall('Robocop eats baby food. BABY FOOD.') ['o', 'o', 'o', 'e', 'a', 'a', 'o', 'o', 'A', 'O', 'O'] ``` You can also include ranges of letters or numbers by using a hyphen. For example, the character class [a-zA-Z0-9] will match all lowercase letters, uppercase letters, and numbers. By placing a caret character (^) just after the character class’s opening bracket, you can make a negative character class. A negative character class will match all the characters that are not in the character class. For example, enter the following into the interactive shell: ```python >>> consonant_regex = re.compile(r'[^aeiouAEIOU]') >>> consonant_regex.findall('Robocop eats baby food. BABY FOOD.') ['R', 'b', 'c', 'p', ' ', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', ' ', 'B', 'B', 'Y', ' ', 'F', 'D', '.'] ``` [*Return to the Top*](#python-cheatsheet) ### The Caret and Dollar Sign Characters - You can also use the caret symbol (^) at the start of a regex to indicate that a match must occur at the beginning of the searched text. - Likewise, you can put a dollar sign ($) at the end of the regex to indicate the string must end with this regex pattern. - And you can use the ^ and $ together to indicate that the entire string must match the regex—that is, it’s not enough for a match to be made on some subset of the string. The r'^Hello' regular expression string matches strings that begin with 'Hello': ```python >>> begins_with_hello = re.compile(r'^Hello') >>> begins_with_hello.search('Hello world!') <_sre.SRE_Match object; span=(0, 5), match='Hello'> >>> begins_with_hello.search('He said hello.') is None True ``` The r'\d$' regular expression string matches strings that end with a numeric character from 0 to 9: ```python >>> whole_string_is_num = re.compile(r'^\d+$') >>> whole_string_is_num.search('1234567890') <_sre.SRE_Match object; span=(0, 10), match='1234567890'> >>> whole_string_is_num.search('12345xyz67890') is None True >>> whole_string_is_num.search('12 34567890') is None True ``` [*Return to the Top*](#python-cheatsheet) ### The Wildcard Character The . (or dot) character in a regular expression is called a wildcard and will match any character except for a newline: ```python >>> at_regex = re.compile(r'.at') >>> at_regex.findall('The cat in the hat sat on the flat mat.') ['cat', 'hat', 'sat', 'lat', 'mat'] ``` [*Return to the Top*](#python-cheatsheet) ### Matching Everything with Dot-Star ```python >>> name_regex = re.compile(r'First Name: (.*) Last Name: (.*)') >>> mo = name_regex.search('First Name: Al Last Name: Sweigart') >>> mo.group(1) 'Al' ``` ```python >>> mo.group(2) 'Sweigart' ``` The dot-star uses greedy mode: It will always try to match as much text as possible. To match any and all text in a nongreedy fashion, use the dot, star, and question mark (.*?). The question mark tells Python to match in a nongreedy way: ```python >>> nongreedy_regex = re.compile(r'<.*?>') >>> mo = nongreedy_regex.search(' for dinner.>') >>> mo.group() '' ``` ```python >>> greedy_regex = re.compile(r'<.*>') >>> mo = greedy_regex.search(' for dinner.>') >>> mo.group() ' for dinner.>' ``` [*Return to the Top*](#python-cheatsheet) ### Matching Newlines with the Dot Character The dot-star will match everything except a newline. By passing re.DOTALL as the second argument to re.compile(), you can make the dot character match all characters, including the newline character: ```python >>> no_newline_regex = re.compile('.*') >>> no_newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group() 'Serve the public trust.' ``` ```python >>> newline_regex = re.compile('.*', re.DOTALL) >>> newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group() 'Serve the public trust.\nProtect the innocent.\nUphold the law.' ``` [*Return to the Top*](#python-cheatsheet) ### Review of Regex Symbols | Symbol | Matches | | ------------------------ | ------------------------------------------------------------ | | `?` | zero or one of the preceding group. | | `*` | zero or more of the preceding group. | | `+` | one or more of the preceding group. | | `{n}` | exactly n of the preceding group. | | `{n,}` | n or more of the preceding group. | | `{,m}` | 0 to m of the preceding group. | | `{n,m}` | at least n and at most m of the preceding p. | | `{n,m}?` or `*?` or `+?` | performs a nongreedy match of the preceding p. | | `^spam` | means the string must begin with spam. | | `spam$` | means the string must end with spam. | | `.` | any character, except newline characters. | | `\d`, `\w`, and `\s` | a digit, word, or space character, ectively. | | `\D`, `\W`, and `\S` | anything except a digit, word, or space acter, respectively. | | `[abc]` | any character between the brackets (such as a, b, ). | | `[^abc]` | any character that isn’t between the brackets. | [*Return to the Top*](#python-cheatsheet) ### Case-Insensitive Matching To make your regex case-insensitive, you can pass re.IGNORECASE or re.I as a second argument to re.compile(): ```python >>> robocop = re.compile(r'robocop', re.I) >>> robocop.search('Robocop is part man, part machine, all cop.').group() 'Robocop' ``` ```python >>> robocop.search('ROBOCOP protects the innocent.').group() 'ROBOCOP' ``` ```python >>> robocop.search('Al, why does your programming book talk about robocop so much?').group() 'robocop' ``` [*Return to the Top*](#python-cheatsheet) ### Substituting Strings with the sub() Method The sub() method for Regex objects is passed two arguments: 1. The first argument is a string to replace any matches. 1. The second is the string for the regular expression. The sub() method returns a string with the substitutions applied: ```python >>> names_regex = re.compile(r'Agent \w+') >>> names_regex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.') 'CENSORED gave the secret documents to CENSORED.' ``` Another example: ```python >>> agent_names_regex = re.compile(r'Agent (\w)\w*') >>> agent_names_regex.sub(r'\1****', 'Agent Alice told Agent Carol that Agent Eve knew Agent Bob was a double agent.') A**** told C**** that E**** knew B**** was a double agent.' ``` [*Return to the Top*](#python-cheatsheet) ### Managing Complex Regexes To tell the re.compile() function to ignore whitespace and comments inside the regular expression string, “verbose mode” can be enabled by passing the variable re.VERBOSE as the second argument to re.compile(). Now instead of a hard-to-read regular expression like this: ```python phone_regex = re.compile(r'((\d{3}|\(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4}(\s*(ext|x|ext.)\s*\d{2,5})?)') ``` you can spread the regular expression over multiple lines with comments like this: ```python phone_regex = re.compile(r'''( (\d{3}|\(\d{3}\))? # area code (\s|-|\.)? # separator \d{3} # first 3 digits (\s|-|\.) # separator \d{4} # last 4 digits (\s*(ext|x|ext.)\s*\d{2,5})? # extension )''', re.VERBOSE) ``` [*Return to the Top*](#python-cheatsheet) ## Handling File and Directory Paths There are two main modules in Python that deals with path manipulation. One is the `os.path` module and the other is the `pathlib` module. The `pathlib` module was added in Python 3.4, offering an object-oriented way to handle file system paths. [*Return to the Top*](#python-cheatsheet) ### Backslash on Windows and Forward Slash on OS X and Linux On Windows, paths are written using backslashes (\) as the separator between folder names. On Unix based operating system such as macOS, Linux, and BSDs, the forward slash (/) is used as the path separator. Joining paths can be a headache if your code needs to work on different platforms. Fortunately, Python provides easy ways to handle this. We will showcase how to deal with this with both `os.path.join` and `pathlib.Path.joinpath` Using `os.path.join` on Windows: ```python >>> import os >>> os.path.join('usr', 'bin', 'spam') 'usr\\bin\\spam' ``` And using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> print(Path('usr').joinpath('bin').joinpath('spam')) usr/bin/spam ``` `pathlib` also provides a shortcut to joinpath using the `/` operator: ```python >>> from pathlib import Path >>> print(Path('usr') / 'bin' / 'spam') usr/bin/spam ``` Notice the path separator is different between Windows and Unix based operating system, that's why you want to use one of the above methods instead of adding strings together to join paths together. Joining paths is helpful if you need to create different file paths under the same directory. Using `os.path.join` on Windows: ```python >>> my_files = ['accounts.txt', 'details.csv', 'invite.docx'] >>> for filename in my_files: >>> print(os.path.join('C:\\Users\\asweigart', filename)) C:\Users\asweigart\accounts.txt C:\Users\asweigart\details.csv C:\Users\asweigart\invite.docx ``` Using `pathlib` on \*nix: ```python >>> my_files = ['accounts.txt', 'details.csv', 'invite.docx'] >>> home = Path.home() >>> for filename in my_files: >>> print(home / filename) /home/asweigart/accounts.txt /home/asweigart/details.csv /home/asweigart/invite.docx ``` [*Return to the Top*](#python-cheatsheet) ### The Current Working Directory Using `os` on Windows: ```python >>> import os >>> os.getcwd() 'C:\\Python34' >>> os.chdir('C:\\Windows\\System32') >>> os.getcwd() 'C:\\Windows\\System32' ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> from os import chdir >>> print(Path.cwd()) /home/asweigart >>> chdir('/usr/lib/python3.6') >>> print(Path.cwd()) /usr/lib/python3.6 ``` [*Return to the Top*](#python-cheatsheet) ### Creating New Folders Using `os` on Windows: ```python >>> import os >>> os.makedirs('C:\\delicious\\walnut\\waffles') ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> cwd = Path.cwd() >>> (cwd / 'delicious' / 'walnut' / 'waffles').mkdir() Traceback (most recent call last): File "", line 1, in File "/usr/lib/python3.6/pathlib.py", line 1226, in mkdir self._accessor.mkdir(self, mode) File "/usr/lib/python3.6/pathlib.py", line 387, in wrapped return strfunc(str(pathobj), *args) FileNotFoundError: [Errno 2] No such file or directory: '/home/asweigart/delicious/walnut/waffles' ``` Oh no, we got a nasty error! The reason is that the 'delicious' directory does not exist, so we cannot make the 'walnut' and the 'waffles' directories under it. To fix this, do: ```python >>> from pathlib import Path >>> cwd = Path.cwd() >>> (cwd / 'delicious' / 'walnut' / 'waffles').mkdir(parents=True) ``` And all is good :) [*Return to the Top*](#python-cheatsheet) ### Absolute vs. Relative Paths There are two ways to specify a file path. - An absolute path, which always begins with the root folder - A relative path, which is relative to the program’s current working directory There are also the dot (.) and dot-dot (..) folders. These are not real folders but special names that can be used in a path. A single period (“dot”) for a folder name is shorthand for “this directory.” Two periods (“dot-dot”) means “the parent folder.” [*Return to the Top*](#python-cheatsheet) ### Handling Absolute and Relative Paths To see if a path is an absolute path: Using `os.path` on \*nix: ```python >>> import os >>> os.path.isabs('/') True >>> os.path.isabs('..') False ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> Path('/').is_absolute() True >>> Path('..').is_absolute() False ``` You can extract an absolute path with both `os.path` and `pathlib` Using `os.path` on \*nix: ```python >>> import os >>> os.getcwd() '/home/asweigart' >>> os.path.abspath('..') '/home' ``` Using `pathlib` on \*nix: ```python from pathlib import Path print(Path.cwd()) /home/asweigart print(Path('..').resolve()) /home ``` You can get a relative path from a starting path to another path. Using `os.path` on \*nix: ```python >>> import os >>> os.path.relpath('/etc/passwd', '/') 'etc/passwd' ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> print(Path('/etc/passwd').relative_to('/')) etc/passwd ``` [*Return to the Top*](#python-cheatsheet) ### Checking Path Validity Checking if a file/directory exists: Using `os.path` on \*nix: ```python import os >>> os.path.exists('.') True >>> os.path.exists('setup.py') True >>> os.path.exists('/etc') True >>> os.path.exists('nonexistentfile') False ``` Using `pathlib` on \*nix: ```python from pathlib import Path >>> Path('.').exists() True >>> Path('setup.py').exists() True >>> Path('/etc').exists() True >>> Path('nonexistentfile').exists() False ``` Checking if a path is a file: Using `os.path` on \*nix: ```python >>> import os >>> os.path.isfile('setup.py') True >>> os.path.isfile('/home') False >>> os.path.isfile('nonexistentfile') False ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> Path('setup.py').is_file() True >>> Path('/home').is_file() False >>> Path('nonexistentfile').is_file() False ``` Checking if a path is a directory: Using `os.path` on \*nix: ```python >>> import os >>> os.path.isdir('/') True >>> os.path.isdir('setup.py') False >>> os.path.isdir('/spam') False ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> Path('/').is_dir() True >>> Path('setup.py').is_dir() False >>> Path('/spam').is_dir() False ``` [*Return to the Top*](#python-cheatsheet) ### Finding File Sizes and Folder Contents Getting a file's size in bytes: Using `os.path` on Windows: ```python >>> import os >>> os.path.getsize('C:\\Windows\\System32\\calc.exe') 776192 ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> stat = Path('/bin/python3.6').stat() >>> print(stat) # stat contains some other information about the file as well os.stat_result(st_mode=33261, st_ino=141087, st_dev=2051, st_nlink=2, st_uid=0, --snip-- st_gid=0, st_size=10024, st_atime=1517725562, st_mtime=1515119809, st_ctime=1517261276) >>> print(stat.st_size) # size in bytes 10024 ``` Listing directory contents using `os.listdir` on Windows: ```python >>> import os >>> os.listdir('C:\\Windows\\System32') ['0409', '12520437.cpx', '12520850.cpx', '5U877.ax', 'aaclient.dll', --snip-- 'xwtpdui.dll', 'xwtpw32.dll', 'zh-CN', 'zh-HK', 'zh-TW', 'zipfldr.dll'] ``` Listing directory contents using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> for f in Path('/usr/bin').iterdir(): >>> print(f) ... /usr/bin/tiff2rgba /usr/bin/iconv /usr/bin/ldd /usr/bin/cache_restore /usr/bin/udiskie /usr/bin/unix2dos /usr/bin/t1reencode /usr/bin/epstopdf /usr/bin/idle3 ... ``` To find the total size of all the files in this directory: **WARNING**: Directories themselves also have a size! So you might want to check for whether a path is a file or directory using the methods in the methods discussed in the above section! Using `os.path.getsize()` and `os.listdir()` together on Windows: ```python >>> import os >>> total_size = 0 >>> for filename in os.listdir('C:\\Windows\\System32'): total_size = total_size + os.path.getsize(os.path.join('C:\\Windows\\System32', filename)) >>> print(total_size) 1117846456 ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> total_size = 0 >>> for sub_path in Path('/usr/bin').iterdir(): ... total_size += sub_path.stat().st_size >>> >>> print(total_size) 1903178911 ``` [*Return to the Top*](#python-cheatsheet) ### Copying Files and Folders The shutil module provides functions for copying files, as well as entire folders. ```python >>> import shutil, os >>> os.chdir('C:\\') >>> shutil.copy('C:\\spam.txt', 'C:\\delicious') 'C:\\delicious\\spam.txt' >>> shutil.copy('eggs.txt', 'C:\\delicious\\eggs2.txt') 'C:\\delicious\\eggs2.txt' ``` While shutil.copy() will copy a single file, shutil.copytree() will copy an entire folder and every folder and file contained in it: ```python >>> import shutil, os >>> os.chdir('C:\\') >>> shutil.copytree('C:\\bacon', 'C:\\bacon_backup') 'C:\\bacon_backup' ``` [*Return to the Top*](#python-cheatsheet) ### Moving and Renaming Files and Folders ```python >>> import shutil >>> shutil.move('C:\\bacon.txt', 'C:\\eggs') 'C:\\eggs\\bacon.txt' ``` The destination path can also specify a filename. In the following example, the source file is moved and renamed: ```python >>> shutil.move('C:\\bacon.txt', 'C:\\eggs\\new_bacon.txt') 'C:\\eggs\\new_bacon.txt' ``` If there is no eggs folder, then move() will rename bacon.txt to a file named eggs. ```python >>> shutil.move('C:\\bacon.txt', 'C:\\eggs') 'C:\\eggs' ``` [*Return to the Top*](#python-cheatsheet) ### Permanently Deleting Files and Folders - Calling os.unlink(path) or Path.unlink() will delete the file at path. - Calling os.rmdir(path) or Path.rmdir() will delete the folder at path. This folder must be empty of any files or folders. - Calling shutil.rmtree(path) will remove the folder at path, and all files and folders it contains will also be deleted. [*Return to the Top*](#python-cheatsheet) ### Safe Deletes with the send2trash Module You can install this module by running pip install send2trash from a Terminal window. ```python >>> import send2trash >>> with open('bacon.txt', 'a') as bacon_file: # creates the file ... bacon_file.write('Bacon is not a vegetable.') 25 >>> send2trash.send2trash('bacon.txt') ``` [*Return to the Top*](#python-cheatsheet) ### Walking a Directory Tree ```python >>> import os >>> >>> for folder_name, subfolders, filenames in os.walk('C:\\delicious'): >>> print('The current folder is {}'.format(folder_name)) >>> >>> for subfolder in subfolders: >>> print('SUBFOLDER OF {}: {}'.format(folder_name, subfolder)) >>> for filename in filenames: >>> print('FILE INSIDE {}: {}'.format(folder_name, filename)) >>> >>> print('') The current folder is C:\delicious SUBFOLDER OF C:\delicious: cats SUBFOLDER OF C:\delicious: walnut FILE INSIDE C:\delicious: spam.txt The current folder is C:\delicious\cats FILE INSIDE C:\delicious\cats: catnames.txt FILE INSIDE C:\delicious\cats: zophie.jpg The current folder is C:\delicious\walnut SUBFOLDER OF C:\delicious\walnut: waffles The current folder is C:\delicious\walnut\waffles FILE INSIDE C:\delicious\walnut\waffles: butter.txt ``` [*Return to the Top*](#python-cheatsheet) `pathlib` provides a lot more functionality than the ones listed above, like getting file name, getting file extension, reading/writing a file without manually opening it, etc. Check out the [official documentation](https://docs.python.org/3/library/pathlib.html) if you want to know more! ## Reading and Writing Files ### The File Reading/Writing Process To read/write to a file in Python, you will want to use the `with` statement, which will close the file for you after you are done. [*Return to the Top*](#python-cheatsheet) ### Opening and reading files with the open() function ```python >>> with open('C:\\Users\\your_home_folder\\hello.txt') as hello_file: ... hello_content = hello_file.read() >>> hello_content 'Hello World!' >>> # Alternatively, you can use the *readlines()* method to get a list of string values from the file, one string for each line of text: >>> with open('sonnet29.txt') as sonnet_file: ... sonnet_file.readlines() [When, in disgrace with fortune and men's eyes,\n', ' I all alone beweep my outcast state,\n', And trouble deaf heaven with my bootless cries,\n', And look upon myself and curse my fate,'] >>> # You can also iterate through the file line by line: >>> with open('sonnet29.txt') as sonnet_file: ... for line in sonnet_file: # note the new line character will be included in the line ... print(line, end='') When, in disgrace with fortune and men's eyes, I all alone beweep my outcast state, And trouble deaf heaven with my bootless cries, And look upon myself and curse my fate, ``` [*Return to the Top*](#python-cheatsheet) ### Writing to Files ```python >>> with open('bacon.txt', 'w') as bacon_file: ... bacon_file.write('Hello world!\n') 13 >>> with open('bacon.txt', 'a') as bacon_file: ... bacon_file.write('Bacon is not a vegetable.') 25 >>> with open('bacon.txt') as bacon_file: ... content = bacon_file.read() >>> print(content) Hello world! Bacon is not a vegetable. ``` [*Return to the Top*](#python-cheatsheet) ### Saving Variables with the shelve Module To save variables: ```python >>> import shelve >>> cats = ['Zophie', 'Pooka', 'Simon'] >>> with shelve.open('mydata') as shelf_file: ... shelf_file['cats'] = cats ``` To open and read variables: ```python >>> with shelve.open('mydata') as shelf_file: ... print(type(shelf_file)) ... print(shelf_file['cats']) ['Zophie', 'Pooka', 'Simon'] ``` Just like dictionaries, shelf values have keys() and values() methods that will return list-like values of the keys and values in the shelf. Since these methods return list-like values instead of true lists, you should pass them to the list() function to get them in list form. ```python >>> with shelve.open('mydata') as shelf_file: ... print(list(shelf_file.keys())) ... print(list(shelf_file.values())) ['cats'] [['Zophie', 'Pooka', 'Simon']] ``` [*Return to the Top*](#python-cheatsheet) ### Saving Variables with the pprint.pformat() Function ```python >>> import pprint >>> cats = [{'name': 'Zophie', 'desc': 'chubby'}, {'name': 'Pooka', 'desc': 'fluffy'}] >>> pprint.pformat(cats) "[{'desc': 'chubby', 'name': 'Zophie'}, {'desc': 'fluffy', 'name': 'Pooka'}]" >>> with open('myCats.py', 'w') as file_obj: ... file_obj.write('cats = {}\n'.format(pprint.pformat(cats))) 83 ``` [*Return to the Top*](#python-cheatsheet) ### Reading ZIP Files ```python >>> import zipfile, os >>> os.chdir('C:\\') # move to the folder with example.zip >>> with zipfile.ZipFile('example.zip') as example_zip: ... print(example_zip.namelist()) ... spam_info = example_zip.getinfo('spam.txt') ... print(spam_info.file_size) ... print(spam_info.compress_size) ... print('Compressed file is %sx smaller!' % (round(spam_info.file_size / spam_info.compress_size, 2))) ['spam.txt', 'cats/', 'cats/catnames.txt', 'cats/zophie.jpg'] 13908 3828 'Compressed file is 3.63x smaller!' ``` [*Return to the Top*](#python-cheatsheet) ### Extracting from ZIP Files The extractall() method for ZipFile objects extracts all the files and folders from a ZIP file into the current working directory. ```python >>> import zipfile, os >>> os.chdir('C:\\') # move to the folder with example.zip >>> with zipfile.ZipFile('example.zip') as example_zip: ... example_zip.extractall() ``` The extract() method for ZipFile objects will extract a single file from the ZIP file. Continue the interactive shell example: ```python >>> with zipfile.ZipFile('example.zip') as example_zip: ... print(example_zip.extract('spam.txt')) ... print(example_zip.extract('spam.txt', 'C:\\some\\new\\folders')) 'C:\\spam.txt' 'C:\\some\\new\\folders\\spam.txt' ``` [*Return to the Top*](#python-cheatsheet) ### Creating and Adding to ZIP Files ```python >>> import zipfile >>> with zipfile.ZipFile('new.zip', 'w') as new_zip: ... new_zip.write('spam.txt', compress_type=zipfile.ZIP_DEFLATED) ``` This code will create a new ZIP file named new.zip that has the compressed contents of spam.txt. [*Return to the Top*](#python-cheatsheet) ## JSON, YAML and configuration files ### JSON Open a JSON file with: ```python import json with open("filename.json", "r") as f: content = json.loads(f.read()) ``` Write a JSON file with: ```python import json content = {"name": "Joe", "age": 20} with open("filename.json", "w") as f: f.write(json.dumps(content, indent=2)) ``` [*Return to the Top*](#python-cheatsheet) ### YAML Compared to JSON, YAML allows a much better humain maintainance and gives ability to add comments. It is a convinient choice for configuration files where human will have to edit. There are two main librairies allowing to access to YAML files: - [PyYaml](https://pypi.python.org/pypi/PyYAML) - [Ruamel.yaml](https://pypi.python.org/pypi/ruamel.yaml) Install them using `pip install` in your virtual environment. The first one it easier to use but the second one, Ruamel, implements much better the YAML specification, and allow for example to modify a YAML content without altering comments. Open a YAML file with: ```python from ruamel.yaml import YAML with open("filename.yaml") as f: yaml=YAML() yaml.load(f) ``` [*Return to the Top*](#python-cheatsheet) ### Anyconfig [Anyconfig](https://pypi.python.org/pypi/anyconfig) is a very handy package allowing to abstract completly the underlying configuration file format. It allows to load a Python dictionary from JSON, YAML, TOML, and so on. Install it with: ```bash pip install anyconfig ``` Usage: ```python import anyconfig conf1 = anyconfig.load("/path/to/foo/conf.d/a.yml") ``` [*Return to the Top*](#python-cheatsheet) ## Debugging ### Raising Exceptions Exceptions are raised with a raise statement. In code, a raise statement consists of the following: - The raise keyword - A call to the Exception() function - A string with a helpful error message passed to the Exception() function ```python >>> raise Exception('This is the error message.') Traceback (most recent call last): File "", line 1, in raise Exception('This is the error message.') Exception: This is the error message. ``` Often it’s the code that calls the function, not the function itself, that knows how to handle an expection. So you will commonly see a raise statement inside a function and the try and except statements in the code calling the function. ```python def box_print(symbol, width, height): if len(symbol) != 1: raise Exception('Symbol must be a single character string.') if width <= 2: raise Exception('Width must be greater than 2.') if height <= 2: raise Exception('Height must be greater than 2.') print(symbol * width) for i in range(height - 2): print(symbol + (' ' * (width - 2)) + symbol) print(symbol * width) for sym, w, h in (('*', 4, 4), ('O', 20, 5), ('x', 1, 3), ('ZZ', 3, 3)): try: box_print(sym, w, h) except Exception as err: print('An exception happened: ' + str(err)) ``` [*Return to the Top*](#python-cheatsheet) ### Getting the Traceback as a String The traceback is displayed by Python whenever a raised exception goes unhandled. But can also obtain it as a string by calling traceback.format_exc(). This function is useful if you want the information from an exception’s traceback but also want an except statement to gracefully handle the exception. You will need to import Python’s traceback module before calling this function. ```python >>> import traceback >>> try: >>> raise Exception('This is the error message.') >>> except: >>> with open('errorInfo.txt', 'w') as error_file: >>> error_file.write(traceback.format_exc()) >>> print('The traceback info was written to errorInfo.txt.') 116 The traceback info was written to errorInfo.txt. ``` The 116 is the return value from the write() method, since 116 characters were written to the file. The traceback text was written to errorInfo.txt. Traceback (most recent call last): File "", line 2, in Exception: This is the error message. [*Return to the Top*](#python-cheatsheet) ### Assertions An assertion is a sanity check to make sure your code isn’t doing something obviously wrong. These sanity checks are performed by assert statements. If the sanity check fails, then an AssertionError exception is raised. In code, an assert statement consists of the following: - The assert keyword - A condition (that is, an expression that evaluates to True or False) - A comma - A string to display when the condition is False ```python >>> pod_bay_door_status = 'open' >>> assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' >>> pod_bay_door_status = 'I\'m sorry, Dave. I\'m afraid I can\'t do that.' >>> assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' Traceback (most recent call last): File "", line 1, in assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' AssertionError: The pod bay doors need to be "open". ``` In plain English, an assert statement says, “I assert that this condition holds true, and if not, there is a bug somewhere in the program.” Unlike exceptions, your code should not handle assert statements with try and except; if an assert fails, your program should crash. By failing fast like this, you shorten the time between the original cause of the bug and when you first notice the bug. This will reduce the amount of code you will have to check before finding the code that’s causing the bug. Disabling Assertions Assertions can be disabled by passing the -O option when running Python. [*Return to the Top*](#python-cheatsheet) ### Logging To enable the logging module to display log messages on your screen as your program runs, copy the following to the top of your program (but under the #! python shebang line): ```python import logging logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s- %(message)s') ``` Say you wrote a function to calculate the factorial of a number. In mathematics, factorial 4 is 1 × 2 × 3 × 4, or 24. Factorial 7 is 1 × 2 × 3 × 4 × 5 × 6 × 7, or 5,040. Open a new file editor window and enter the following code. It has a bug in it, but you will also enter several log messages to help yourself figure out what is going wrong. Save the program as factorialLog.py. ```python >>> import logging >>> >>> logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s- %(message)s') >>> >>> logging.debug('Start of program') >>> >>> def factorial(n): >>> >>> logging.debug('Start of factorial(%s)' % (n)) >>> total = 1 >>> >>> for i in range(1, n + 1): >>> total *= i >>> logging.debug('i is ' + str(i) + ', total is ' + str(total)) >>> >>> logging.debug('End of factorial(%s)' % (n)) >>> >>> return total >>> >>> print(factorial(5)) >>> logging.debug('End of program') 2015-05-23 16:20:12,664 - DEBUG - Start of program 2015-05-23 16:20:12,664 - DEBUG - Start of factorial(5) 2015-05-23 16:20:12,665 - DEBUG - i is 0, total is 0 2015-05-23 16:20:12,668 - DEBUG - i is 1, total is 0 2015-05-23 16:20:12,670 - DEBUG - i is 2, total is 0 2015-05-23 16:20:12,673 - DEBUG - i is 3, total is 0 2015-05-23 16:20:12,675 - DEBUG - i is 4, total is 0 2015-05-23 16:20:12,678 - DEBUG - i is 5, total is 0 2015-05-23 16:20:12,680 - DEBUG - End of factorial(5) 0 2015-05-23 16:20:12,684 - DEBUG - End of program ``` [*Return to the Top*](#python-cheatsheet) ### Logging Levels Logging levels provide a way to categorize your log messages by importance. There are five logging levels, described in Table 10-1 from least to most important. Messages can be logged at each level using a different logging function. | Level | Logging Function | Description | | ---------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `DEBUG` | `logging.debug()` | The lowest level. Used for small details. Usually you care about these messages only when diagnosing problems. | | `INFO` | `logging.info()` | Used to record information on general events in your program or confirm that things are working at their point in the program. | | `WARNING` | `logging.warning()` | Used to indicate a potential problem that doesn’t prevent the program from working but might do so in the future. | | `ERROR` | `logging.error()` | Used to record an error that caused the program to fail to do something. | | `CRITICAL` | `logging.critical()` | The highest level. Used to indicate a fatal error that has caused or is about to cause the program to stop running entirely. | [*Return to the Top*](#python-cheatsheet) ### Disabling Logging After you’ve debugged your program, you probably don’t want all these log messages cluttering the screen. The logging.disable() function disables these so that you don’t have to go into your program and remove all the logging calls by hand. ```python >>> import logging >>> logging.basicConfig(level=logging.INFO, format=' %(asctime)s -%(levelname)s - %(message)s') >>> logging.critical('Critical error! Critical error!') 2015-05-22 11:10:48,054 - CRITICAL - Critical error! Critical error! >>> logging.disable(logging.CRITICAL) >>> logging.critical('Critical error! Critical error!') >>> logging.error('Error! Error!') ``` [*Return to the Top*](#python-cheatsheet) ### Logging to a File Instead of displaying the log messages to the screen, you can write them to a text file. The logging.basicConfig() function takes a filename keyword argument, like so: ```python import logging logging.basicConfig(filename='myProgramLog.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') ``` [*Return to the Top*](#python-cheatsheet) ## Lambda Functions This function: ```python >>> def add(x, y): return x + y >>> add(5, 3) 8 ``` Is equivalent to the *lambda* function: ```python >>> add = lambda x, y: x + y >>> add(5, 3) 8 ``` It's not even need to bind it to a name like add before: ```python >>> (lambda x, y: x + y)(5, 3) 8 ``` Like regular nested functions, lambdas also work as lexical closures: ```python >>> def make_adder(n): return lambda x: x + n >>> plus_3 = make_adder(3) >>> plus_5 = make_adder(5) >>> plus_3(4) 7 >>> plus_5(4) 9 ``` Note: lambda can only evaluate an expression, like a single line of code. [*Return to the Top*](#python-cheatsheet) ## Ternary Conditional Operator Many programming languages have a ternary operator, which define a conditional expression. The most common usage is to make a terse simple conditional assignment statement. In other words, it offers one-line code to evaluate the first expression if the condition is true, otherwise it evaluates the second expression. if else Example: ```python >>> age = 15 >>> print('kid' if age < 18 else 'adult') kid ``` Ternary operators can be changed: ```python >>> age = 15 >>> print('kid' if age < 13 else 'teenager' if age < 18 else 'adult') teenager ``` The code above is equivalent to: ```python if age < 18: if age < 12: print('kid') else: print('teenager') else: print('adult') ``` [*Return to the Top*](#python-cheatsheet) ## args and kwargs The names ```args and kwargs``` are arbitrary - the important thing are the ```*``` and ```**``` operators. They can mean: 1. In a function declaration, ```*``` means “pack all remaining positional arguments into a tuple named ``”, while ```**``` is the same for keyword arguments (except it uses a dictionary, not a tuple). 2. In a function call, ```*``` means “unpack tuple or list named `` to positional arguments at this position”, while ```**``` is the same for keyword arguments. For example you can make a function that you can use to call any other function, no matter what parameters it has: ```python def forward(f, *args, **kwargs): return f(*args, **kwargs) ``` Inside forward, args is a tuple (of all positional arguments except the first one, because we specified it - the f), kwargs is a dict. Then we call f and unpack them so they become normal arguments to f. You use ```*args``` when you have an indefinite amount of positional arguments. ```python >>> def fruits(*args): >>> for fruit in args: >>> print(fruit) >>> fruits("apples", "bananas", "grapes") "apples" "bananas" "grapes" ``` Similarly, you use ```**kwargs``` when you have an indefinite number of keyword arguments. ```python >>> def fruit(**kwargs): >>> for key, value in kwargs.items(): >>> print("{0}: {1}".format(key, value)) >>> fruit(name = "apple", color = "red") name: apple color: red ``` ```python >>> def show(arg1, arg2, *args, kwarg1=None, kwarg2=None, **kwargs): >>> print(arg1) >>> print(arg2) >>> print(args) >>> print(kwarg1) >>> print(kwarg2) >>> print(kwargs) >>> data1 = [1,2,3] >>> data2 = [4,5,6] >>> data3 = {'a':7,'b':8,'c':9} >>> show(*data1,*data2, kwarg1="python",kwarg2="cheatsheet",**data3) 1 2 (3, 4, 5, 6) python cheatsheet {'a': 7, 'b': 8, 'c': 9} >>> show(*data1, *data2, **data3) 1 2 (3, 4, 5, 6) None None {'a': 7, 'b': 8, 'c': 9} # If you do not specify ** for kwargs >>> show(*data1, *data2, *data3) 1 2 (3, 4, 5, 6, "a", "b", "c") None None {} ``` ### Thinks to Remember(args) 1. Functions can accept a variable number of positional arguments by using ```*args``` in the def statement. 2. You can use the items from a sequence as the positional arguments for a function with the ```*``` operator. 3. Using the ```*``` operator with a generator may cause your program to run out of memory and crash. 4. Adding new positional parameters to functions that accept ```*args``` can introduce hard-to-find bugs. ### Thinks to remember(kwargs) 1. Function arguments can be specified by position or by keyword. 2. Keywords make it clear what the purpose of each argument is when it would be confusing with only positional arguments. 3. Keyword arguments with default values make it easy to add new behaviors to a function, especially when the function has existing callers. 4. Optional keyword arguments should always be passed by keyword instead of by position. [*Return to the Top*](#python-cheatsheet) ## Context Manager While Python's context managers are widely used, few understand the purpose behind their use. These statements, commonly used with reading and writing files, assist the application in conserving system memory and improve resource management by ensuring specific resources are only in use for certain processes. ### with statement A context manager is an object that is notified when a context (a block of code) starts and ends. You commonly use one with the with statement. It takes care of the notifying. For example, file objects are context managers. When a context ends, the file object is closed automatically: ```python >>> with open(filename) as f: >>> file_contents = f.read() # the open_file object has automatically been closed. ``` Anything that ends execution of the block causes the context manager's exit method to be called. This includes exceptions, and can be useful when an error causes you to prematurely exit from an open file or connection. Exiting a script without properly closing files/connections is a bad idea, that may cause data loss or other problems. By using a context manager you can ensure that precautions are always taken to prevent damage or loss in this way. ### Writing your own contextmanager using generator syntax It is also possible to write a context manager using generator syntax thanks to the ```contextlib.contextmanager``` decorator: ```python >>> import contextlib >>> @contextlib.contextmanager ... def context_manager(num): ... print('Enter') ... yield num + 1 ... print('Exit') >>> with context_manager(2) as cm: ... # the following instructions are run when the 'yield' point of the context ... # manager is reached. ... # 'cm' will have the value that was yielded ... print('Right in the middle with cm = {}'.format(cm)) Enter Right in the middle with cm = 3 Exit >>> ``` [*Return to the Top*](#python-cheatsheet) ## `__main__` Top-level script environment `__main__` is the name of the scope in which top-level code executes. A module’s __name__ is set equal to `__main__` when read from standard input, a script, or from an interactive prompt. A module can discover whether or not it is running in the main scope by checking its own `__name__`, which allows a common idiom for conditionally executing code in a module when it is run as a script or with `python -m` but not when it is imported: ```python >>> if __name__ == "__main__": ... # execute only if run as a script ... main() ``` For a package, the same effect can be achieved by including a __main__.py module, the contents of which will be executed when the module is run with -m For example we are developing script which is designed to be used as module, we should do: ```python >>> # Python program to execute function directly >>> def add(a, b): ... return a+b ... >>> add(10, 20) # we can test it by calling the function save it as calculate.py 30 >>> # Now if we want to use that module by importing we have to comment out our call, >>> # Instead we can write like this in calculate.py >>> if __name__ == "__main__": ... add(3, 5) ... >>> import calculate >>> calculate.add(3, 5) 8 ``` ### Advantages 1. Every Python module has it’s `__name__` defined and if this is `__main__`, it implies that the module is being run standalone by the user and we can do corresponding appropriate actions. 2. If you import this script as a module in another script, the __name__ is set to the name of the script/module. 3. Python files can act as either reusable modules, or as standalone programs. 4. if `__name__ == “main”:` is used to execute some code only if the file was run directly, and not imported. [*Return to the Top*](#python-cheatsheet) ## setup.py The setup script is the centre of all activity in building, distributing, and installing modules using the Distutils. The main purpose of the setup script is to describe your module distribution to the Distutils, so that the various commands that operate on your modules do the right thing. The `setup.py` file is at the heart of a Python project. It describes all of the metadata about your project. There a quite a few fields you can add to a project to give it a rich set of metadata describing the project. However, there are only three required fields: name, version, and packages. The name field must be unique if you wish to publish your package on the Python Package Index (PyPI). The version field keeps track of different releases of the project. The packages field describes where you’ve put the Python source code within your project. This allows you to easily install Python packages. Often it's enough to write: ```bash python setup.py install ``` and module will install itself. Our initial setup.py will also include information about the license and will re-use the README.txt file for the long_description field. This will look like: ```python >>> from distutils.core import setup >>> setup( ... name='pythonCheatsheet', ... version='0.1', ... packages=['pipenv',], ... license='MIT', ... long_description=open('README.txt').read(), ... ) ``` Find more information visit [http://docs.python.org/install/index.html](http://docs.python.org/install/index.html). [*Return to the Top*](#python-cheatsheet) ## Dataclasses `Dataclasses` are python classes but are suited for storing data objects. This module provides a decorator and functions for automatically adding generated special methods such as `__init__()` and `__repr__()` to user-defined classes. ### Features 1. They store data and represent a certain data type. Ex: A number. For people familiar with ORMs, a model instance is a data object. It represents a specific kind of entity. It holds attributes that define or represent the entity. 2. They can be compared to other objects of the same type. Ex: A number can be greater than, less than, or equal to another number. Python 3.7 provides a decorator dataclass that is used to convert a class into a dataclass. python 2.7 ```python >>> class Number: ... def __init__(self, val): ... self.val = val ... >>> obj = Number(2) >>> obj.val 2 ``` with dataclass ```python >>> @dataclass ... class Number: ... val: int ... >>> obj = Number(2) >>> obj.val 2 ``` [*Return to the Top*](#python-cheatsheet) ### Default values It is easy to add default values to the fields of your data class. ```python >>> @dataclass ... class Product: ... name: str ... count: int = 0 ... price: float = 0.0 ... >>> obj = Product("Python") >>> obj.name Python >>> obj.count 0 >>> obj.price 0.0 ``` ### Type hints It is mandatory to define the data type in dataclass. However, If you don't want specify the datatype then, use ```typing.Any```. ```python >>> from dataclasses import dataclass >>> from typing import Any >>> @dataclass ... class WithoutExplicitTypes: ... name: Any ... value: Any = 42 ... ``` [*Return to the Top*](#python-cheatsheet) ## Virtual Environment The use of a Virtual Environment is to test python code in encapsulated environments and to also avoid filling the base Python installation with libraries we might use for only one project. [*Return to the Top*](#python-cheatsheet) ### virtualenv 1. Install virtualenv pip install virtualenv 1. Install virtualenvwrapper-win (Windows) pip install virtualenvwrapper-win Usage: 1. Make a Virtual Environment mkvirtualenv HelloWold Anything we install now will be specific to this project. And available to the projects we connect to this environment. 1. Set Project Directory To bind our virtualenv with our current working directory we simply enter: setprojectdir . 1. Deactivate To move onto something else in the command line type ‘deactivate’ to deactivate your environment. deactivate Notice how the parenthesis disappear. 1. Workon Open up the command prompt and type ‘workon HelloWold’ to activate the environment and move into your root project folder workon HelloWold [*Return to the Top*](#python-cheatsheet) ### pipenv > [Pipenv](https://pipenv.readthedocs.io/en/latest/) is a tool that aims to bring the best of all packaging worlds (bundler, composer, npm, cargo, yarn, etc.) to the Python world. Windows is a first-class citizen, in our world. 1. Install pipenv pip install pipenv 1. Enter your Project directory and install the Packages for your project cd my_project pipenv install Pipenv will install your package and create a Pipfile for you in your project’s directory. The Pipfile is used to track which dependencies your project needs in case you need to re-install them. 1. Uninstall Packages pipenv uninstall 1. Activate the Virtual Environment associated with your Python project pipenv shell 1. Exit the Virtual Environment exit Find more information and a video in [docs.pipenv.org](https://docs.pipenv.org/). [*Return to the Top*](#python-cheatsheet) ### anaconda [Anaconda](https://anaconda.org/) is another popular tool to manage python packages. > Where packages, notebooks, projects and environments are shared. Your place for free public conda package hosting. Usage: 1. Make a Virtual Environment conda create -n HelloWorld 2. To use the Virtual Environment, activate it by: conda activate HelloWorld Anything installed now will be specific to the project HelloWorld 3. Exit the Virtual Environment conda deactivate [*Return to the Top*](#python-cheatsheet) ================================================ FILE: Python/_config.yml ================================================ theme: jekyll-theme-cayman ================================================ FILE: Python/blog_files/about.md ================================================ ## About Python Cheat Sheet This is a basic [cheatsheet](https://www.pythoncheatsheet.org) for Python mostly based on the book written by Al Sweigart, [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/) under the [Creative Commons license](https://creativecommons.org/licenses/by-nc-sa/3.0/) and many other sources. > Anyone can forget how to make [character classes for a regex](https://www.pythoncheatsheet.org/index#Making-Your-Own-Character-Classes), [slice a list](https://www.pythoncheatsheet.org/index#Getting-Sublists-with-Slices) or do a [for loop](https://www.pythoncheatsheet.org/index#Using-for-Loops-with-Lists). This cheatsheet tries to provide a basic reference for beginner and advanced developers, lower the entry barrier for newcomers and help veterans refresh the old tricks. ## About the Website Build with the [Flask](http://flask.pocoo.org/) microframework, this website provides a simple managment system with the following features: ### Features - Blog system powered by SqlAlchemy - Articles and Static pages can render Markdown, HTML or both. - Uses a lightweight comments widget built on GitHub issues: [Utterances](https://github.com/utterance/utterances). - Tags. - Users roles. - Custom Profiles for users. - Quick search for static pages. - Elasticsearch integration. - Users Managment (create, edit, delete). - Articles Managment (create, edit, delete). - Licensed [MIT](https://github.com/wilfredinni/pysheetBlog/blob/master/LICENSE). In the frontend is [Bulma](https://github.com/jgthms/bulma), a great and easy to use CSS framework along with some vanilla Javascript. ![flask](https://raw.githubusercontent.com/wilfredinni/pysheetBlog/master/img/new_post.png) For more information visit the [Project Page](https://github.com/wilfredinni/pysheetBlog). ================================================ FILE: Python/blog_files/pysheet.md ================================================ ## The Zen of Python From the [PEP 20 -- The Zen of Python](https://www.python.org/dev/peps/pep-0020/): > Long time Pythoneer Tim Peters succinctly channels the BDFL's guiding principles for Python's design into 20 aphorisms, only 19 of which have been written down. ```python >>> import this The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those! ``` ## Python Basics ### Math Operators From **Highest** to **Lowest** precedence: | Operators | Operation | Example | | --------- | ---------------- | --------------- | | ** | Exponent | `2 ** 3 = 8` | | % | Modulus/Remaider | `22 % 8 = 6` | | // | Integer division | `22 // 8 = 2` | | / | Division | `22 / 8 = 2.75` | | * | Multiplication | `3 * 3 = 9` | | - | Subtraction | `5 - 2 = 3` | | + | Addition | `2 + 2 = 4` | Examples of expressions in the interactive shell: ```python >>> 2 + 3 * 6 20 ``` ```python >>> (2 + 3) * 6 30 ``` ```python >>> 2 ** 8 256 ``` ```python >>> 23 // 7 3 ``` ```python >>> 23 % 7 2 ``` ```python >>> (5 - 1) * ((7 + 1) / (3 - 1)) 16.0 ``` ### Data Types | Data Type | Examples | | ---------------------- | ----------------------------------------- | | Integers | `-2, -1, 0, 1, 2, 3, 4, 5` | | Floating-point numbers | `-1.25, -1.0, --0.5, 0.0, 0.5, 1.0, 1.25` | | Strings | `'a', 'aa', 'aaa', 'Hello!', '11 cats'` | ### String Concatenation and Replication String concatenation: ```python >>> 'Alice' 'Bob' 'AliceBob' ``` Note: Avoid `+` operator for string concatenation. Prefer string formatting. String Replication: ```python >>> 'Alice' * 5 'AliceAliceAliceAliceAlice' ``` ### Variables You can name a variable anything as long as it obeys the following three rules: 1. It can be only one word. 1. It can use only letters, numbers, and the underscore (`_`) character. 1. It can’t begin with a number. 1. Variable name starting with an underscore (`_`) are considered as "unuseful`. Example: ```python >>> spam = 'Hello' >>> spam 'Hello' ``` ```python >>> _spam = 'Hello' ``` `_spam` should not be used again in the code. ### Comments Inline comment: ```python # This is a comment ``` Multiline comment: ```Python # This is a # multiline comment ``` Code with a comment: ```python a = 1 # initialization ``` Please note the two spaces in front of the comment. Function docstring: ```python def foo(): """ This is a function docstring You can also use: ''' Function Docstring ''' """ ``` ### The print Function ```python >>> print('Hello world!') Hello world! ``` ```python >>> a = 1 >>> print('Hello world!', a) Hello world! 1 ``` ### The input Function Example Code: ```python >>> print('What is your name?') # ask for their name >>> myName = input() >>> print('It is good to meet you, {}'.format(myName)) What is your name? Al It is good to meet you, Al ``` ### The len Function Evaluates to the integer value of the number of characters in a string: ```python >>> len('hello') 5 ``` Note: test of emptiness of strings, lists, dictionary, etc, should **not** use len, but prefer direct boolean evaluation. ```python >>> a = [1, 2, 3] >>> if a: >>> print("the list is not empty!") ``` ### The str, int, and float Functions Integer to String or Float: ```python >>> str(29) '29' ``` ```python >>> print('I am {} years old.'.format(str(29))) I am 29 years old. ``` ```python >>> str(-3.14) '-3.14' ``` Float to Integer: ```python >>> int(7.7) 7 ``` ```python >>> int(7.7) + 1 8 ``` ## Flow Control ### Comparison Operators | Operator | Meaning | | -------- | ------------------------ | | `==` | Equal to | | `!=` | Not equal to | | `<` | Less than | | `>` | Greater Than | | `<=` | Less than or Equal to | | `>=` | Greater than or Equal to | These operators evaluate to True or False depending on the values you give them. Examples: ```python >>> 42 == 42 True ``` ```python >>> 40 == 42 False ``` ```python >>> 'hello' == 'hello' True ``` ```python >>> 'hello' == 'Hello' False ``` ```python >>> 'dog' != 'cat' True ``` ```python >>> 42 == 42.0 True ``` ```python >>> 42 == '42' False ``` ### Boolean evaluation Never use `==` or `!=` operator to evaluate boolean operation. Use the `is` or `is not` operators, or use implicit boolean evaluation. NO (even if they are valid Python): ```python >>> True == True True ``` ```python >>> True != False True ``` YES (even if they are valid Python): ```python >>> True is True True ``` ```python >>> True is not False True ``` These statements are equivalent: ```Python >>> if a is True: >>> pass >>> if a is not False: >>> pass >>> if a: >>> pass ``` And these as well: ```Python >>> if a is False: >>> pass >>> if a is not True: >>> pass >>> if not a: >>> pass ``` ### Boolean Operators There are three Boolean operators: and, or, and not. The *and* Operator’s *Truth* Table: | Expression | Evaluates to | | --------------- | ------------ | | True and True | True | | True and False | False | | False and True | False | | False and False | False | The *or* Operator’s *Truth* Table: | Expression | Evaluates to | | -------------- | ------------ | | True or True | True | | True or False | True | | False or True | True | | False or False | False | The *not* Operator’s *Truth* Table: | Expression | Evaluates to | | ---------- | ------------ | | not True | False | | not False | True | ### Mixing Boolean and Comparison Operators ```python >>> (4 < 5) and (5 < 6) True ``` ```python >>> (4 < 5) and (9 < 6) False ``` ```python >>> (1 == 2) or (2 == 2) True ``` You can also use multiple Boolean operators in an expression, along with the comparison operators: ```python >>> 2 + 2 == 4 and not 2 + 2 == 5 and 2 * 2 == 2 + 2 True ``` ### if Statements ```python if name == 'Alice': print('Hi, Alice.') ``` ### else Statements ```python name = 'Bob' if name == 'Alice': print('Hi, Alice.') else: print('Hello, stranger.') ``` ### elif Statements ```python name = 'Bob' age = 5 if name == 'Alice': print('Hi, Alice.') elif age < 12: print('You are not Alice, kiddo.') ``` ```python name = 'Bob' age = 30 if name == 'Alice': print('Hi, Alice.') elif age < 12: print('You are not Alice, kiddo.') else: print('You are neither Alice nor a little kid.') ``` ### while Loop Statements ```python spam = 0 while spam < 5: print('Hello, world.') spam = spam + 1 ``` ### break Statements If the execution reaches a break statement, it immediately exits the while loop’s clause: ```python while True: print('Please type your name.') name = input() if name == 'your name': break print('Thank you!') ``` ### continue Statements When the program execution reaches a continue statement, the program execution immediately jumps back to the start of the loop. ```python while True: print('Who are you?') name = input() if name != 'Joe': continue print('Hello, Joe. What is the password? (It is a fish.)') password = input() if password == 'swordfish': break print('Access granted.') ``` ### for Loops and the range() Function ```python >>> print('My name is') >>> for i in range(5): >>> print('Jimmy Five Times ({})'.format(str(i))) My name is Jimmy Five Times (0) Jimmy Five Times (1) Jimmy Five Times (2) Jimmy Five Times (3) Jimmy Five Times (4) ``` The *range()* function can also be called with three arguments. The first two arguments will be the start and stop values, and the third will be the step argument. The step is the amount that the variable is increased by after each iteration. ```python >>> for i in range(0, 10, 2): >>> print(i) 0 2 4 6 8 ``` You can even use a negative number for the step argument to make the for loop count down instead of up. ```python >>> for i in range(5, -1, -1): >>> print(i) 5 4 3 2 1 0 ``` ### For else statement This allows to specify a statement to execute in case of the full loop has been executed. Only useful when a `break` condition can occur in the loop: ```python >>> for i in [1, 2, 3, 4, 5]: >>> if i == 3: >>> break >>> else: >>> print("only executed when no item of the list is equal to 3") ``` ### Importing Modules ```python import random for i in range(5): print(random.randint(1, 10)) ``` ```python import random, sys, os, math ``` ```python from random import *. ``` ### Ending a Program with sys.exit ```python import sys while True: print('Type exit to exit.') response = input() if response == 'exit': sys.exit() print('You typed {}.'.format(response)) ``` ## Functions ```python >>> def hello(name): >>> print('Hello {}'.format(name)) >>> >>> hello('Alice') >>> hello('Bob') Hello Alice Hello Bob ``` ### Return Values and return Statements When creating a function using the def statement, you can specify what the return value should be with a return statement. A return statement consists of the following: - The return keyword. - The value or expression that the function should return. ```python import random def getAnswer(answerNumber): if answerNumber == 1: return 'It is certain' elif answerNumber == 2: return 'It is decidedly so' elif answerNumber == 3: return 'Yes' elif answerNumber == 4: return 'Reply hazy try again' elif answerNumber == 5: return 'Ask again later' elif answerNumber == 6: return 'Concentrate and ask again' elif answerNumber == 7: return 'My reply is no' elif answerNumber == 8: return 'Outlook not so good' elif answerNumber == 9: return 'Very doubtful' r = random.randint(1, 9) fortune = getAnswer(r) print(fortune) ``` ### The None Value ```python >>> spam = print('Hello!') Hello! ``` ```python >>> spam is None True ``` Note: never compare to `None` with the `==` operator. Always use `is`. ### print Keyword Arguments ```python >>> print('Hello', end='') >>> print('World') HelloWorld ``` ```python >>> print('cats', 'dogs', 'mice') cats dogs mice ``` ```python >>> print('cats', 'dogs', 'mice', sep=',') cats,dogs,mice ``` ### Local and Global Scope - Code in the global scope cannot use any local variables. - However, a local scope can access global variables. - Code in a function’s local scope cannot use variables in any other local scope. - You can use the same name for different variables if they are in different scopes. That is, there can be a local variable named spam and a global variable also named spam. ### The global Statement If you need to modify a global variable from within a function, use the global statement: ```python >>> def spam(): >>> global eggs >>> eggs = 'spam' >>> >>> eggs = 'global' >>> spam() >>> print(eggs) spam ``` There are four rules to tell whether a variable is in a local scope or global scope: 1. If a variable is being used in the global scope (that is, outside of all functions), then it is always a global variable. 1. If there is a global statement for that variable in a function, it is a global variable. 1. Otherwise, if the variable is used in an assignment statement in the function, it is a local variable. 1. But if the variable is not used in an assignment statement, it is a global variable. ## Exception Handling ### Basic exception handling ```python >>> def spam(divideBy): >>> try: >>> return 42 / divideBy >>> except ZeroDivisionError as e: >>> print('Error: Invalid argument: {}'.format(e)) >>> >>> print(spam(2)) >>> print(spam(12)) >>> print(spam(0)) >>> print(spam(1)) 21.0 3.5 Error: Invalid argument: division by zero None 42.0 ``` ### Final code in exception handling Code inside the `finally` section is always executed, no matter if an exception has been raised or not, and even if an exception is not caught. ```python >>> def spam(divideBy): >>> try: >>> return 42 / divideBy >>> except ZeroDivisionError as e: >>> print('Error: Invalid argument: {}'.format(e)) >>> finally: >>> print("-- division finished --") >>> print(spam(12)) >>> print(spam(0)) 21.0 -- division finished -- 3.5 -- division finished -- Error: Invalid argument: division by zero -- division finished -- None -- division finished -- 42.0 -- division finished -- ``` ## Lists ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam ['cat', 'bat', 'rat', 'elephant'] ``` ### Getting Individual Values in a List with Indexes ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[0] 'cat' ``` ```python >>> spam[1] 'bat' ``` ```python >>> spam[2] 'rat' ``` ```python >>> spam[3] 'elephant' ``` ### Negative Indexes ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[-1] 'elephant' ``` ```python >>> spam[-3] 'bat' ``` ```python >>> 'The {} is afraid of the {}.'.format(spam[-1], spam[-3]) 'The elephant is afraid of the bat.' ``` ### Getting Sublists with Slices ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[0:4] ['cat', 'bat', 'rat', 'elephant'] ``` ```python >>> spam[1:3] ['bat', 'rat'] ``` ```python >>> spam[0:-1] ['cat', 'bat', 'rat'] ``` ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[:2] ['cat', 'bat'] ``` ```python >>> spam[1:] ['bat', 'rat', 'elephant'] ``` ```python >>> spam[:] ['cat', 'bat', 'rat', 'elephant'] ``` ### Getting a list Length with len ```python >>> spam = ['cat', 'dog', 'moose'] >>> len(spam) 3 ``` ### Changing Values in a List with Indexes ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[1] = 'aardvark' >>> spam ['cat', 'aardvark', 'rat', 'elephant'] >>> spam[2] = spam[1] >>> spam ['cat', 'aardvark', 'aardvark', 'elephant'] >>> spam[-1] = 12345 >>> spam ['cat', 'aardvark', 'aardvark', 12345] ``` ### List Concatenation and List Replication ```python >>> [1, 2, 3] + ['A', 'B', 'C'] [1, 2, 3, 'A', 'B', 'C'] >>> ['X', 'Y', 'Z'] * 3 ['X', 'Y', 'Z', 'X', 'Y', 'Z', 'X', 'Y', 'Z'] >>> spam = [1, 2, 3] >>> spam = spam + ['A', 'B', 'C'] >>> spam [1, 2, 3, 'A', 'B', 'C'] ``` ### Removing Values from Lists with del Statements ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> del spam[2] >>> spam ['cat', 'bat', 'elephant'] ``` ```python >>> del spam[2] >>> spam ['cat', 'bat'] ``` ### Using for Loops with Lists ```python >>> supplies = ['pens', 'staplers', 'flame-throwers', 'binders'] >>> for i, supply in enumerate(supplies): >>> print('Index {} in supplies is: {}'.format(str(i), supply)) Index 0 in supplies is: pens Index 1 in supplies is: staplers Index 2 in supplies is: flame-throwers Index 3 in supplies is: binders ``` ### Looping Through Multiple Lists with zip ```python >>> name = ['Pete', 'John', 'Elizabeth'] >>> age = [6, 23, 44] >>> for n, a in zip(name, age): >>> print('{} is {} years old'.format(n, a)) Pete is 6 years old John is 23 years old Elizabeth is 44 years old ``` ### The in and not in Operators ```python >>> 'howdy' in ['hello', 'hi', 'howdy', 'heyas'] True ``` ```python >>> spam = ['hello', 'hi', 'howdy', 'heyas'] >>> 'cat' in spam False ``` ```python >>> 'howdy' not in spam False ``` ```python >>> 'cat' not in spam True ``` ### The Multiple Assignment Trick The multiple assignment trick is a shortcut that lets you assign multiple variables with the values in a list in one line of code. So instead of doing this: ```python >>> cat = ['fat', 'orange', 'loud'] >>> size = cat[0] >>> color = cat[1] >>> disposition = cat[2] ``` You could type this line of code: ```python >>> cat = ['fat', 'orange', 'loud'] >>> size, color, disposition = cat ``` The multiple assignment trick can also be used to swap the values in two variables: ```python >>> a, b = 'Alice', 'Bob' >>> a, b = b, a >>> print(a) 'Bob' ``` ```python >>> print(b) 'Alice' ``` ### Augmented Assignment Operators | Operator | Equivalent | | ----------- | ----------------- | | `spam += 1` | `spam = spam + 1` | | `spam -= 1` | `spam = spam - 1` | | `spam *= 1` | `spam = spam * 1` | | `spam /= 1` | `spam = spam / 1` | | `spam %= 1` | `spam = spam % 1` | Examples: ```python >>> spam = 'Hello' >>> spam += ' world!' >>> spam 'Hello world!' >>> bacon = ['Zophie'] >>> bacon *= 3 >>> bacon ['Zophie', 'Zophie', 'Zophie'] ``` ### Finding a Value in a List with the index Method ```python >>> spam = ['Zophie', 'Pooka', 'Fat-tail', 'Pooka'] >>> spam.index('Pooka') 1 ``` ### Adding Values to Lists with append and insert **append()**: ```python >>> spam = ['cat', 'dog', 'bat'] >>> spam.append('moose') >>> spam ['cat', 'dog', 'bat', 'moose'] ``` **insert()**: ```python >>> spam = ['cat', 'dog', 'bat'] >>> spam.insert(1, 'chicken') >>> spam ['cat', 'chicken', 'dog', 'bat'] ``` ### Removing Values from Lists with remove ```python >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam.remove('bat') >>> spam ['cat', 'rat', 'elephant'] ``` If the value appears multiple times in the list, only the first instance of the value will be removed. ### Sorting the Values in a List with sort ```python >>> spam = [2, 5, 3.14, 1, -7] >>> spam.sort() >>> spam [-7, 1, 2, 3.14, 5] ``` ```python >>> spam = ['ants', 'cats', 'dogs', 'badgers', 'elephants'] >>> spam.sort() >>> spam ['ants', 'badgers', 'cats', 'dogs', 'elephants'] ``` You can also pass True for the reverse keyword argument to have sort() sort the values in reverse order: ```python >>> spam.sort(reverse=True) >>> spam ['elephants', 'dogs', 'cats', 'badgers', 'ants'] ``` If you need to sort the values in regular alphabetical order, pass str. lower for the key keyword argument in the sort() method call: ```python >>> spam = ['a', 'z', 'A', 'Z'] >>> spam.sort(key=str.lower) >>> spam ['a', 'A', 'z', 'Z'] ``` You can use the built-in function `sorted` to return a new list: ```python >>> spam = ['ants', 'cats', 'dogs', 'badgers', 'elephants'] >>> sorted(spam) ['ants', 'badgers', 'cats', 'dogs', 'elephants'] ``` ### Tuple Data Type ```python >>> eggs = ('hello', 42, 0.5) >>> eggs[0] 'hello' ``` ```python >>> eggs[1:3] (42, 0.5) ``` ```python >>> len(eggs) 3 ``` The main way that tuples are different from lists is that tuples, like strings, are immutable. ### Converting Types with the list and tuple Functions ```python >>> tuple(['cat', 'dog', 5]) ('cat', 'dog', 5) ``` ```python >>> list(('cat', 'dog', 5)) ['cat', 'dog', 5] ``` ```python >>> list('hello') ['h', 'e', 'l', 'l', 'o'] ``` ## Dictionaries and Structuring Data Example Dictionary: ```python myCat = {'size': 'fat', 'color': 'gray', 'disposition': 'loud'} ``` ### The keys, values, and items Methods values(): ```python >>> spam = {'color': 'red', 'age': 42} >>> for v in spam.values(): >>> print(v) red 42 ``` keys(): ```python >>> for k in spam.keys(): >>> print(k) color age ``` items(): ```python >>> for i in spam.items(): >>> print(i) ('color', 'red') ('age', 42) ``` Using the keys(), values(), and items() methods, a for loop can iterate over the keys, values, or key-value pairs in a dictionary, respectively. ```python >>> spam = {'color': 'red', 'age': 42} >>> >>> for k, v in spam.items(): >>> print('Key: {} Value: {}'.format(k, str(v))) Key: age Value: 42 Key: color Value: red ``` ### Checking if a Key or Value Exists in a Dictionary ```python >>> spam = {'name': 'Zophie', 'age': 7} ``` ```python >>> 'name' in spam.keys() True ``` ```python >>> 'Zophie' in spam.values() True ``` ```python >>> # You can omit the call to keys() when checking for a key >>> 'color' in spam False ``` ```python >>> 'color' not in spam True ``` ```python >>> 'color' in spam False ``` ### The get Method ```python >>> picnic_items = {'apples': 5, 'cups': 2} >>> 'I am bringing {} cups.'.format(str(picnic_items.get('cups', 0))) 'I am bringing 2 cups.' ``` ```python >>> 'I am bringing {} eggs.'.format(str(picnic_items.get('eggs', 0))) 'I am bringing 0 eggs.' ``` ### The setdefault Method Let's consider this code: ```python spam = {'name': 'Pooka', 'age': 5} if 'color' not in spam: spam['color'] = 'black' ``` Using `setdefault` we could make the same code more shortly: ```python >>> spam = {'name': 'Pooka', 'age': 5} >>> spam.setdefault('color', 'black') 'black' ``` ```python >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'} ``` ```python >>> spam.setdefault('color', 'white') 'black' ``` ```python >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'} ``` ### Pretty Printing ```python >>> import pprint >>> >>> message = 'It was a bright cold day in April, and the clocks were striking >>> thirteen.' >>> count = {} >>> >>> for character in message: >>> count.setdefault(character, 0) >>> count[character] = count[character] + 1 >>> >>> pprint.pprint(count) {' ': 13, ',': 1, '.': 1, 'A': 1, 'I': 1, 'a': 4, 'b': 1, 'c': 3, 'd': 3, 'e': 5, 'g': 2, 'h': 3, 'i': 6, 'k': 2, 'l': 3, 'n': 4, 'o': 2, 'p': 1, 'r': 5, 's': 3, 't': 6, 'w': 2, 'y': 1} ``` ### Merge two dictionaries ```python # in Python 3.5+: >>> x = {'a': 1, 'b': 2} >>> y = {'b': 3, 'c': 4} >>> z = {**x, **y} >>> z {'c': 4, 'a': 1, 'b': 3} # in Python 2.7 >>> z = dict(x, **y) >>> z {'c': 4, 'a': 1, 'b': 3} ``` ## sets From the Python 3 [documentation](https://docs.python.org/3/tutorial/datastructures.html) > A set is an unordered collection with no duplicate elements. Basic uses include membership testing and eliminating duplicate entries. Set objects also support mathematical operations like union, intersection, difference, and symmetric difference. ### Initializing a set There are two ways to create sets: using curly braces `{}` and the bult-in function `set()` ```python >>> s = {1, 2, 3} >>> s = set([1, 2, 3]) ``` When creating an empty set, be sure to not use the curly braces `{}` or you will get an empty dictionary instead. ```python >>> s = {} >>> type(s) ``` ### sets: unordered collections of unique elements A set automatically remove all the duplicate values. ```python >>> s = {1, 2, 3, 2, 3, 4} >>> s {1, 2, 3, 4} ``` And as an unordered data type, they can't be indexed. ```python >>> s = {1, 2, 3} >>> s(0) Traceback (most recent call last): File "", line 1, in TypeError: 'set' object does not support indexing >>> ``` ### set add and update Using the `add()` method we can add a single element to the set. ```python >>> s = {1, 2, 3} >>> s.add(4) >>> s {1, 2, 3, 4} ``` And with `update()`, multiple ones . ```python >>> s = {1, 2, 3} >>> s.update([2, 3, 4, 5, 6]) >>> s {1, 2, 3, 4, 5, 6} # remember, sets automatically remove duplicates ``` ### set remove and discard Both methods will remove an element from the set, but `remove()` will raise a `key error` if the value doesn't exist. ```python >>> s = {1, 2, 3} >>> s.remove(3) >>> s {1, 2} >>> s.remove(3) Traceback (most recent call last): File "", line 1, in KeyError: 3 ``` `discard()` won't raise any errors. ```python >>> s = {1, 2, 3} >>> s.discard(3) >>> s {1, 2} >>> s.discard(3) >>> ``` ### set union `union()` or `|` will create a new set that contains all the elements from the sets provided. ```python >>> s1 = {1, 2, 3} >>> s2 = {3, 4, 5} >>> s1.union(s2) # or 's1 | s2' {1, 2, 3, 4, 5} ``` ### set intersection `intersection` or `&` will return a set containing only the elements that are common to all of them. ```python >>> s1 = {1, 2, 3} >>> s2 = {2, 3, 4} >>> s3 = {3, 4, 5} >>> s1.intersection(s2, s3) # or 's1 & s2 & s3' {3} ``` ### set difference `difference` or `-` will return only the elements that are in one of the sets. ```python >>> s1 = {1, 2, 3} >>> s2 = {2, 3, 4} >>> s1.difference(s2) # or 's1 - s2' {1} ``` ### set symetric_difference `symetric_difference` or `^` will return all the elements that are not common between them. ```python >>> s1 = {1, 2, 3} >>> s2 = {2, 3, 4} >>> s1.symmetric_difference(s2) # or 's1 ^ s2' {1, 4} ``` ## itertools Module The *itertools* module is a collection of tools intented to be fast and use memory efficiently when handling iterators (like [lists](#lists) or [dictionaries](#dictionaries-and-structuring-data)). From the official [Python 3.x documentation](https://docs.python.org/3/library/itertools.html): > The module standardizes a core set of fast, memory efficient tools that are useful by themselves or in combination. Together, they form an “iterator algebra” making it possible to construct specialized tools succinctly and efficiently in pure Python. The *itertools* module comes in the standard library and must be imported. The [operator](https://docs.python.org/3/library/operator.html) module will also be used. This module is not necessary when using itertools, but needed for some of the examples below. ### accumulate Makes an iterator that returns the results of a function. ```python itertools.accumulate(iterable[, func]) ``` Example: ```python >>> data = [1, 2, 3, 4, 5] >>> result = itertools.accumulate(data, operator.mul) >>> for each in result: >>> print(each) 1 2 6 24 120 ``` The operator.mul takes two numbers and multiplies them: ```python operator.mul(1, 2) 2 operator.mul(2, 3) 6 operator.mul(6, 4) 24 operator.mul(24, 5) 120 ``` Passing a function is optional: ```python >>> data = [5, 2, 6, 4, 5, 9, 1] >>> result = itertools.accumulate(data) >>> for each in result: >>> print(each) 5 7 13 17 22 31 32 ``` If no function is designated the items will be summed: ```python 5 5 + 2 = 7 7 + 6 = 13 13 + 4 = 17 17 + 5 = 22 22 + 9 = 31 31 + 1 = 32 ``` ### combinations Takes an iterable and a integer. This will create all the unique combination that have r members. ```python itertools.combinations(iterable, r) ``` Example: ```python >>> shapes = ['circle', 'triangle', 'square',] >>> result = itertools.combinations(shapes, 2) >>> for each in result: >>> print(each) ('circle', 'triangle') ('circle', 'square') ('triangle', 'square') ``` ### combinations_with_replacement Just like combinations(), but allows individual elements to be repeated more than once. ```python itertools.combinations_with_replacement(iterable, r) ``` Example: ```python >>> shapes = ['circle', 'triangle', 'square'] >>> result = itertools.combinations_with_replacement(shapes, 2) >>> for each in result: >>> print(each) ('circle', 'circle') ('circle', 'triangle') ('circle', 'square') ('triangle', 'triangle') ('triangle', 'square') ('square', 'square') ``` ### count Makes an iterator that returns evenly spaced values starting with number start. ```python itertools.count(start=0, step=1) ``` Example: ```python >>> for i in itertools.count(10,3): >>> print(i) >>> if i > 20: >>> break 10 13 16 19 22 ``` ### cycle This function cycles through an iterator endlessly. ```python itertools.cycle(iterable) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue', 'violet'] >>> for color in itertools.cycle(colors): >>> print(color) red orange yellow green blue violet red orange ``` When reached the end of the iterable it start over again from the beginning. ### chain Take a series of iterables and return them as one long iterable. ```python itertools.chain(*iterables) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue'] >>> shapes = ['circle', 'triangle', 'square', 'pentagon'] >>> result = itertools.chain(colors, shapes) >>> for each in result: >>> print(each) red orange yellow green blue circle triangle square pentagon ``` ### compress Filters one iterable with another. ```python itertools.compress(data, selectors) ``` Example: ```python >>> shapes = ['circle', 'triangle', 'square', 'pentagon'] >>> selections = [True, False, True, False] >>> result = itertools.compress(shapes, selections) >>> for each in result: >>> print(each) circle square ``` ### dropwhile Make an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every element. ```python itertools.dropwhile(predicate, iterable) ``` Example: ```python >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1] >>> result = itertools.dropwhile(lambda x: x<5, data) >>> for each in result: >>> print(each) 5 6 7 8 9 10 1 ``` ### filterfalse Makes an iterator that filters elements from iterable returning only those for which the predicate is False. ```python itertools.filterfalse(predicate, iterable) ``` Example: ```python >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> result = itertools.filterfalse(lambda x: x<5, data) >>> for each in result: >>> print(each) 5 6 7 8 9 10 ``` ### groupby Simply put, this function groups things together. ```python itertools.groupby(iterable, key=None) ``` Example: ```python >>> robots = [{ 'name': 'blaster', 'faction': 'autobot' }, { 'name': 'galvatron', 'faction': 'decepticon' }, { 'name': 'jazz', 'faction': 'autobot' }, { 'name': 'metroplex', 'faction': 'autobot' }, { 'name': 'megatron', 'faction': 'decepticon' }, { 'name': 'starcream', 'faction': 'decepticon' }] >>> for key, group in itertools.groupby(robots, key=lambda x: x['faction']): >>> print(key) >>> print(list(group)) autobot [{'name': 'blaster', 'faction': 'autobot'}] decepticon [{'name': 'galvatron', 'faction': 'decepticon'}] autobot [{'name': 'jazz', 'faction': 'autobot'}, {'name': 'metroplex', 'faction': 'autobot'}] decepticon [{'name': 'megatron', 'faction': 'decepticon'}, {'name': 'starcream', 'faction': 'decepticon'}] ``` ### islice This function is very much like slices. This allows you to cut out a piece of an iterable. ```python itertools.islice(iterable, start, stop[, step]) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue',] >>> few_colors = itertools.islice(colors, 2) >>> for each in few_colors: >>> print(each) red orange ``` ### permutations ```python itertools.permutations(iterable, r=None) ``` Example: ```python >>> alpha_data = ['a', 'b', 'c'] >>> result = itertools.permutations(alpha_data) >>> for each in result: >>> print(each) ('a', 'b', 'c') ('a', 'c', 'b') ('b', 'a', 'c') ('b', 'c', 'a') ('c', 'a', 'b') ('c', 'b', 'a') ``` ### product Creates the cartesian products from a series of iterables. ```python >>> num_data = [1, 2, 3] >>> alpha_data = ['a', 'b', 'c'] >>> result = itertools.product(num_data, alpha_data) >>> for each in result: print(each) (1, 'a') (1, 'b') (1, 'c') (2, 'a') (2, 'b') (2, 'c') (3, 'a') (3, 'b') (3, 'c') ``` ### repeat This function will repeat an object over and over again. Unless, there is a times argument. ```python itertools.repeat(object[, times]) ``` Example: ```python >>> for i in itertools.repeat("spam", 3): print(i) spam spam spam ``` ### starmap Makes an iterator that computes the function using arguments obtained from the iterable. ```python itertools.starmap(function, iterable) ``` Example: ```python >>> data = [(2, 6), (8, 4), (7, 3)] >>> result = itertools.starmap(operator.mul, data) >>> for each in result: >>> print(each) 12 32 21 ``` ### takewhile The opposite of dropwhile(). Makes an iterator and returns elements from the iterable as long as the predicate is true. ```python itertools.takewhile(predicate, iterable) ``` Example: ```python >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1] >>> result = itertools.takewhile(lambda x: x<5, data) >>> for each in result: >>> print(each) 1 2 3 4 ``` ### tee Return n independent iterators from a single iterable. ```python itertools.tee(iterable, n=2) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue'] >>> alpha_colors, beta_colors = itertools.tee(colors) >>> for each in alpha_colors: >>> print(each) red orange yellow green blue ``` ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue'] >>> alpha_colors, beta_colors = itertools.tee(colors) >>> for each in beta_colors: >>> print(each) red orange yellow green blue ``` ### zip_longest Makes an iterator that aggregates elements from each of the iterables. If the iterables are of uneven length, missing values are filled-in with fillvalue. Iteration continues until the longest iterable is exhausted. ```python itertools.zip_longest(*iterables, fillvalue=None) ``` Example: ```python >>> colors = ['red', 'orange', 'yellow', 'green', 'blue',] >>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,] >>> for each in itertools.zip_longest(colors, data, fillvalue=None): >>> print(each) ('red', 1) ('orange', 2) ('yellow', 3) ('green', 4) ('blue', 5) (None, 6) (None, 7) (None, 8) (None, 9) (None, 10) ``` ## Comprehensions ### List comprehension ```python >>> a = [1, 3, 5, 7, 9, 11] >>> [i - 1 for i in a] [0, 2, 4, 6, 8, 10] ``` ### Set comprehension ```python >>> b = {"abc", "def"} >>> {s.upper() for s in b} {"ABC", "DEF} ``` ### Dict comprehension ```python >>> c = {'name': 'Pooka', 'age': 5} >>> {v, k for k, v in c.items()} {'Pooka': 'name', 5: 'age'} ``` A List comprehension can be generated from a dictionary: ```python >>> c = {'name': 'Pooka', 'first_name': 'Oooka'} >>> ["{}:{}".format(k.upper(), v.upper()) for k, v in c.items()] ['NAME:POOKA', 'FIRST_NAME:OOOKA'] ``` ## Manipulating Strings ### Escape Characters | Escape character | Prints as | | ---------------- | -------------------- | | `\'` | Single quote | | `\"` | Double quote | | `\t` | Tab | | `\n` | Newline (line break) | | `\\` | Backslash | Example: ```python >>> print("Hello there!\nHow are you?\nI\'m doing fine.") Hello there! How are you? I'm doing fine. ``` ### Raw Strings A raw string completely ignores all escape characters and prints any backslash that appears in the string. ```python >>> print(r'That is Carol\'s cat.') That is Carol\'s cat. ``` Note: mostly used for regular expression definition (see `re` package) ### Multiline Strings with Triple Quotes ```python >>> print('''Dear Alice, >>> >>> Eve's cat has been arrested for catnapping, cat burglary, and extortion. >>> >>> Sincerely, >>> Bob''') Dear Alice, Eve's cat has been arrested for catnapping, cat burglary, and extortion. Sincerely, Bob ``` To keep a nicer flow in your code, you can use the `dedent` function from the `textwrap` standard package. ```python >>> from textwrap import dedent >>> >>> def my_function(): >>> print(''' >>> Dear Alice, >>> >>> Eve's cat has been arrested for catnapping, cat burglary, and extortion. >>> >>> Sincerely, >>> Bob >>> ''').strip() ``` This generates the same string than before. ### Indexing and Slicing Strings H e l l o w o r l d ! 0 1 2 3 4 5 6 7 8 9 10 11 ```python >>> spam = 'Hello world!' >>> spam[0] 'H' ``` ```python >>> spam[4] 'o' ``` ```python >>> spam[-1] '!' ``` Slicing: ```python >>> spam[0:5] 'Hello' ``` ```python >>> spam[:5] 'Hello' ``` ```python >>> spam[6:] 'world!' ``` ```python >>> spam[6:-1] 'world' ``` ```python >>> spam[:-1] 'Hello world' ``` ```python >>> spam[::-1] '!dlrow olleH' ``` ```python >>> spam = 'Hello world!' >>> fizz = spam[0:5] >>> fizz 'Hello' ``` ### The in and not in Operators with Strings ```python >>> 'Hello' in 'Hello World' True ``` ```python >>> 'Hello' in 'Hello' True ``` ```python >>> 'HELLO' in 'Hello World' False ``` ```python >>> '' in 'spam' True ``` ```python >>> 'cats' not in 'cats and dogs' False ``` ### The in and not in Operators with list ```python >>> a = [1, 2, 3, 4] >>> 5 in a False ``` ```python >>> 2 in a True ``` ### The upper, lower, isupper, and islower String Methods `upper()` and `lower()`: ```python >>> spam = 'Hello world!' >>> spam = spam.upper() >>> spam 'HELLO WORLD!' ``` ```python >>> spam = spam.lower() >>> spam 'hello world!' ``` isupper() and islower(): ```python >>> spam = 'Hello world!' >>> spam.islower() False ``` ```python >>> spam.isupper() False ``` ```python >>> 'HELLO'.isupper() True ``` ```python >>> 'abc12345'.islower() True ``` ```python >>> '12345'.islower() False ``` ```python >>> '12345'.isupper() False ``` ### The isX String Methods - **isalpha()** returns True if the string consists only of letters and is not blank. - **isalnum()** returns True if the string consists only of lettersand numbers and is not blank. - **isdecimal()** returns True if the string consists only ofnumeric characters and is not blank. - **isspace()** returns True if the string consists only of spaces,tabs, and new-lines and is not blank. - **istitle()** returns True if the string consists only of wordsthat begin with an uppercase letter followed by onlylowercase letters. ### The startswith and endswith String Methods ```python >>> 'Hello world!'.startswith('Hello') True ``` ```python >>> 'Hello world!'.endswith('world!') True ``` ```python >>> 'abc123'.startswith('abcdef') False ``` ```python >>> 'abc123'.endswith('12') False ``` ```python >>> 'Hello world!'.startswith('Hello world!') True ``` ```python >>> 'Hello world!'.endswith('Hello world!') True ``` ### The join and split String Methods join(): ```python >>> ', '.join(['cats', 'rats', 'bats']) 'cats, rats, bats' ``` ```python >>> ' '.join(['My', 'name', 'is', 'Simon']) 'My name is Simon' ``` ```python >>> 'ABC'.join(['My', 'name', 'is', 'Simon']) 'MyABCnameABCisABCSimon' ``` split(): ```python >>> 'My name is Simon'.split() ['My', 'name', 'is', 'Simon'] ``` ```python >>> 'MyABCnameABCisABCSimon'.split('ABC') ['My', 'name', 'is', 'Simon'] ``` ```python >>> 'My name is Simon'.split('m') ['My na', 'e is Si', 'on'] ``` ### Justifying Text with rjust, ljust, and center rjust() and ljust(): ```python >>> 'Hello'.rjust(10) ' Hello' ``` ```python >>> 'Hello'.rjust(20) ' Hello' ``` ```python >>> 'Hello World'.rjust(20) ' Hello World' ``` ```python >>> 'Hello'.ljust(10) 'Hello ' ``` An optional second argument to rjust() and ljust() will specify a fill character other than a space character. Enter the following into the interactive shell: ```python >>> 'Hello'.rjust(20, '*') '***************Hello' ``` ```python >>> 'Hello'.ljust(20, '-') 'Hello---------------' ``` center(): ```python >>> 'Hello'.center(20) ' Hello ' ``` ```python >>> 'Hello'.center(20, '=') '=======Hello========' ``` ### Removing Whitespace with strip, rstrip, and lstrip ```python >>> spam = ' Hello World ' >>> spam.strip() 'Hello World' ``` ```python >>> spam.lstrip() 'Hello World ' ``` ```python >>> spam.rstrip() ' Hello World' ``` ```python >>> spam = 'SpamSpamBaconSpamEggsSpamSpam' >>> spam.strip('ampS') 'BaconSpamEggs' ``` ### Copying and Pasting Strings with the pyperclip Module First, install `pypeerclip` with pip: ```shell pip install pyperclip ``` ```python >>> import pyperclip >>> pyperclip.copy('Hello world!') >>> pyperclip.paste() 'Hello world!' ``` ## String Formatting ### % operator ```python >>> name = 'Pete' >>> 'Hello %s' % name "Hello Pete" ``` We can use the `%x` format specifier to convert an int value to a string: ```python >>> num = 5 >>> 'I have %x apples' % num "I have 5 apples" ``` Note: For new code, using str.format or f-strings is strongly recommended over the `%` operator. ### str.format Python 3 introduced a new way to do string formatting that was later back-ported to Python 2.7. This makes the syntax for string formatting more regular. ```python >>> name = 'John' >>> age = 20' >>> "Hello I'm {}, my age is {}".format(name, age) "Hello I'm John, my age is 20" ``` ```python >>> "Hello I'm {0}, my age is {1}".format(name, age) "Hello I'm John, my age is 20" ``` The official [Python 3.x documentation](https://docs.python.org/3/library/stdtypes.html?highlight=sprintf#printf-style-string-formatting) recommend `str.format` over the `%` operator: > The formatting operations described here exhibit a variety of quirks that lead to a number of common errors (such as failing to display tuples and dictionaries correctly). Using the newer formatted string literals or the str.format() interface helps avoid these errors. These alternatives also provide more powerful, flexible and extensible approaches to formatting text. ### Lazy string formatting You would only use `%s` string formatting on functions that can do lazy parameters evaluation, the most common being logging: Prefer: ```python >>> name = "alice" >>> logging.debug("User name: %s", name) ``` Over: ```python >>> logging.debug("User name: {}".format(name)) ``` Or: ```python >>> logging.debug("User name: " + name) ``` ### Formatted String Literals or f-strings Python 3.6+ ```python >>> name = 'Elizabeth' >>> f'Hello {name}!' 'Hello Elizabeth! ``` It is even possible to do inline arithmetic with it: ```python >>> a = 5 >>> b = 10 >>> f'Five plus ten is {a + b} and not {2 * (a + b)}.' 'Five plus ten is 15 and not 30.' ``` ### Template Strings A simpler and less powerful mechanism, but it is recommended when handling format strings generated by users. Due to their reduced complexity template strings are a safer choice. ```python >>> from string import Template >>> name = 'Elizabeth' >>> t = Template('Hey $name!') >>> t.substitute(name=name) 'Hey Elizabeth!' ``` ## Regular Expressions 1. Import the regex module with `import re`. 2. Create a Regex object with the `re.compile()` function. (Remember to use a raw string.) 3. Pass the string you want to search into the Regex object’s `search()` method. This returns a `Match` object. 4. Call the Match object’s `group()` method to return a string of the actual matched text. All the regex functions in Python are in the re module: ```python >>> import re ``` ### Matching Regex Objects ```python >>> phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d') >>> mo = phone_num_regex.search('My number is 415-555-4242.') >>> print('Phone number found: {}'.format(mo.group())) Phone number found: 415-555-4242 ``` ### Grouping with Parentheses ```python >>> phone_num_regex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)') >>> mo = phone_num_regex.search('My number is 415-555-4242.') >>> mo.group(1) '415' >>> mo.group(2) '555-4242' >>> mo.group(0) '415-555-4242' >>> mo.group() '415-555-4242' ``` To retrieve all the groups at once: use the groups() method—note the plural form for the name. ```python >>> mo.groups() ('415', '555-4242') >>> area_code, main_number = mo.groups() >>> print(area_code) 415 >>> print(main_number) 555-4242 ``` ### Matching Multiple Groups with the Pipe The | character is called a pipe. You can use it anywhere you want to match one of many expressions. For example, the regular expression r'Batman|Tina Fey' will match either 'Batman' or 'Tina Fey'. ```python >>> hero_regex = re.compile (r'Batman|Tina Fey') >>> mo1 = hero_regex.search('Batman and Tina Fey.') >>> mo1.group() 'Batman' >>> mo2 = hero_regex.search('Tina Fey and Batman.') >>> mo2.group() 'Tina Fey' ``` You can also use the pipe to match one of several patterns as part of your regex: ```python >>> bat_regex = re.compile(r'Bat(man|mobile|copter|bat)') >>> mo = bat_regex.search('Batmobile lost a wheel') >>> mo.group() 'Batmobile' >>> mo.group(1) 'mobile' ``` ### Optional Matching with the Question Mark The ? character flags the group that precedes it as an optional part of the pattern. ```python >>> bat_regex = re.compile(r'Bat(wo)?man') >>> mo1 = bat_regex.search('The Adventures of Batman') >>> mo1.group() 'Batman' >>> mo2 = bat_regex.search('The Adventures of Batwoman') >>> mo2.group() 'Batwoman' ``` ### Matching Zero or More with the Star The * (called the star or asterisk) means “match zero or more”—the group that precedes the star can occur any number of times in the text. ```python >>> bat_regex = re.compile(r'Bat(wo)*man') >>> mo1 = bat_regex.search('The Adventures of Batman') >>> mo1.group() 'Batman' >>> mo2 = bat_regex.search('The Adventures of Batwoman') >>> mo2.group() 'Batwoman' >>> mo3 = bat_regex.search('The Adventures of Batwowowowoman') >>> mo3.group() 'Batwowowowoman' ``` ### Matching One or More with the Plus While * means “match zero or more,” the + (or plus) means “match one or more”. The group preceding a plus must appear at least once. It is not optional: ```python >>> bat_regex = re.compile(r'Bat(wo)+man') >>> mo1 = bat_regex.search('The Adventures of Batwoman') >>> mo1.group() 'Batwoman' ``` ```python >>> mo2 = bat_regex.search('The Adventures of Batwowowowoman') >>> mo2.group() 'Batwowowowoman' ``` ```python >>> mo3 = bat_regex.search('The Adventures of Batman') >>> mo3 is None True ``` ### Matching Specific Repetitions with Curly Brackets If you have a group that you want to repeat a specific number of times, follow the group in your regex with a number in curly brackets. For example, the regex (Ha){3} will match the string 'HaHaHa', but it will not match 'HaHa', since the latter has only two repeats of the (Ha) group. Instead of one number, you can specify a range by writing a minimum, a comma, and a maximum in between the curly brackets. For example, the regex (Ha){3,5} will match 'HaHaHa', 'HaHaHaHa', and 'HaHaHaHaHa'. ```python >>> ha_regex = re.compile(r'(Ha){3}') >>> mo1 = ha_regex.search('HaHaHa') >>> mo1.group() 'HaHaHa' ``` ```python >>> mo2 = ha_regex.search('Ha') >>> mo2 is None True ``` ### Greedy and Nongreedy Matching Python’s regular expressions are greedy by default, which means that in ambiguous situations they will match the longest string possible. The non-greedy version of the curly brackets, which matches the shortest string possible, has the closing curly bracket followed by a question mark. ```python >>> greedy_ha_regex = re.compile(r'(Ha){3,5}') >>> mo1 = greedy_ha_regex.search('HaHaHaHaHa') >>> mo1.group() 'HaHaHaHaHa' ``` ```python >>> nongreedy_ha_regex = re.compile(r'(Ha){3,5}?') >>> mo2 = nongreedy_ha_regex.search('HaHaHaHaHa') >>> mo2.group() 'HaHaHa' ``` ### The findall Method In addition to the search() method, Regex objects also have a findall() method. While search() will return a Match object of the first matched text in the searched string, the findall() method will return the strings of every match in the searched string. ```python >>> phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d') # has no groups >>> phone_num_regex.findall('Cell: 415-555-9999 Work: 212-555-0000') ['415-555-9999', '212-555-0000'] ``` To summarize what the findall() method returns, remember the following: - When called on a regex with no groups, such as \d-\d\d\d-\d\d\d\d, the method findall() returns a list of ng matches, such as ['415-555-9999', '212-555-0000']. - When called on a regex that has groups, such as (\d\d\d)-d\d)-(\d\ d\d\d), the method findall() returns a list of es of strings (one string for each group), such as [('415', ', '9999'), ('212', '555', '0000')]. ### Making Your Own Character Classes There are times when you want to match a set of characters but the shorthand character classes (\d, \w, \s, and so on) are too broad. You can define your own character class using square brackets. For example, the character class [aeiouAEIOU] will match any vowel, both lowercase and uppercase. ```python >>> vowel_regex = re.compile(r'[aeiouAEIOU]') >>> vowel_regex.findall('Robocop eats baby food. BABY FOOD.') ['o', 'o', 'o', 'e', 'a', 'a', 'o', 'o', 'A', 'O', 'O'] ``` You can also include ranges of letters or numbers by using a hyphen. For example, the character class [a-zA-Z0-9] will match all lowercase letters, uppercase letters, and numbers. By placing a caret character (^) just after the character class’s opening bracket, you can make a negative character class. A negative character class will match all the characters that are not in the character class. For example, enter the following into the interactive shell: ```python >>> consonant_regex = re.compile(r'[^aeiouAEIOU]') >>> consonant_regex.findall('Robocop eats baby food. BABY FOOD.') ['R', 'b', 'c', 'p', ' ', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', ' ', 'B', 'B', 'Y', ' ', 'F', 'D', '.'] ``` ### The Caret and Dollar Sign Characters - You can also use the caret symbol (^) at the start of a regex to indicate that a match must occur at the beginning of the searched text. - Likewise, you can put a dollar sign ($) at the end of the regex to indicate the string must end with this regex pattern. - And you can use the ^ and $ together to indicate that the entire string must match the regex—that is, it’s not enough for a match to be made on some subset of the string. The r'^Hello' regular expression string matches strings that begin with 'Hello': ```python >>> begins_with_hello = re.compile(r'^Hello') >>> begins_with_hello.search('Hello world!') <_sre.SRE_Match object; span=(0, 5), match='Hello'> >>> begins_with_hello.search('He said hello.') is None True ``` The r'\d$' regular expression string matches strings that end with a numeric character from 0 to 9: ```python >>> whole_string_is_num = re.compile(r'^\d+$') >>> whole_string_is_num.search('1234567890') <_sre.SRE_Match object; span=(0, 10), match='1234567890'> >>> whole_string_is_num.search('12345xyz67890') is None True >>> whole_string_is_num.search('12 34567890') is None True ``` ### The Wildcard Character The . (or dot) character in a regular expression is called a wildcard and will match any character except for a newline: ```python >>> at_regex = re.compile(r'.at') >>> at_regex.findall('The cat in the hat sat on the flat mat.') ['cat', 'hat', 'sat', 'lat', 'mat'] ``` ### Matching Everything with Dot-Star ```python >>> name_regex = re.compile(r'First Name: (.*) Last Name: (.*)') >>> mo = name_regex.search('First Name: Al Last Name: Sweigart') >>> mo.group(1) 'Al' ``` ```python >>> mo.group(2) 'Sweigart' ``` The dot-star uses greedy mode: It will always try to match as much text as possible. To match any and all text in a nongreedy fashion, use the dot, star, and question mark (.*?). The question mark tells Python to match in a nongreedy way: ```python >>> nongreedy_regex = re.compile(r'<.*?>') >>> mo = nongreedy_regex.search(' for dinner.>') >>> mo.group() '' ``` ```python >>> greedy_regex = re.compile(r'<.*>') >>> mo = greedy_regex.search(' for dinner.>') >>> mo.group() ' for dinner.>' ``` ### Matching Newlines with the Dot Character The dot-star will match everything except a newline. By passing re.DOTALL as the second argument to re.compile(), you can make the dot character match all characters, including the newline character: ```python >>> no_newline_regex = re.compile('.*') >>> no_newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group() 'Serve the public trust.' ``` ```python >>> newline_regex = re.compile('.*', re.DOTALL) >>> newline_regex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group() 'Serve the public trust.\nProtect the innocent.\nUphold the law.' ``` ### Review of Regex Symbols | Symbol | Matches | | ------------------------ | ------------------------------------------------------------ | | `?` | zero or one of the preceding group. | | `*` | zero or more of the preceding group. | | `+` | one or more of the preceding group. | | `{n}` | exactly n of the preceding group. | | `{n,}` | n or more of the preceding group. | | `{,m}` | 0 to m of the preceding group. | | `{n,m}` | at least n and at most m of the preceding p. | | `{n,m}?` or `*?` or `+?` | performs a nongreedy match of the preceding p. | | `^spam` | means the string must begin with spam. | | `spam$` | means the string must end with spam. | | `.` | any character, except newline characters. | | `\d`, `\w`, and `\s` | a digit, word, or space character, resectively. | | `\D`, `\W`, and `\S` | anything except a digit, word, or space acter, respectively. | | `[abc]` | any character between the brackets (such as a, b, ). | | `[^abc]` | any character that isn’t between the brackets. | ### Case-Insensitive Matching To make your regex case-insensitive, you can pass re.IGNORECASE or re.I as a second argument to re.compile(): ```python >>> robocop = re.compile(r'robocop', re.I) >>> robocop.search('Robocop is part man, part machine, all cop.').group() 'Robocop' ``` ```python >>> robocop.search('ROBOCOP protects the innocent.').group() 'ROBOCOP' ``` ```python >>> robocop.search('Al, why does your programming book talk about robocop so much?').group() 'robocop' ``` ### Substituting Strings with the sub() Method The sub() method for Regex objects is passed two arguments: 1. The first argument is a string to replace any matches. 1. The second is the string for the regular expression. The sub() method returns a string with the substitutions applied: ```python >>> names_regex = re.compile(r'Agent \w+') >>> names_regex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.') 'CENSORED gave the secret documents to CENSORED.' ``` Another example: ```python >>> agent_names_regex = re.compile(r'Agent (\w)\w*') >>> agent_names_regex.sub(r'\1****', 'Agent Alice told Agent Carol that Agent Eve knew Agent Bob was a double agent.') A**** told C**** that E**** knew B**** was a double agent.' ``` ### Managing Complex Regexes To tell the re.compile() function to ignore whitespace and comments inside the regular expression string, “verbose mode” can be enabled by passing the variable re.VERBOSE as the second argument to re.compile(). Now instead of a hard-to-read regular expression like this: ```python phone_regex = re.compile(r'((\d{3}|\(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4}(\s*(ext|x|ext.)\s*\d{2,5})?)') ``` you can spread the regular expression over multiple lines with comments like this: ```python phone_regex = re.compile(r'''( (\d{3}|\(\d{3}\))? # area code (\s|-|\.)? # separator \d{3} # first 3 digits (\s|-|\.) # separator \d{4} # last 4 digits (\s*(ext|x|ext.)\s*\d{2,5})? # extension )''', re.VERBOSE) ``` ## Handling File and Directory Paths There are two main modules in Python that deals with path manipulation. One is the `os.path` module and the other is the `pathlib` module. The `pathlib` module was added in Python 3.4, offering an object-oriented way to handle file system paths. ### Backslash on Windows and Forward Slash on OS X and Linux On Windows, paths are written using backslashes (\) as the separator between folder names. On Unix based operating system such as macOS, Linux, and BSDs, the forward slash (/) is used as the path separator. Joining paths can be a headache if your code needs to work on different platforms. Fortunately, Python provides easy ways to handle this. We will showcase how to deal with this with both `os.path.join` and `pathlib.Path.joinpath` Using `os.path.join` on Windows: ```python >>> import os >>> os.path.join('usr', 'bin', 'spam') 'usr\\bin\\spam' ``` And using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> print(Path('usr').joinpath('bin').joinpath('spam')) usr/bin/spam ``` `pathlib` also provides a shortcut to joinpath using the `/` operator: ```python >>> from pathlib import Path >>> print(Path('usr') / 'bin' / 'spam') usr/bin/spam ``` Notice the path separator is different between Windows and Unix based operating system, that's why you want to use one of the above methods instead of adding strings together to join paths together. Joining paths is helpful if you need to create different file paths under the same directory. Using `os.path.join` on Windows: ```python >>> my_files = ['accounts.txt', 'details.csv', 'invite.docx'] >>> for filename in my_files: >>> print(os.path.join('C:\\Users\\asweigart', filename)) C:\Users\asweigart\accounts.txt C:\Users\asweigart\details.csv C:\Users\asweigart\invite.docx ``` Using `pathlib` on \*nix: ```python >>> my_files = ['accounts.txt', 'details.csv', 'invite.docx'] >>> home = Path.home() >>> for filename in my_files: >>> print(home / filename) /home/asweigart/accounts.txt /home/asweigart/details.csv /home/asweigart/invite.docx ``` ### The Current Working Directory Using `os` on Windows: ```python >>> import os >>> os.getcwd() 'C:\\Python34' >>> os.chdir('C:\\Windows\\System32') >>> os.getcwd() 'C:\\Windows\\System32' ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> from os import chdir >>> print(Path.cwd()) /home/asweigart >>> chdir('/usr/lib/python3.6') >>> print(Path.cwd()) /usr/lib/python3.6 ``` ### Creating New Folders Using `os` on Windows: ```python >>> import os >>> os.makedirs('C:\\delicious\\walnut\\waffles') ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> cwd = Path.cwd() >>> (cwd / 'delicious' / 'walnut' / 'waffles').mkdir() Traceback (most recent call last): File "", line 1, in File "/usr/lib/python3.6/pathlib.py", line 1226, in mkdir self._accessor.mkdir(self, mode) File "/usr/lib/python3.6/pathlib.py", line 387, in wrapped return strfunc(str(pathobj), *args) FileNotFoundError: [Errno 2] No such file or directory: '/home/asweigart/delicious/walnut/waffles' ``` Oh no, we got a nasty error! The reason is that the 'delicious' directory does not exist, so we cannot make the 'walnut' and the 'waffles' directories under it. To fix this, do: ```python >>> from pathlib import Path >>> cwd = Path.cwd() >>> (cwd / 'delicious' / 'walnut' / 'waffles').mkdir(parents=True) ``` And all is good :) ### Absolute vs. Relative Paths There are two ways to specify a file path. - An absolute path, which always begins with the root folder - A relative path, which is relative to the program’s current working directory There are also the dot (.) and dot-dot (..) folders. These are not real folders but special names that can be used in a path. A single period (“dot”) for a folder name is shorthand for “this directory.” Two periods (“dot-dot”) means “the parent folder.” ### Handling Absolute and Relative Paths To see if a path is an absolute path: Using `os.path` on \*nix: ```python >>> import os >>> os.path.isabs('/') True >>> os.path.isabs('..') False ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> Path('/').is_absolute() True >>> Path('..').is_absolute() False ``` You can extract an absolute path with both `os.path` and `pathlib` Using `os.path` on \*nix: ```python >>> import os >>> os.getcwd() '/home/asweigart' >>> os.path.abspath('..') '/home' ``` Using `pathlib` on \*nix: ```python from pathlib import Path print(Path.cwd()) /home/asweigart print(Path('..').resolve()) /home ``` You can get a relative path from a starting path to another path. Using `os.path` on \*nix: ```python >>> import os >>> os.path.relpath('/etc/passwd', '/') 'etc/passwd' ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> print(Path('/etc/passwd').relative_to('/')) etc/passwd ``` ### Checking Path Validity Checking if a file/directory exists: Using `os.path` on \*nix: ```python import os >>> os.path.exists('.') True >>> os.path.exists('setup.py') True >>> os.path.exists('/etc') True >>> os.path.exists('nonexistentfile') False ``` Using `pathlib` on \*nix: ```python from pathlib import Path >>> Path('.').exists() True >>> Path('setup.py').exists() True >>> Path('/etc').exists() True >>> Path('nonexistentfile').exists() False ``` Checking if a path is a file: Using `os.path` on \*nix: ```python >>> import os >>> os.path.isfile('setup.py') True >>> os.path.isfile('/home') False >>> os.path.isfile('nonexistentfile') False ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> Path('setup.py').is_file() True >>> Path('/home').is_file() False >>> Path('nonexistentfile').is_file() False ``` Checking if a path is a directory: Using `os.path` on \*nix: ```python >>> import os >>> os.path.isdir('/') True >>> os.path.isdir('setup.py') False >>> os.path.isdir('/spam') False ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> Path('/').is_dir() True >>> Path('setup.py').is_dir() False >>> Path('/spam').is_dir() False ``` ### Finding File Sizes and Folder Contents Getting a file's size in bytes: Using `os.path` on Windows: ```python >>> import os >>> os.path.getsize('C:\\Windows\\System32\\calc.exe') 776192 ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> stat = Path('/bin/python3.6').stat() >>> print(stat) # stat contains some other information about the file as well os.stat_result(st_mode=33261, st_ino=141087, st_dev=2051, st_nlink=2, st_uid=0, --snip-- st_gid=0, st_size=10024, st_atime=1517725562, st_mtime=1515119809, st_ctime=1517261276) >>> print(stat.st_size) # size in bytes 10024 ``` Listing directory contents using `os.listdir` on Windows: ```python >>> import os >>> os.listdir('C:\\Windows\\System32') ['0409', '12520437.cpx', '12520850.cpx', '5U877.ax', 'aaclient.dll', --snip-- 'xwtpdui.dll', 'xwtpw32.dll', 'zh-CN', 'zh-HK', 'zh-TW', 'zipfldr.dll'] ``` Listing directory contents using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> for f in Path('/usr/bin').iterdir(): >>> print(f) ... /usr/bin/tiff2rgba /usr/bin/iconv /usr/bin/ldd /usr/bin/cache_restore /usr/bin/udiskie /usr/bin/unix2dos /usr/bin/t1reencode /usr/bin/epstopdf /usr/bin/idle3 ... ``` To find the total size of all the files in this directory: **WARNING**: Directories themselves also have a size! So you might want to check for whether a path is a file or directory using the methods in the methods discussed in the above section! Using `os.path.getsize()` and `os.listdir()` together on Windows: ```python >>> import os >>> total_size = 0 >>> for filename in os.listdir('C:\\Windows\\System32'): total_size = total_size + os.path.getsize(os.path.join('C:\\Windows\\System32', filename)) >>> print(total_size) 1117846456 ``` Using `pathlib` on \*nix: ```python >>> from pathlib import Path >>> total_size = 0 >>> for sub_path in Path('/usr/bin').iterdir(): ... total_size += sub_path.stat().st_size >>> >>> print(total_size) 1903178911 ``` ### Copying Files and Folders The shutil module provides functions for copying files, as well as entire folders. ```python >>> import shutil, os >>> os.chdir('C:\\') >>> shutil.copy('C:\\spam.txt', 'C:\\delicious') 'C:\\delicious\\spam.txt' >>> shutil.copy('eggs.txt', 'C:\\delicious\\eggs2.txt') 'C:\\delicious\\eggs2.txt' ``` While shutil.copy() will copy a single file, shutil.copytree() will copy an entire folder and every folder and file contained in it: ```python >>> import shutil, os >>> os.chdir('C:\\') >>> shutil.copytree('C:\\bacon', 'C:\\bacon_backup') 'C:\\bacon_backup' ``` ### Moving and Renaming Files and Folders ```python >>> import shutil >>> shutil.move('C:\\bacon.txt', 'C:\\eggs') 'C:\\eggs\\bacon.txt' ``` The destination path can also specify a filename. In the following example, the source file is moved and renamed: ```python >>> shutil.move('C:\\bacon.txt', 'C:\\eggs\\new_bacon.txt') 'C:\\eggs\\new_bacon.txt' ``` If there is no eggs folder, then move() will rename bacon.txt to a file named eggs. ```python >>> shutil.move('C:\\bacon.txt', 'C:\\eggs') 'C:\\eggs' ``` ### Permanently Deleting Files and Folders - Calling os.unlink(path) or Path.unlink() will delete the file at path. - Calling os.rmdir(path) or Path.rmdir() will delete the folder at path. This folder must be empty of any files or folders. - Calling shutil.rmtree(path) will remove the folder at path, and all files and folders it contains will also be deleted. ### Safe Deletes with the send2trash Module You can install this module by running pip install send2trash from a Terminal window. ```python >>> import send2trash >>> with open('bacon.txt', 'a') as bacon_file: # creates the file ... bacon_file.write('Bacon is not a vegetable.') 25 >>> send2trash.send2trash('bacon.txt') ``` ### Walking a Directory Tree ```python >>> import os >>> >>> for folder_name, subfolders, filenames in os.walk('C:\\delicious'): >>> print('The current folder is {}'.format(folder_name)) >>> >>> for subfolder in subfolders: >>> print('SUBFOLDER OF {}: {}'.format(folder_name, subfolder)) >>> for filename in filenames: >>> print('FILE INSIDE {}: {}'.format(folder_name, filename)) >>> >>> print('') The current folder is C:\delicious SUBFOLDER OF C:\delicious: cats SUBFOLDER OF C:\delicious: walnut FILE INSIDE C:\delicious: spam.txt The current folder is C:\delicious\cats FILE INSIDE C:\delicious\cats: catnames.txt FILE INSIDE C:\delicious\cats: zophie.jpg The current folder is C:\delicious\walnut SUBFOLDER OF C:\delicious\walnut: waffles The current folder is C:\delicious\walnut\waffles FILE INSIDE C:\delicious\walnut\waffles: butter.txt ``` `pathlib` provides a lot more functionality than the ones listed above, like getting file name, getting file extension, reading/writing a file without manually opening it, etc. Check out the [official documentation](https://docs.python.org/3/library/pathlib.html) if you want to know more! ## Reading and Writing Files ### The File Reading/Writing Process To read/write to a file in Python, you will want to use the `with` statement, which will close the file for you after you are done. ### Opening and reading files with the open function ```python >>> with open('C:\\Users\\your_home_folder\\hello.txt') as hello_file: ... hello_content = hello_file.read() >>> hello_content 'Hello World!' >>> # Alternatively, you can use the *readlines()* method to get a list of string values from the file, one string for each line of text: >>> with open('sonnet29.txt') as sonnet_file: ... sonnet_file.readlines() [When, in disgrace with fortune and men's eyes,\n', ' I all alone beweep my outcast state,\n', And trouble deaf heaven with my bootless cries,\n', And look upon myself and curse my fate,'] >>> # You can also iterate through the file line by line: >>> with open('sonnet29.txt') as sonnet_file: ... for line in sonnet_file: # note the new line character will be included in the line ... print(line, end='') When, in disgrace with fortune and men's eyes, I all alone beweep my outcast state, And trouble deaf heaven with my bootless cries, And look upon myself and curse my fate, ``` ### Writing to Files ```python >>> with open('bacon.txt', 'w') as bacon_file: ... bacon_file.write('Hello world!\n') 13 >>> with open('bacon.txt', 'a') as bacon_file: ... bacon_file.write('Bacon is not a vegetable.') 25 >>> with open('bacon.txt') as bacon_file: ... content = bacon_file.read() >>> print(content) Hello world! Bacon is not a vegetable. ``` ### Saving Variables with the shelve Module To save variables: ```python >>> import shelve >>> cats = ['Zophie', 'Pooka', 'Simon'] >>> with shelve.open('mydata') as shelf_file: ... shelf_file['cats'] = cats ``` To open and read variables: ```python >>> with shelve.open('mydata') as shelf_file: ... print(type(shelf_file)) ... print(shelf_file['cats']) ['Zophie', 'Pooka', 'Simon'] ``` Just like dictionaries, shelf values have keys() and values() methods that will return list-like values of the keys and values in the shelf. Since these methods return list-like values instead of true lists, you should pass them to the list() function to get them in list form. ```python >>> with shelve.open('mydata') as shelf_file: ... print(list(shelf_file.keys())) ... print(list(shelf_file.values())) ['cats'] [['Zophie', 'Pooka', 'Simon']] ``` ### Saving Variables with pprint.pformat ```python >>> import pprint >>> cats = [{'name': 'Zophie', 'desc': 'chubby'}, {'name': 'Pooka', 'desc': 'fluffy'}] >>> pprint.pformat(cats) "[{'desc': 'chubby', 'name': 'Zophie'}, {'desc': 'fluffy', 'name': 'Pooka'}]" >>> with open('myCats.py', 'w') as file_obj: ... file_obj.write('cats = {}\n'.format(pprint.pformat(cats))) 83 ``` ### Reading ZIP Files ```python >>> import zipfile, os >>> os.chdir('C:\\') # move to the folder with example.zip >>> with zipfile.ZipFile('example.zip') as example_zip: ... print(example_zip.namelist()) ... spam_info = example_zip.getinfo('spam.txt') ... print(spam_info.file_size) ... print(spam_info.compress_size) ... print('Compressed file is %sx smaller!' % (round(spam_info.file_size / spam_info.compress_size, 2))) ['spam.txt', 'cats/', 'cats/catnames.txt', 'cats/zophie.jpg'] 13908 3828 'Compressed file is 3.63x smaller!' ``` ### Extracting from ZIP Files The extractall() method for ZipFile objects extracts all the files and folders from a ZIP file into the current working directory. ```python >>> import zipfile, os >>> os.chdir('C:\\') # move to the folder with example.zip >>> with zipfile.ZipFile('example.zip') as example_zip: ... example_zip.extractall() ``` The extract() method for ZipFile objects will extract a single file from the ZIP file. Continue the interactive shell example: ```python >>> with zipfile.ZipFile('example.zip') as example_zip: ... print(example_zip.extract('spam.txt')) ... print(example_zip.extract('spam.txt', 'C:\\some\\new\\folders')) 'C:\\spam.txt' 'C:\\some\\new\\folders\\spam.txt' ``` ### Creating and Adding to ZIP Files ```python >>> import zipfile >>> with zipfile.ZipFile('new.zip', 'w') as new_zip: ... new_zip.write('spam.txt', compress_type=zipfile.ZIP_DEFLATED) ``` This code will create a new ZIP file named new.zip that has the compressed contents of spam.txt. ## JSON, YAML and configuration files ### JSON Open a JSON file with: ```python import json with open("filename.json", "r") as f: content = json.loads(f.read()) ``` Write a JSON file with: ```python import json content = {"name": "Joe", "age": 20} with open("filename.json", "w") as f: f.write(json.dumps(content, indent=2)) ``` ### YAML Compared to JSON, YAML allows a much better humain maintainance and gives ability to add comments. It is a convinient choice for configuration files where human will have to edit. There are two main librairies allowing to access to YAML files: - [PyYaml](https://pypi.python.org/pypi/PyYAML) - [Ruamel.yaml](https://pypi.python.org/pypi/ruamel.yaml) Install them using `pip install` in your virtual environment. The first one it easier to use but the second one, Ruamel, implements much better the YAML specification, and allow for example to modify a YAML content without altering comments. Open a YAML file with: ```python from ruamel.yaml import YAML with open("filename.yaml") as f: yaml=YAML() yaml.load(f) ``` ### Anyconfig [Anyconfig](https://pypi.python.org/pypi/anyconfig) is a very handy package allowing to abstract completly the underlying configuration file format. It allows to load a Python dictionary from JSON, YAML, TOML, and so on. Install it with: ```bash pip install anyconfig ``` Usage: ```python import anyconfig conf1 = anyconfig.load("/path/to/foo/conf.d/a.yml") ``` ## Debugging ### Raising Exceptions Exceptions are raised with a raise statement. In code, a raise statement consists of the following: - The raise keyword - A call to the Exception() function - A string with a helpful error message passed to the Exception() function ```python >>> raise Exception('This is the error message.') Traceback (most recent call last): File "", line 1, in raise Exception('This is the error message.') Exception: This is the error message. ``` Often it’s the code that calls the function, not the function itself, that knows how to handle an expection. So you will commonly see a raise statement inside a function and the try and except statements in the code calling the function. ```python def box_print(symbol, width, height): if len(symbol) != 1: raise Exception('Symbol must be a single character string.') if width <= 2: raise Exception('Width must be greater than 2.') if height <= 2: raise Exception('Height must be greater than 2.') print(symbol * width) for i in range(height - 2): print(symbol + (' ' * (width - 2)) + symbol) print(symbol * width) for sym, w, h in (('*', 4, 4), ('O', 20, 5), ('x', 1, 3), ('ZZ', 3, 3)): try: box_print(sym, w, h) except Exception as err: print('An exception happened: ' + str(err)) ``` ### Getting the Traceback as a String The traceback is displayed by Python whenever a raised exception goes unhandled. But can also obtain it as a string by calling traceback.format_exc(). This function is useful if you want the information from an exception’s traceback but also want an except statement to gracefully handle the exception. You will need to import Python’s traceback module before calling this function. ```python >>> import traceback >>> try: >>> raise Exception('This is the error message.') >>> except: >>> with open('errorInfo.txt', 'w') as error_file: >>> error_file.write(traceback.format_exc()) >>> print('The traceback info was written to errorInfo.txt.') 116 The traceback info was written to errorInfo.txt. ``` The 116 is the return value from the write() method, since 116 characters were written to the file. The traceback text was written to errorInfo.txt. Traceback (most recent call last): File "", line 2, in Exception: This is the error message. ### Assertions An assertion is a sanity check to make sure your code isn’t doing something obviously wrong. These sanity checks are performed by assert statements. If the sanity check fails, then an AssertionError exception is raised. In code, an assert statement consists of the following: - The assert keyword - A condition (that is, an expression that evaluates to True or False) - A comma - A string to display when the condition is False ```python >>> pod_bay_door_status = 'open' >>> assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' >>> pod_bay_door_status = 'I\'m sorry, Dave. I\'m afraid I can\'t do that.' >>> assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' Traceback (most recent call last): File "", line 1, in assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' AssertionError: The pod bay doors need to be "open". ``` In plain English, an assert statement says, “I assert that this condition holds true, and if not, there is a bug somewhere in the program.” Unlike exceptions, your code should not handle assert statements with try and except; if an assert fails, your program should crash. By failing fast like this, you shorten the time between the original cause of the bug and when you first notice the bug. This will reduce the amount of code you will have to check before finding the code that’s causing the bug. Disabling Assertions Assertions can be disabled by passing the -O option when running Python. ### Logging To enable the logging module to display log messages on your screen as your program runs, copy the following to the top of your program (but under the #! python shebang line): ```python import logging logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s- %(message)s') ``` Say you wrote a function to calculate the factorial of a number. In mathematics, factorial 4 is 1 × 2 × 3 × 4, or 24. Factorial 7 is 1 × 2 × 3 × 4 × 5 × 6 × 7, or 5,040. Open a new file editor window and enter the following code. It has a bug in it, but you will also enter several log messages to help yourself figure out what is going wrong. Save the program as factorialLog.py. ```python >>> import logging >>> >>> logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s- %(message)s') >>> >>> logging.debug('Start of program') >>> >>> def factorial(n): >>> >>> logging.debug('Start of factorial(%s)' % (n)) >>> total = 1 >>> >>> for i in range(1, n + 1): >>> total *= i >>> logging.debug('i is ' + str(i) + ', total is ' + str(total)) >>> >>> logging.debug('End of factorial(%s)' % (n)) >>> >>> return total >>> >>> print(factorial(5)) >>> logging.debug('End of program') 2015-05-23 16:20:12,664 - DEBUG - Start of program 2015-05-23 16:20:12,664 - DEBUG - Start of factorial(5) 2015-05-23 16:20:12,665 - DEBUG - i is 0, total is 0 2015-05-23 16:20:12,668 - DEBUG - i is 1, total is 0 2015-05-23 16:20:12,670 - DEBUG - i is 2, total is 0 2015-05-23 16:20:12,673 - DEBUG - i is 3, total is 0 2015-05-23 16:20:12,675 - DEBUG - i is 4, total is 0 2015-05-23 16:20:12,678 - DEBUG - i is 5, total is 0 2015-05-23 16:20:12,680 - DEBUG - End of factorial(5) 0 2015-05-23 16:20:12,684 - DEBUG - End of program ``` ### Logging Levels Logging levels provide a way to categorize your log messages by importance. There are five logging levels, described in Table 10-1 from least to most important. Messages can be logged at each level using a different logging function. | Level | Logging Function | Description | | ---------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `DEBUG` | `logging.debug()` | The lowest level. Used for small details. Usually you care about these messages only when diagnosing problems. | | `INFO` | `logging.info()` | Used to record information on general events in your program or confirm that things are working at their point in the program. | | `WARNING` | `logging.warning()` | Used to indicate a potential problem that doesn’t prevent the program from working but might do so in the future. | | `ERROR` | `logging.error()` | Used to record an error that caused the program to fail to do something. | | `CRITICAL` | `logging.critical()` | The highest level. Used to indicate a fatal error that has caused or is about to cause the program to stop running entirely. | ### Disabling Logging After you’ve debugged your program, you probably don’t want all these log messages cluttering the screen. The logging.disable() function disables these so that you don’t have to go into your program and remove all the logging calls by hand. ```python >>> import logging >>> logging.basicConfig(level=logging.INFO, format=' %(asctime)s -%(levelname)s - %(message)s') >>> logging.critical('Critical error! Critical error!') 2015-05-22 11:10:48,054 - CRITICAL - Critical error! Critical error! >>> logging.disable(logging.CRITICAL) >>> logging.critical('Critical error! Critical error!') >>> logging.error('Error! Error!') ``` ### Logging to a File Instead of displaying the log messages to the screen, you can write them to a text file. The logging.basicConfig() function takes a filename keyword argument, like so: ```python import logging logging.basicConfig(filename='myProgramLog.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') ``` ## Lambda Functions This function: ```python >>> def add(x, y): return x + y >>> add(5, 3) 8 ``` Is equivalent to the *lambda* function: ```python >>> add = lambda x, y: x + y >>> add(5, 3) 8 ``` It's not even need to bind it to a name like add before: ```python >>> (lambda x, y: x + y)(5, 3) 8 ``` Like regular nested functions, lambdas also work as lexical closures: ```python >>> def make_adder(n): return lambda x: x + n >>> plus_3 = make_adder(3) >>> plus_5 = make_adder(5) >>> plus_3(4) 7 >>> plus_5(4) 9 ``` Note: lambda can only evaluate an expression, like a single line of code. ## Ternary Conditional Operator Many programming languages have a ternary operator, which define a conditional expression. The most common usage is to make a terse simple conditional assignment statement. In other words, it offers one-line code to evaluate the first expression if the condition is true, otherwise it evaluates the second expression. if else Example: ```python >>> age = 15 >>> print('kid' if age < 18 else 'adult') kid ``` Ternary operators can be changed: ```python >>> age = 15 >>> print('kid' if age < 13 else 'teenager' if age < 18 else 'adult') teenager ``` The code above is equivalent to: ```python if age < 18: if age < 12: print('kid') else: print('teenager') else: print('adult') ``` ## args and kwargs The names ```args and kwargs``` are arbitrary - the important thing are the ```*``` and ```**``` operators. They can mean: 1. In a function declaration, ```*``` means “pack all remaining positional arguments into a tuple named ``”, while ```**``` is the same for keyword arguments (except it uses a dictionary, not a tuple). 2. In a function call, ```*``` means “unpack tuple or list named `` to positional arguments at this position”, while ```**``` is the same for keyword arguments. For example you can make a function that you can use to call any other function, no matter what parameters it has: ```python def forward(f, *args, **kwargs): return f(*args, **kwargs) ``` Inside forward, args is a tuple (of all positional arguments except the first one, because we specified it - the f), kwargs is a dict. Then we call f and unpack them so they become normal arguments to f. You use ```*args``` when you have an indefinite amount of positional arguments. ```python >>> def fruits(*args): >>> for fruit in args: >>> print(fruit) >>> fruits("apples", "bananas", "grapes") "apples" "bananas" "grapes" ``` Similarly, you use ```**kwargs``` when you have an indefinite number of keyword arguments. ```python >>> def fruit(**kwargs): >>> for key, value in kwargs.items(): >>> print("{0}: {1}".format(key, value)) >>> fruit(name = "apple", color = "red") name: apple color: red ``` ```python >>> def show(arg1, arg2, *args, kwarg1=None, kwarg2=None, **kwargs): >>> print(arg1) >>> print(arg2) >>> print(args) >>> print(kwarg1) >>> print(kwarg2) >>> print(kwargs) >>> data1 = [1,2,3] >>> data2 = [4,5,6] >>> data3 = {'a':7,'b':8,'c':9} >>> show(*data1,*data2, kwarg1="python",kwarg2="cheatsheet",**data3) 1 2 (3, 4, 5, 6) python cheatsheet {'a': 7, 'b': 8, 'c': 9} >>> show(*data1, *data2, **data3) 1 2 (3, 4, 5, 6) None None {'a': 7, 'b': 8, 'c': 9} # If you do not specify ** for kwargs >>> show(*data1, *data2, *data3) 1 2 (3, 4, 5, 6, "a", "b", "c") None None {} ``` ### Thinks to Remember(args) 1. Functions can accept a variable number of positional arguments by using ```*args``` in the def statement. 2. You can use the items from a sequence as the positional arguments for a function with the ```*``` operator. 3. Using the ```*``` operator with a generator may cause your program to run out of memory and crash. 4. Adding new positional parameters to functions that accept ```*args``` can introduce hard-to-find bugs. ### Thinks to remember(kwargs) 1. Function arguments can be specified by position or by keyword. 2. Keywords make it clear what the purpose of each argument is when it would be confusing with only positional arguments. 3. Keyword arguments with default values make it easy to add new behaviors to a function, especially when the function has existing callers. 4. Optional keyword arguments should always be passed by keyword instead of by position. ## Context Manager While Python's context managers are widely used, few understand the purpose behind their use. These statements, commonly used with reading and writing files, assist the application in conserving system memory and improve resource management by ensuring specific resources are only in use for certain processes. ### with statement A context manager is an object that is notified when a context (a block of code) starts and ends. You commonly use one with the with statement. It takes care of the notifying. For example, file objects are context managers. When a context ends, the file object is closed automatically: ```python >>> with open(filename) as f: >>> file_contents = f.read() # the open_file object has automatically been closed. ``` Anything that ends execution of the block causes the context manager's exit method to be called. This includes exceptions, and can be useful when an error causes you to prematurely exit from an open file or connection. Exiting a script without properly closing files/connections is a bad idea, that may cause data loss or other problems. By using a context manager you can ensure that precautions are always taken to prevent damage or loss in this way. ### Writing your own contextmanager using generator syntax It is also possible to write a context manager using generator syntax thanks to the ```contextlib.contextmanager``` decorator: ```python >>> import contextlib >>> @contextlib.contextmanager ... def context_manager(num): ... print('Enter') ... yield num + 1 ... print('Exit') >>> with context_manager(2) as cm: ... # the following instructions are run when the 'yield' point of the context ... # manager is reached. ... # 'cm' will have the value that was yielded ... print('Right in the middle with cm = {}'.format(cm)) Enter Right in the middle with cm = 3 Exit >>> ``` ## `__main__` Top-level script environment `__main__` is the name of the scope in which top-level code executes. A module’s __name__ is set equal to `__main__` when read from standard input, a script, or from an interactive prompt. A module can discover whether or not it is running in the main scope by checking its own `__name__`, which allows a common idiom for conditionally executing code in a module when it is run as a script or with `python -m` but not when it is imported: ```python >>> if __name__ == "__main__": ... # execute only if run as a script ... main() ``` For a package, the same effect can be achieved by including a __main__.py module, the contents of which will be executed when the module is run with -m. For example we are developing script which is designed to be used as module, we should do: ```python >>> # Python program to execute function directly >>> def add(a, b): ... return a+b ... >>> add(10, 20) # we can test it by calling the function save it as calculate.py 30 >>> # Now if we want to use that module by importing we have to comment out our call, >>> # Instead we can write like this in calculate.py >>> if __name__ == "__main__": ... add(3, 5) ... >>> import calculate >>> calculate.add(3, 5) 8 ``` ### Advantages 1. Every Python module has it’s `__name__` defined and if this is `__main__`, it implies that the module is being run standalone by the user and we can do corresponding appropriate actions. 2. If you import this script as a module in another script, the __name__ is set to the name of the script/module. 3. Python files can act as either reusable modules, or as standalone programs. 4. if `__name__ == “main”:` is used to execute some code only if the file was run directly, and not imported. ## setup.py The setup script is the centre of all activity in building, distributing, and installing modules using the Distutils. The main purpose of the setup script is to describe your module distribution to the Distutils, so that the various commands that operate on your modules do the right thing. The `setup.py` file is at the heart of a Python project. It describes all of the metadata about your project. There a quite a few fields you can add to a project to give it a rich set of metadata describing the project. However, there are only three required fields: name, version, and packages. The name field must be unique if you wish to publish your package on the Python Package Index (PyPI). The version field keeps track of different releases of the project. The packages field describes where you’ve put the Python source code within your project. This allows you to easily install Python packages. Often it's enough to write: ```bash python setup.py install ``` and module will install itself. Our initial setup.py will also include information about the license and will re-use the README.txt file for the long_description field. This will look like: ```python >>> from distutils.core import setup >>> setup( ... name='pythonCheatsheet', ... version='0.1', ... packages=['pipenv',], ... license='MIT', ... long_description=open('README.txt').read(), ... ) ``` Find more information visit [http://docs.python.org/install/index.html](http://docs.python.org/install/index.html). ## Dataclasses `Dataclasses` are python classes but are suited for storing data objects. This module provides a decorator and functions for automatically adding generated special methods such as `__init__()` and `__repr__()` to user-defined classes. ### Features 1. They store data and represent a certain data type. Ex: A number. For people familiar with ORMs, a model instance is a data object. It represents a specific kind of entity. It holds attributes that define or represent the entity. 2. They can be compared to other objects of the same type. Ex: A number can be greater than, less than, or equal to another number. Python 3.7 provides a decorator dataclass that is used to convert a class into a dataclass. python 2.7 ```python >>> class Number: ... def __init__(self, val): ... self.val = val ... >>> obj = Number(2) >>> obj.val 2 ``` with dataclass ```python >>> @dataclass ... class Number: ... val: int ... >>> obj = Number(2) >>> obj.val 2 ``` ### Default values It is easy to add default values to the fields of your data class. ```python >>> @dataclass ... class Product: ... name: str ... count: int = 0 ... price: float = 0.0 ... >>> obj = Product("Python") >>> obj.name Python >>> obj.count 0 >>> obj.price 0.0 ``` ### Type hints It is mandatory to define the data type in dataclass. However, If you don't want specify the datatype then, use ```typing.Any```. ```python >>> from dataclasses import dataclass >>> from typing import Any >>> @dataclass ... class WithoutExplicitTypes: ... name: Any ... value: Any = 42 ... ``` ## Virtual Environment The use of a Virtual Environment is to test python code in encapsulated environments and to also avoid filling the base Python installation with libraries we might use for only one project. ### virtualenv 1. Install virtualenv pip install virtualenv 1. Install virtualenvwrapper-win (Windows) pip install virtualenvwrapper-win Usage: 1. Make a Virtual Environment mkvirtualenv HelloWold Anything we install now will be specific to this project. And available to the projects we connect to this environment. 1. Set Project Directory To bind our virtualenv with our current working directory we simply enter: setprojectdir . 1. Deactivate To move onto something else in the command line type ‘deactivate’ to deactivate your environment. deactivate Notice how the parenthesis disappear. 1. Workon Open up the command prompt and type ‘workon HelloWold’ to activate the environment and move into your root project folder workon HelloWold ### pipenv > [Pipenv](https://pipenv.readthedocs.io/en/latest/) is a tool that aims to bring the best of all packaging worlds (bundler, composer, npm, cargo, yarn, etc.) to the Python world. Windows is a first-class citizen, in our world. 1. Install pipenv pip install pipenv 1. Enter your Project directory and install the Packages for your project cd my_project pipenv install Pipenv will install your package and create a Pipfile for you in your project’s directory. The Pipfile is used to track which dependencies your project needs in case you need to re-install them. 1. Uninstall Packages pipenv uninstall 1. Activate the Virtual Environment associated with your Python project pipenv shell 1. Exit the Virtual Environment exit Find more information and a video in [docs.pipenv.org](https://docs.pipenv.org/). ### anaconda [Anaconda](https://anaconda.org/) is another popular tool to manage python packages. > Where packages, notebooks, projects and environments are shared. Your place for free public conda package hosting. Usage: 1. Make a Virtual Environment conda create -n HelloWorld 2. To use the Virtual Environment, activate it by: conda activate HelloWorld Anything installed now will be specific to the project HelloWorld 3. Exit the Virtual Environment conda deactivate ================================================ FILE: Python/pyproject.toml ================================================ [tool.poetry] name = "python-cheatsheet" version = "0.1.0" description = "" authors = ["'Carlos <'carlos.w.montecinos@gmail.com'>"] [tool.poetry.dependencies] python = "*" notedown = "^1.5" [tool.poetry.dev-dependencies] ================================================ FILE: Python/python_cheat_sheet.ipynb ================================================ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# About [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/wilfredinni/python-cheatsheet/master)\n", "\n", "Basic cheatsheet for Python mostly based on the book written by Al Sweigart, [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/) under the [Creative Commons license](https://creativecommons.org/licenses/by-nc-sa/3.0/) and many other sources.\n", "\n", "## Contribute\n", "\n", "All contributions are welcome:\n", "\n", "- Read the issues, Fork the project and do a Pull Request.\n", "- Request a new topic creating a `New issue` with the `enhancement` tag.\n", "- Find any kind of errors in the cheat sheet and create a `New issue` with the details or fork the project and do a Pull Request.\n", "- Suggest a better or more pythonic way for existing examples.\n", "\n", "## Read It\n", "\n", "- [Website](https://www.pythoncheatsheet.org)\n", "- [Github](https://github.com/wilfredinni/python-cheatsheet)\n", "- [PDF](https://github.com/wilfredinni/Python-cheatsheet/raw/master/python_cheat_sheet.pdf)\n", "- [Jupyter Notebook](https://mybinder.org/v2/gh/wilfredinni/python-cheatsheet/master?filepath=python_cheat_sheet.ipynb)\n", "\n", "## Python Cheatsheet\n", "\n", "- [The Zen of Python](#the-zen-of-python)\n", "- [Python Basics](#python-basics)\n", " - [Math Operators](#math-operators)\n", " - [Data Types](#data-types)\n", " - [String Concatenation and Replication](#string-concatenation-and-replication)\n", " - [Variables](#variables)\n", " - [Comments](#comments)\n", " - [The print() Function](#the-print-function)\n", " - [The input() Function](#the-input-function)\n", " - [The len() Function](#the-len-function)\n", " - [The str(), int(), and float() Functions](#the-str-int-and-float-functions)\n", "- [Flow Control](#flow-control)\n", " - [Comparison Operators](#comparison-operators)\n", " - [Boolean evaluation](#boolean-evaluation)\n", " - [Boolean Operators](#boolean-operators)\n", " - [Mixing Boolean and Comparison Operators](#mixing-boolean-and-comparison-operators)\n", " - [if Statements](#if-statements)\n", " - [else Statements](#else-statements)\n", " - [elif Statements](#elif-statements)\n", " - [while Loop Statements](#while-loop-statements)\n", " - [break Statements](#break-statements)\n", " - [continue Statements](#continue-statements)\n", " - [for Loops and the range() Function](#for-loops-and-the-range-function)\n", " - [For else statement](#for-else-statement)\n", " - [Importing Modules](#importing-modules)\n", " - [Ending a Program Early with sys.exit()](#ending-a-program-early-with-sysexit)\n", "- [Functions](#functions)\n", " - [Return Values and return Statements](#return-values-and-return-statements)\n", " - [The None Value](#the-none-value)\n", " - [Keyword Arguments and print()](#keyword-arguments-and-print)\n", " - [Local and Global Scope](#local-and-global-scope)\n", " - [The global Statement](#the-global-statement)\n", "- [Exception Handling](#exception-handling)\n", " - [Basic exception handling](#basic-exception-handling)\n", " - [Final code in exception handling](#final-code-in-exception-handling)\n", "- [Lists](#lists)\n", " - [Getting Individual Values in a List with Indexes](#getting-individual-values-in-a-list-with-indexes)\n", " - [Negative Indexes](#negative-indexes)\n", " - [Getting Sublists with Slices](#getting-sublists-with-slices)\n", " - [Getting a List’s Length with len()](#getting-a-list%E2%80%99s-length-with-len)\n", " - [Changing Values in a List with Indexes](#changing-values-in-a-list-with-indexes)\n", " - [List Concatenation and List Replication](#list-concatenation-and-list-replication)\n", " - [Removing Values from Lists with del Statements](#removing-values-from-lists-with-del-statements)\n", " - [Using for Loops with Lists](#using-for-loops-with-lists)\n", " - [Looping Through Multiple Lists with zip()](#looping-through-multiple-lists-with-zip)\n", " - [The in and not in Operators](#the-in-and-not-in-operators)\n", " - [The Multiple Assignment Trick](#the-multiple-assignment-trick)\n", " - [Augmented Assignment Operators](#augmented-assignment-operators)\n", " - [Finding a Value in a List with the index() Method](#finding-a-value-in-a-list-with-the-index-method)\n", " - [Adding Values to Lists with the append() and insert() Methods](#adding-values-to-lists-with-the-append-and-insert-methods)\n", " - [Removing Values from Lists with remove()](#removing-values-from-lists-with-remove)\n", " - [Sorting the Values in a List with the sort() Method](#sorting-the-values-in-a-list-with-the-sort-method)\n", " - [Tuple Data Type](#tuple-data-type)\n", " - [Converting Types with the list() and tuple() Functions](#converting-types-with-the-list-and-tuple-functions)\n", "- [Dictionaries and Structuring Data](#dictionaries-and-structuring-data)\n", " - [The keys(), values(), and items() Methods](#the-keys-values-and-items-methods)\n", " - [Checking Whether a Key or Value Exists in a Dictionary](#checking-whether-a-key-or-value-exists-in-a-dictionary)\n", " - [The get() Method](#the-get-method)\n", " - [The setdefault() Method](#the-setdefault-method)\n", " - [Pretty Printing](#pretty-printing)\n", " - [Merge two dictionaries](#merge-two-dictionaries)\n", "- [sets](#sets)\n", " - [Initializing a set](#initializing-a-set)\n", " - [sets: unordered collections of unique elements](#sets-unordered-collections-of-unique-elements)\n", " - [set add() and update()](#set-add-and-update)\n", " - [set remove() and discard()](#set-remove-and-discard)\n", " - [set union()](#set-union)\n", " - [set intersection](#set-intersection)\n", " - [set difference](#set-difference)\n", " - [set symetric_difference](#set-symetricdifference)\n", "- [itertools Module](#itertools-module)\n", " - [accumulate()](#accumulate)\n", " - [combinations()](#combinations)\n", " - [combinations_with_replacement()](#combinationswithreplacement)\n", " - [count()](#count)\n", " - [cycle()](#cycle)\n", " - [chain()](#chain)\n", " - [compress()](#compress)\n", " - [dropwhile()](#dropwhile)\n", " - [filterfalse()](#filterfalse)\n", " - [groupby()](#groupby)\n", " - [islice()](#islice)\n", " - [permutations()](#permutations)\n", " - [product()](#product)\n", " - [repeat()](#repeat)\n", " - [starmap()](#starmap)\n", " - [takewhile()](#takewhile)\n", " - [tee()](#tee)\n", " - [zip_longest()](#ziplongest)\n", "- [Comprehensions](#comprehensions)\n", " - [List comprehension](#list-comprehension)\n", " - [Set comprehension](#set-comprehension)\n", " - [Dict comprehension](#dict-comprehension)\n", "- [Manipulating Strings](#manipulating-strings)\n", " - [Escape Characters](#escape-characters)\n", " - [Raw Strings](#raw-strings)\n", " - [Multiline Strings with Triple Quotes](#multiline-strings-with-triple-quotes)\n", " - [Indexing and Slicing Strings](#indexing-and-slicing-strings)\n", " - [The in and not in Operators with Strings](#the-in-and-not-in-operators-with-strings)\n", " - [The in and not in Operators with list](#the-in-and-not-in-operators-with-list)\n", " - [The upper(), lower(), isupper(), and islower() String Methods](#the-upper-lower-isupper-and-islower-string-methods)\n", " - [The isX String Methods](#the-isx-string-methods)\n", " - [The startswith() and endswith() String Methods](#the-startswith-and-endswith-string-methods)\n", " - [The join() and split() String Methods](#the-join-and-split-string-methods)\n", " - [Justifying Text with rjust(), ljust(), and center()](#justifying-text-with-rjust-ljust-and-center)\n", " - [Removing Whitespace with strip(), rstrip(), and lstrip()](#removing-whitespace-with-strip-rstrip-and-lstrip)\n", " - [Copying and Pasting Strings with the pyperclip Module (need pip install)](#copying-and-pasting-strings-with-the-pyperclip-module-need-pip-install)\n", "- [String Formatting](#string-formatting)\n", " - [% operator](#operator)\n", " - [String Formatting (str.format)](#string-formatting-strformat)\n", " - [Lazy string formatting](#lazy-string-formatting)\n", " - [Formatted String Literals or f-strings (Python 3.6+)](#formatted-string-literals-or-f-strings-python-36)\n", " - [Template Strings](#template-strings)\n", "- [Regular Expressions](#regular-expressions)\n", " - [Matching Regex Objects](#matching-regex-objects)\n", " - [Grouping with Parentheses](#grouping-with-parentheses)\n", " - [Matching Multiple Groups with the Pipe](#matching-multiple-groups-with-the-pipe)\n", " - [Optional Matching with the Question Mark](#optional-matching-with-the-question-mark)\n", " - [Matching Zero or More with the Star](#matching-zero-or-more-with-the-star)\n", " - [Matching One or More with the Plus](#matching-one-or-more-with-the-plus)\n", " - [Matching Specific Repetitions with Curly Brackets](#matching-specific-repetitions-with-curly-brackets)\n", " - [Greedy and Nongreedy Matching](#greedy-and-nongreedy-matching)\n", " - [The findall() Method](#the-findall-method)\n", " - [Making Your Own Character Classes](#making-your-own-character-classes)\n", " - [The Caret and Dollar Sign Characters](#the-caret-and-dollar-sign-characters)\n", " - [The Wildcard Character](#the-wildcard-character)\n", " - [Matching Everything with Dot-Star](#matching-everything-with-dot-star)\n", " - [Matching Newlines with the Dot Character](#matching-newlines-with-the-dot-character)\n", " - [Review of Regex Symbols](#review-of-regex-symbols)\n", " - [Case-Insensitive Matching](#case-insensitive-matching)\n", " - [Substituting Strings with the sub() Method](#substituting-strings-with-the-sub-method)\n", " - [Managing Complex Regexes](#managing-complex-regexes)\n", "- [Handling File and Directory Paths](#handling-file-and-directory-paths)\n", " - [Backslash on Windows and Forward Slash on OS X and Linux](#backslash-on-windows-and-forward-slash-on-os-x-and-linux)\n", " - [The Current Working Directory](#the-current-working-directory)\n", " - [Creating New Folders](#creating-new-folders)\n", " - [Absolute vs. Relative Paths](#absolute-vs-relative-paths)\n", " - [Handling Absolute and Relative Paths](#handling-absolute-and-relative-paths)\n", " - [Checking Path Validity](#checking-path-validity)\n", " - [Finding File Sizes and Folder Contents](#finding-file-sizes-and-folder-contents)\n", " - [Copying Files and Folders](#copying-files-and-folders)\n", " - [Moving and Renaming Files and Folders](#moving-and-renaming-files-and-folders)\n", " - [Permanently Deleting Files and Folders](#permanently-deleting-files-and-folders)\n", " - [Safe Deletes with the send2trash Module](#safe-deletes-with-the-send2trash-module)\n", " - [Walking a Directory Tree](#walking-a-directory-tree)\n", "- [Reading and Writing Files](#reading-and-writing-files)\n", " - [The File Reading/Writing Process](#the-file-readingwriting-process)\n", " - [Opening and reading files with the open() function](#opening-and-reading-files-with-the-open-function)\n", " - [Writing to Files](#writing-to-files)\n", " - [Saving Variables with the shelve Module](#saving-variables-with-the-shelve-module)\n", " - [Saving Variables with the pprint.pformat() Function](#saving-variables-with-the-pprintpformat-function)\n", " - [Reading ZIP Files](#reading-zip-files)\n", " - [Extracting from ZIP Files](#extracting-from-zip-files)\n", " - [Creating and Adding to ZIP Files](#creating-and-adding-to-zip-files)\n", "- [JSON, YAML and configuration files](#json-yaml-and-configuration-files)\n", " - [JSON](#json)\n", " - [YAML](#yaml)\n", " - [Anyconfig](#anyconfig)\n", "- [Debugging](#debugging)\n", " - [Raising Exceptions](#raising-exceptions)\n", " - [Getting the Traceback as a String](#getting-the-traceback-as-a-string)\n", " - [Assertions](#assertions)\n", " - [Logging](#logging)\n", " - [Logging Levels](#logging-levels)\n", " - [Disabling Logging](#disabling-logging)\n", " - [Logging to a File](#logging-to-a-file)\n", "- [Lambda Functions](#lambda-functions)\n", "- [Ternary Conditional Operator](#ternary-conditional-operator)\n", "- [args and kwargs](#args-and-kwargs)\n", " - [Thinks to Remember(args)](#thinks-to-rememberargs)\n", " - [Thinks to remember(kwargs)](#thinks-to-rememberkwargs)\n", "- [Context Manager](#context-manager)\n", " - [with statement](#with-statement)\n", " - [Writing your own contextmanager using generator syntax](#writing-your-own-contextmanager-using-generator-syntax)\n", "- [`__main__` Top-level script environment](#main-top-level-script-environment)\n", " - [Advantages](#advantages)\n", "- [setup.py](#setuppy)\n", "- [Dataclasses](#dataclasses)\n", " - [Features](#features)\n", " - [Default values](#default-values)\n", " - [Type hints](#type-hints)\n", "- [Virtual Environment](#virtual-environment)\n", " - [virtualenv](#virtualenv)\n", " - [pipenv](#pipenv)\n", " - [anaconda](#anaconda)\n", "\n", "## The Zen of Python\n", "\n", "From the [PEP 20 -- The Zen of Python](https://www.python.org/dev/peps/pep-0020/):\n", "\n", "> Long time Pythoneer Tim Peters succinctly channels the BDFL's guiding principles for Python's design into 20 aphorisms, only 19 of which have been written down." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import this\n", "The Zen of Python, by Tim Peters\n", "\n", "Beautiful is better than ugly.\n", "Explicit is better than implicit.\n", "Simple is better than complex.\n", "Complex is better than complicated.\n", "Flat is better than nested.\n", "Sparse is better than dense.\n", "Readability counts.\n", "Special cases aren't special enough to break the rules.\n", "Although practicality beats purity.\n", "Errors should never pass silently.\n", "Unless explicitly silenced.\n", "In the face of ambiguity, refuse the temptation to guess.\n", "There should be one-- and preferably only one --obvious way to do it.\n", "Although that way may not be obvious at first unless you're Dutch.\n", "Now is better than never.\n", "Although never is often better than *right* now.\n", "If the implementation is hard to explain, it's a bad idea.\n", "If the implementation is easy to explain, it may be a good idea.\n", "Namespaces are one honking great idea -- let's do more of those!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Python Basics\n", "\n", "### Math Operators\n", "\n", "From **Highest** to **Lowest** precedence:\n", "\n", "| Operators | Operation | Example |\n", "| --------- | ---------------- | --------------- |\n", "| ** | Exponent | `2 ** 3 = 8` |\n", "| % | Modulus/Remaider | `22 % 8 = 6` |\n", "| // | Integer division | `22 // 8 = 2` |\n", "| / | Division | `22 / 8 = 2.75` |\n", "| * | Multiplication | `3 * 3 = 9` |\n", "| - | Subtraction | `5 - 2 = 3` |\n", "| + | Addition | `2 + 2 = 4` |\n", "\n", "Examples of expressions in the interactive shell:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 2 + 3 * 6\n", "20" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> (2 + 3) * 6\n", "30" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 2 ** 8\n", "256" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 23 // 7\n", "3" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 23 % 7\n", "2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> (5 - 1) * ((7 + 1) / (3 - 1))\n", "16.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Data Types\n", "\n", "| Data Type | Examples |\n", "| ---------------------- | ----------------------------------------- |\n", "| Integers | `-2, -1, 0, 1, 2, 3, 4, 5` |\n", "| Floating-point numbers | `-1.25, -1.0, --0.5, 0.0, 0.5, 1.0, 1.25` |\n", "| Strings | `'a', 'aa', 'aaa', 'Hello!', '11 cats'` |\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### String Concatenation and Replication\n", "\n", "String concatenation:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Alice' 'Bob'\n", "'AliceBob'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: Avoid `+` operator for string concatenation. Prefer string formatting.\n", "\n", "String Replication:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Alice' * 5\n", "'AliceAliceAliceAliceAlice'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Variables\n", "\n", "You can name a variable anything as long as it obeys the following three rules:\n", "\n", "1. It can be only one word.\n", "1. It can use only letters, numbers, and the underscore (`_`) character.\n", "1. It can’t begin with a number.\n", "1. Variable name starting with an underscore (`_`) are considered as \"unuseful`.\n", "\n", "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = 'Hello'\n", ">>> spam\n", "'Hello'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> _spam = 'Hello'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`_spam` should not be used again in the code.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Comments\n", "\n", "Inline comment:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# This is a comment" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Multiline comment:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "attributes": { "classes": [ "Python" ], "id": "" } }, "outputs": [], "source": [ "# This is a\n", "# multiline comment" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Code with a comment:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 1 # initialization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Please note the two spaces in front of the comment.\n", "\n", "Function docstring:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def foo():\n", " \"\"\"\n", " This is a function docstring\n", " You can also use:\n", " ''' Function Docstring '''\n", " \"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The print() Function" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print('Hello world!')\n", "Hello world!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> a = 1\n", ">>> print('Hello world!', a)\n", "Hello world! 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The input() Function\n", "\n", "Example Code:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print('What is your name?') # ask for their name\n", ">>> myName = input()\n", ">>> print('It is good to meet you, {}'.format(myName))\n", "What is your name?\n", "Al\n", "It is good to meet you, Al" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The len() Function\n", "\n", "Evaluates to the integer value of the number of characters in a string:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> len('hello')\n", "5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: test of emptiness of strings, lists, dictionary, etc, should **not** use len, but prefer direct\n", "boolean evaluation." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> a = [1, 2, 3]\n", ">>> if a:\n", ">>> print(\"the list is not empty!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The str(), int(), and float() Functions\n", "\n", "Integer to String or Float:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> str(29)\n", "'29'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print('I am {} years old.'.format(str(29)))\n", "I am 29 years old." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> str(-3.14)\n", "'-3.14'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Float to Integer:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> int(7.7)\n", "7" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> int(7.7) + 1\n", "8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Flow Control\n", "\n", "### Comparison Operators\n", "\n", "| Operator | Meaning |\n", "| -------- | ------------------------ |\n", "| `==` | Equal to |\n", "| `!=` | Not equal to |\n", "| `<` | Less than |\n", "| `>` | Greater Than |\n", "| `<=` | Less than or Equal to |\n", "| `>=` | Greater than or Equal to |\n", "\n", "These operators evaluate to True or False depending on the values you give them.\n", "\n", "Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 42 == 42\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 40 == 42\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'hello' == 'hello'\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'hello' == 'Hello'\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'dog' != 'cat'\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 42 == 42.0\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 42 == '42'\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Boolean evaluation\n", "\n", "Never use `==` or `!=` operator to evaluate boolean operation. Use the `is` or `is not` operators,\n", "or use implicit boolean evaluation.\n", "\n", "NO (even if they are valid Python):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> True == True\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> True != False\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "YES (even if they are valid Python):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> True is True\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> True is not False\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These statements are equivalent:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "attributes": { "classes": [ "Python" ], "id": "" } }, "outputs": [], "source": [ ">>> if a is True:\n", ">>> pass\n", ">>> if a is not False:\n", ">>> pass\n", ">>> if a:\n", ">>> pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And these as well:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "attributes": { "classes": [ "Python" ], "id": "" } }, "outputs": [], "source": [ ">>> if a is False:\n", ">>> pass\n", ">>> if a is not True:\n", ">>> pass\n", ">>> if not a:\n", ">>> pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Boolean Operators\n", "\n", "There are three Boolean operators: and, or, and not.\n", "\n", "The *and* Operator’s *Truth* Table:\n", "\n", "| Expression | Evaluates to |\n", "| ----------------- | ------------ |\n", "| `True and True` | `True` |\n", "| `True and False` | `False` |\n", "| `False and True` | `False` |\n", "| `False and False` | `False` |\n", "\n", "The *or* Operator’s *Truth* Table:\n", "\n", "| Expression | Evaluates to |\n", "| ---------------- | ------------ |\n", "| `True or True` | `True` |\n", "| `True or False` | `True` |\n", "| `False or True` | `True` |\n", "| `False or False` | `False` |\n", "\n", "The *not* Operator’s *Truth* Table:\n", "\n", "| Expression | Evaluates to |\n", "| ----------- | ------------ |\n", "| `not True` | `False` |\n", "| `not False` | `True` |\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Mixing Boolean and Comparison Operators" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> (4 < 5) and (5 < 6)\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> (4 < 5) and (9 < 6)\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> (1 == 2) or (2 == 2)\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also use multiple Boolean operators in an expression, along with the comparison operators:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 2 + 2 == 4 and not 2 + 2 == 5 and 2 * 2 == 2 + 2\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### if Statements" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if name == 'Alice':\n", " print('Hi, Alice.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### else Statements" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "name = 'Bob'\n", "if name == 'Alice':\n", " print('Hi, Alice.')\n", "else:\n", " print('Hello, stranger.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### elif Statements" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "name = 'Bob'\n", "age = 5\n", "if name == 'Alice':\n", " print('Hi, Alice.')\n", "elif age < 12:\n", " print('You are not Alice, kiddo.')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "name = 'Bob'\n", "age = 30\n", "if name == 'Alice':\n", " print('Hi, Alice.')\n", "elif age < 12:\n", " print('You are not Alice, kiddo.')\n", "else:\n", " print('You are neither Alice nor a little kid.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### while Loop Statements" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "spam = 0\n", "while spam < 5:\n", " print('Hello, world.')\n", " spam = spam + 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### break Statements\n", "\n", " If the execution reaches a break statement, it immediately exits the while loop’s clause:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "while True:\n", " print('Please type your name.')\n", " name = input()\n", " if name == 'your name':\n", " break\n", "print('Thank you!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### continue Statements\n", "\n", "When the program execution reaches a continue statement, the program execution immediately jumps back to the start of the loop." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "while True:\n", " print('Who are you?')\n", " name = input()\n", " if name != 'Joe':\n", " continue\n", " print('Hello, Joe. What is the password? (It is a fish.)')\n", " password = input()\n", " if password == 'swordfish':\n", " break\n", "print('Access granted.')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### for Loops and the range() Function" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print('My name is')\n", ">>> for i in range(5):\n", ">>> print('Jimmy Five Times ({})'.format(str(i)))\n", "My name is\n", "Jimmy Five Times (0)\n", "Jimmy Five Times (1)\n", "Jimmy Five Times (2)\n", "Jimmy Five Times (3)\n", "Jimmy Five Times (4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The *range()* function can also be called with three arguments. The first two arguments will be the start and stop values, and the third will be the step argument. The step is the amount that the variable is increased by after each iteration." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> for i in range(0, 10, 2):\n", ">>> print(i)\n", "0\n", "2\n", "4\n", "6\n", "8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can even use a negative number for the step argument to make the for loop count down instead of up." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> for i in range(5, -1, -1):\n", ">>> print(i)\n", "5\n", "4\n", "3\n", "2\n", "1\n", "0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### For else statement\n", "\n", "This allows to specify a statement to execute in case of the full loop has been executed. Only\n", "useful when a `break` condition can occur in the loop:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> for i in [1, 2, 3, 4, 5]:\n", ">>> if i == 3:\n", ">>> break\n", ">>> else:\n", ">>> print(\"only executed when no item of the list is equal to 3\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Importing Modules" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import random\n", "for i in range(5):\n", " print(random.randint(1, 10))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import random, sys, os, math" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from random import *." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Ending a Program Early with sys.exit()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sys\n", "\n", "while True:\n", " print('Type exit to exit.')\n", " response = input()\n", " if response == 'exit':\n", " sys.exit()\n", " print('You typed {}.'.format(response))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Functions" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def hello(name):\n", ">>> print('Hello {}'.format(name))\n", ">>>\n", ">>> hello('Alice')\n", ">>> hello('Bob')\n", "Hello Alice\n", "Hello Bob" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Return Values and return Statements\n", "\n", "When creating a function using the def statement, you can specify what the return value should be with a return statement. A return statement consists of the following:\n", "\n", "- The return keyword.\n", "\n", "- The value or expression that the function should return." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import random\n", "def getAnswer(answerNumber):\n", " if answerNumber == 1:\n", " return 'It is certain'\n", " elif answerNumber == 2:\n", " return 'It is decidedly so'\n", " elif answerNumber == 3:\n", " return 'Yes'\n", " elif answerNumber == 4:\n", " return 'Reply hazy try again'\n", " elif answerNumber == 5:\n", " return 'Ask again later'\n", " elif answerNumber == 6:\n", " return 'Concentrate and ask again'\n", " elif answerNumber == 7:\n", " return 'My reply is no'\n", " elif answerNumber == 8:\n", " return 'Outlook not so good'\n", " elif answerNumber == 9:\n", " return 'Very doubtful'\n", "\n", "r = random.randint(1, 9)\n", "fortune = getAnswer(r)\n", "print(fortune)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The None Value" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = print('Hello!')\n", "Hello!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam is None\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: never compare to `None` with the `==` operator. Always use `is`.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Keyword Arguments and print()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print('Hello', end='')\n", ">>> print('World')\n", "HelloWorld" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print('cats', 'dogs', 'mice')\n", "cats dogs mice" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print('cats', 'dogs', 'mice', sep=',')\n", "cats,dogs,mice" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Local and Global Scope\n", "\n", "- Code in the global scope cannot use any local variables.\n", "\n", "- However, a local scope can access global variables.\n", "\n", "- Code in a function’s local scope cannot use variables in any other local scope.\n", "\n", "- You can use the same name for different variables if they are in different scopes. That is, there can be a local variable named spam and a global variable also named spam.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The global Statement\n", "\n", "If you need to modify a global variable from within a function, use the global statement:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def spam():\n", ">>> global eggs\n", ">>> eggs = 'spam'\n", ">>>\n", ">>> eggs = 'global'\n", ">>> spam()\n", ">>> print(eggs)\n", "spam" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are four rules to tell whether a variable is in a local scope or global scope:\n", "\n", "1. If a variable is being used in the global scope (that is, outside of all functions), then it is always a global variable.\n", "\n", "1. If there is a global statement for that variable in a function, it is a global variable.\n", "\n", "1. Otherwise, if the variable is used in an assignment statement in the function, it is a local variable.\n", "\n", "1. But if the variable is not used in an assignment statement, it is a global variable.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Exception Handling\n", "\n", "### Basic exception handling" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def spam(divideBy):\n", ">>> try:\n", ">>> return 42 / divideBy\n", ">>> except ZeroDivisionError as e:\n", ">>> print('Error: Invalid argument: {}'.format(e))\n", ">>>\n", ">>> print(spam(2))\n", ">>> print(spam(12))\n", ">>> print(spam(0))\n", ">>> print(spam(1))\n", "21.0\n", "3.5\n", "Error: Invalid argument: division by zero\n", "None\n", "42.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Final code in exception handling\n", "\n", "Code inside the `finally` section is always executed, no matter if an exception has been raised or\n", "not, and even if an exception is not caught." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def spam(divideBy):\n", ">>> try:\n", ">>> return 42 / divideBy\n", ">>> except ZeroDivisionError as e:\n", ">>> print('Error: Invalid argument: {}'.format(e))\n", ">>> finally:\n", ">>> print(\"-- division finished --\")\n", ">>> print(spam(12))\n", ">>> print(spam(0))\n", "21.0\n", "-- division finished --\n", "3.5\n", "-- division finished --\n", "Error: Invalid argument: division by zero\n", "-- division finished --\n", "None\n", "-- division finished --\n", "42.0\n", "-- division finished --" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Lists" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'bat', 'rat', 'elephant']\n", "\n", ">>> spam\n", "['cat', 'bat', 'rat', 'elephant']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Getting Individual Values in a List with Indexes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'bat', 'rat', 'elephant']\n", ">>> spam[0]\n", "'cat'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[1]\n", "'bat'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[2]\n", "'rat'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[3]\n", "'elephant'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Negative Indexes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'bat', 'rat', 'elephant']\n", ">>> spam[-1]\n", "'elephant'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[-3]\n", "'bat'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'The {} is afraid of the {}.'.format(spam[-1], spam[-3])\n", "'The elephant is afraid of the bat.'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Getting Sublists with Slices" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'bat', 'rat', 'elephant']\n", ">>> spam[0:4]\n", "['cat', 'bat', 'rat', 'elephant']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[1:3]\n", "['bat', 'rat']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[0:-1]\n", "['cat', 'bat', 'rat']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'bat', 'rat', 'elephant']\n", ">>> spam[:2]\n", "['cat', 'bat']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[1:]\n", "['bat', 'rat', 'elephant']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Slicing the complete list will perform a copy:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam2 = spam[:]\n", "['cat', 'bat', 'rat', 'elephant']\n", ">>> spam.append('dog')\n", ">>> spam\n", "['cat', 'bat', 'rat', 'elephant', 'dog']\n", ">>> spam2\n", "['cat', 'bat', 'rat', 'elephant']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Getting a List’s Length with len()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'dog', 'moose']\n", ">>> len(spam)\n", "3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Changing Values in a List with Indexes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'bat', 'rat', 'elephant']\n", ">>> spam[1] = 'aardvark'\n", "\n", ">>> spam\n", "['cat', 'aardvark', 'rat', 'elephant']\n", "\n", ">>> spam[2] = spam[1]\n", "\n", ">>> spam\n", "['cat', 'aardvark', 'aardvark', 'elephant']\n", "\n", ">>> spam[-1] = 12345\n", "\n", ">>> spam\n", "['cat', 'aardvark', 'aardvark', 12345]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### List Concatenation and List Replication" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> [1, 2, 3] + ['A', 'B', 'C']\n", "[1, 2, 3, 'A', 'B', 'C']\n", "\n", ">>> ['X', 'Y', 'Z'] * 3\n", "['X', 'Y', 'Z', 'X', 'Y', 'Z', 'X', 'Y', 'Z']\n", "\n", ">>> spam = [1, 2, 3]\n", "\n", ">>> spam = spam + ['A', 'B', 'C']\n", "\n", ">>> spam\n", "[1, 2, 3, 'A', 'B', 'C']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Removing Values from Lists with del Statements" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'bat', 'rat', 'elephant']\n", ">>> del spam[2]\n", ">>> spam\n", "['cat', 'bat', 'elephant']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> del spam[2]\n", ">>> spam\n", "['cat', 'bat']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Using for Loops with Lists" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> supplies = ['pens', 'staplers', 'flame-throwers', 'binders']\n", ">>> for i, supply in enumerate(supplies):\n", ">>> print('Index {} in supplies is: {}'.format(str(i), supply))\n", "Index 0 in supplies is: pens\n", "Index 1 in supplies is: staplers\n", "Index 2 in supplies is: flame-throwers\n", "Index 3 in supplies is: binders" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Looping Through Multiple Lists with zip()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> name = ['Pete', 'John', 'Elizabeth']\n", ">>> age = [6, 23, 44]\n", ">>> for n, a in zip(name, age):\n", ">>> print('{} is {} years old'.format(n, a))\n", "Pete is 6 years old\n", "John is 23 years old\n", "Elizabeth is 44 years old" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The in and not in Operators" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'howdy' in ['hello', 'hi', 'howdy', 'heyas']\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['hello', 'hi', 'howdy', 'heyas']\n", ">>> 'cat' in spam\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'howdy' not in spam\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'cat' not in spam\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The Multiple Assignment Trick\n", "\n", "The multiple assignment trick is a shortcut that lets you assign multiple variables with the values in a list in one line of code. So instead of doing this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> cat = ['fat', 'orange', 'loud']\n", "\n", ">>> size = cat[0]\n", "\n", ">>> color = cat[1]\n", "\n", ">>> disposition = cat[2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You could type this line of code:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> cat = ['fat', 'orange', 'loud']\n", "\n", ">>> size, color, disposition = cat" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The multiple assignment trick can also be used to swap the values in two variables:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> a, b = 'Alice', 'Bob'\n", ">>> a, b = b, a\n", ">>> print(a)\n", "'Bob'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print(b)\n", "'Alice'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Augmented Assignment Operators\n", "\n", "| Operator | Equivalent |\n", "| ----------- | ----------------- |\n", "| `spam += 1` | `spam = spam + 1` |\n", "| `spam -= 1` | `spam = spam - 1` |\n", "| `spam *= 1` | `spam = spam * 1` |\n", "| `spam /= 1` | `spam = spam / 1` |\n", "| `spam %= 1` | `spam = spam % 1` |\n", "\n", "Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = 'Hello'\n", ">>> spam += ' world!'\n", ">>> spam\n", "'Hello world!'\n", "\n", ">>> bacon = ['Zophie']\n", ">>> bacon *= 3\n", ">>> bacon\n", "['Zophie', 'Zophie', 'Zophie']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Finding a Value in a List with the index() Method" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['Zophie', 'Pooka', 'Fat-tail', 'Pooka']\n", "\n", ">>> spam.index('Pooka')\n", "1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Adding Values to Lists with the append() and insert() Methods\n", "\n", "**append()**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'dog', 'bat']\n", "\n", ">>> spam.append('moose')\n", "\n", ">>> spam\n", "['cat', 'dog', 'bat', 'moose']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**insert()**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'dog', 'bat']\n", "\n", ">>> spam.insert(1, 'chicken')\n", "\n", ">>> spam\n", "['cat', 'chicken', 'dog', 'bat']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Removing Values from Lists with remove()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['cat', 'bat', 'rat', 'elephant']\n", "\n", ">>> spam.remove('bat')\n", "\n", ">>> spam\n", "['cat', 'rat', 'elephant']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the value appears multiple times in the list, only the first instance of the value will be removed.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Sorting the Values in a List with the sort() Method" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = [2, 5, 3.14, 1, -7]\n", ">>> spam.sort()\n", ">>> spam\n", "[-7, 1, 2, 3.14, 5]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['ants', 'cats', 'dogs', 'badgers', 'elephants']\n", ">>> spam.sort()\n", ">>> spam\n", "['ants', 'badgers', 'cats', 'dogs', 'elephants']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also pass True for the reverse keyword argument to have sort() sort the values in reverse order:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam.sort(reverse=True)\n", ">>> spam\n", "['elephants', 'dogs', 'cats', 'badgers', 'ants']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you need to sort the values in regular alphabetical order, pass str. lower for the key keyword argument in the sort() method call:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['a', 'z', 'A', 'Z']\n", ">>> spam.sort(key=str.lower)\n", ">>> spam\n", "['a', 'A', 'z', 'Z']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can use the built-in function `sorted` to return a new list:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ['ants', 'cats', 'dogs', 'badgers', 'elephants']\n", ">>> sorted(spam)\n", "['ants', 'badgers', 'cats', 'dogs', 'elephants']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Tuple Data Type" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> eggs = ('hello', 42, 0.5)\n", ">>> eggs[0]\n", "'hello'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> eggs[1:3]\n", "(42, 0.5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> len(eggs)\n", "3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The main way that tuples are different from lists is that tuples, like strings, are immutable.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Converting Types with the list() and tuple() Functions" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> tuple(['cat', 'dog', 5])\n", "('cat', 'dog', 5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> list(('cat', 'dog', 5))\n", "['cat', 'dog', 5]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> list('hello')\n", "['h', 'e', 'l', 'l', 'o']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Dictionaries and Structuring Data\n", "\n", "Example Dictionary:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "myCat = {'size': 'fat', 'color': 'gray', 'disposition': 'loud'}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The keys(), values(), and items() Methods\n", "\n", "values():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = {'color': 'red', 'age': 42}\n", ">>> for v in spam.values():\n", ">>> print(v)\n", "red\n", "42" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "keys():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> for k in spam.keys():\n", ">>> print(k)\n", "color\n", "age" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "items():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> for i in spam.items():\n", ">>> print(i)\n", "('color', 'red')\n", "('age', 42)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using the keys(), values(), and items() methods, a for loop can iterate over the keys, values, or key-value pairs in a dictionary, respectively." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", ">>> spam = {'color': 'red', 'age': 42}\n", ">>>\n", ">>> for k, v in spam.items():\n", ">>> print('Key: {} Value: {}'.format(k, str(v)))\n", "Key: age Value: 42\n", "Key: color Value: red" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Checking Whether a Key or Value Exists in a Dictionary" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = {'name': 'Zophie', 'age': 7}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'name' in spam.keys()\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Zophie' in spam.values()\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> # You can omit the call to keys() when checking for a key\n", ">>> 'color' in spam\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'color' not in spam\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'color' in spam\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The get() Method" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> picnic_items = {'apples': 5, 'cups': 2}\n", "\n", ">>> 'I am bringing {} cups.'.format(str(picnic_items.get('cups', 0)))\n", "'I am bringing 2 cups.'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'I am bringing {} eggs.'.format(str(picnic_items.get('eggs', 0)))\n", "'I am bringing 0 eggs.'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The setdefault() Method\n", "\n", "Let's consider this code:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "spam = {'name': 'Pooka', 'age': 5}\n", "\n", "if 'color' not in spam:\n", " spam['color'] = 'black'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `setdefault` we could make the same code more shortly:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = {'name': 'Pooka', 'age': 5}\n", ">>> spam.setdefault('color', 'black')\n", "'black'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam\n", "{'color': 'black', 'age': 5, 'name': 'Pooka'}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam.setdefault('color', 'white')\n", "'black'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam\n", "{'color': 'black', 'age': 5, 'name': 'Pooka'}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Pretty Printing" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import pprint\n", ">>>\n", ">>> message = 'It was a bright cold day in April, and the clocks were striking\n", ">>> thirteen.'\n", ">>> count = {}\n", ">>>\n", ">>> for character in message:\n", ">>> count.setdefault(character, 0)\n", ">>> count[character] = count[character] + 1\n", ">>>\n", ">>> pprint.pprint(count)\n", "{' ': 13,\n", " ',': 1,\n", " '.': 1,\n", " 'A': 1,\n", " 'I': 1,\n", " 'a': 4,\n", " 'b': 1,\n", " 'c': 3,\n", " 'd': 3,\n", " 'e': 5,\n", " 'g': 2,\n", " 'h': 3,\n", " 'i': 6,\n", " 'k': 2,\n", " 'l': 3,\n", " 'n': 4,\n", " 'o': 2,\n", " 'p': 1,\n", " 'r': 5,\n", " 's': 3,\n", " 't': 6,\n", " 'w': 2,\n", " 'y': 1}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Merge two dictionaries" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# in Python 3.5+:\n", ">>> x = {'a': 1, 'b': 2}\n", ">>> y = {'b': 3, 'c': 4}\n", ">>> z = {**x, **y}\n", ">>> z\n", "{'c': 4, 'a': 1, 'b': 3}\n", "\n", "# in Python 2.7\n", ">>> z = dict(x, **y)\n", ">>> z\n", "{'c': 4, 'a': 1, 'b': 3}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## sets\n", "\n", "From the Python 3 [documentation](https://docs.python.org/3/tutorial/datastructures.html)\n", "\n", "> A set is an unordered collection with no duplicate elements. Basic uses include membership testing and eliminating duplicate entries. Set objects also support mathematical operations like union, intersection, difference, and symmetric difference.\n", "\n", "### Initializing a set\n", "\n", "There are two ways to create sets: using curly braces `{}` and the bult-in function `set()`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s = {1, 2, 3}\n", ">>> s = set([1, 2, 3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When creating an empty set, be sure to not use the curly braces `{}` or you will get an empty dictionary instead." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s = {}\n", ">>> type(s)\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### sets: unordered collections of unique elements\n", "\n", "A set automatically remove all the duplicate values." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s = {1, 2, 3, 2, 3, 4}\n", ">>> s\n", "{1, 2, 3, 4}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And as an unordered data type, they can't be indexed." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s = {1, 2, 3}\n", ">>> s[0]\n", "Traceback (most recent call last):\n", " File \"\", line 1, in \n", "TypeError: 'set' object does not support indexing\n", ">>>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### set add() and update()\n", "\n", "Using the `add()` method we can add a single element to the set." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s = {1, 2, 3}\n", ">>> s.add(4)\n", ">>> s\n", "{1, 2, 3, 4}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And with `update()`, multiple ones ." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s = {1, 2, 3}\n", ">>> s.update([2, 3, 4, 5, 6])\n", ">>> s\n", "{1, 2, 3, 4, 5, 6} # remember, sets automatically remove duplicates" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### set remove() and discard()\n", "\n", "Both methods will remove an element from the set, but `remove()` will raise a `key error` if the value doesn't exist." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s = {1, 2, 3}\n", ">>> s.remove(3)\n", ">>> s\n", "{1, 2}\n", ">>> s.remove(3)\n", "Traceback (most recent call last):\n", " File \"\", line 1, in \n", "KeyError: 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`discard()` won't raise any errors." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s = {1, 2, 3}\n", ">>> s.discard(3)\n", ">>> s\n", "{1, 2}\n", ">>> s.discard(3)\n", ">>>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### set union()\n", "\n", "`union()` or `|` will create a new set that contains all the elements from the sets provided." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s1 = {1, 2, 3}\n", ">>> s2 = {3, 4, 5}\n", ">>> s1.union(s2) # or 's1 | s2'\n", "{1, 2, 3, 4, 5}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### set intersection\n", "\n", "`intersection` or `&` will return a set containing only the elements that are common to all of them." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s1 = {1, 2, 3}\n", ">>> s2 = {2, 3, 4}\n", ">>> s3 = {3, 4, 5}\n", ">>> s1.intersection(s2, s3) # or 's1 & s2 & s3'\n", "{3}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### set difference\n", "\n", "`difference` or `-` will return only the elements that are in one of the sets." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s1 = {1, 2, 3}\n", ">>> s2 = {2, 3, 4}\n", ">>> s1.difference(s2) # or 's1 - s2'\n", "{1}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### set symetric_difference\n", "\n", "`symetric_difference` or `^` will return all the elements that are not common between them." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> s1 = {1, 2, 3}\n", ">>> s2 = {2, 3, 4}\n", ">>> s1.symmetric_difference(s2) # or 's1 ^ s2'\n", "{1, 4}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## itertools Module\n", "\n", "The *itertools* module is a colection of tools intented to be fast and use memory efficiently when handling iterators (like [lists](#lists) or [dictionaries](#dictionaries-and-structuring-data)).\n", "\n", "From the official [Python 3.x documentation](https://docs.python.org/3/library/itertools.html):\n", "\n", "> The module standardizes a core set of fast, memory efficient tools that are useful by themselves or in combination. Together, they form an “iterator algebra” making it possible to construct specialized tools succinctly and efficiently in pure Python.\n", "\n", "The *itertools* module comes in the standard library and must be imported.\n", "\n", "The [operator](https://docs.python.org/3/library/operator.html) module will also be used. This module is not necessary when using itertools, but needed for some of the examples below.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### accumulate()\n", "\n", "Makes an iterator that returns the results of a function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.accumulate(iterable[, func])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> data = [1, 2, 3, 4, 5]\n", ">>> result = itertools.accumulate(data, operator.mul)\n", ">>> for each in result:\n", ">>> print(each)\n", "1\n", "2\n", "6\n", "24\n", "120" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The operator.mul takes two numbers and multiplies them:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "operator.mul(1, 2)\n", "2\n", "operator.mul(2, 3)\n", "6\n", "operator.mul(6, 4)\n", "24\n", "operator.mul(24, 5)\n", "120" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Passing a function is optional:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> data = [5, 2, 6, 4, 5, 9, 1]\n", ">>> result = itertools.accumulate(data)\n", ">>> for each in result:\n", ">>> print(each)\n", "5\n", "7\n", "13\n", "17\n", "22\n", "31\n", "32" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If no function is designated the items will be summed:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "5\n", "5 + 2 = 7\n", "7 + 6 = 13\n", "13 + 4 = 17\n", "17 + 5 = 22\n", "22 + 9 = 31\n", "31 + 1 = 32" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### combinations()\n", "\n", "Takes an iterable and a integer. This will create all the unique combination that have r members." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.combinations(iterable, r)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> shapes = ['circle', 'triangle', 'square',]\n", ">>> result = itertools.combinations(shapes, 2)\n", ">>> for each in result:\n", ">>> print(each)\n", "('circle', 'triangle')\n", "('circle', 'square')\n", "('triangle', 'square')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### combinations_with_replacement()\n", "\n", "Just like combinations(), but allows individual elements to be repeated more than once." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.combinations_with_replacement(iterable, r)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> shapes = ['circle', 'triangle', 'square']\n", ">>> result = itertools.combinations_with_replacement(shapes, 2)\n", ">>> for each in result:\n", ">>> print(each)\n", "('circle', 'circle')\n", "('circle', 'triangle')\n", "('circle', 'square')\n", "('triangle', 'triangle')\n", "('triangle', 'square')\n", "('square', 'square')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### count()\n", "\n", "Makes an iterator that returns evenly spaced values starting with number start." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.count(start=0, step=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> for i in itertools.count(10,3):\n", ">>> print(i)\n", ">>> if i > 20:\n", ">>> break\n", "10\n", "13\n", "16\n", "19\n", "22" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### cycle()\n", "\n", "This function cycles through an iterator endlessly." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.cycle(iterable)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> colors = ['red', 'orange', 'yellow', 'green', 'blue', 'violet']\n", ">>> for color in itertools.cycle(colors):\n", ">>> print(color)\n", "red\n", "orange\n", "yellow\n", "green\n", "blue\n", "violet\n", "red\n", "orange" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When reached the end of the iterable it start over again from the beginning.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### chain()\n", "\n", "Take a series of iterables and return them as one long iterable." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.chain(*iterables)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> colors = ['red', 'orange', 'yellow', 'green', 'blue']\n", ">>> shapes = ['circle', 'triangle', 'square', 'pentagon']\n", ">>> result = itertools.chain(colors, shapes)\n", ">>> for each in result:\n", ">>> print(each)\n", "red\n", "orange\n", "yellow\n", "green\n", "blue\n", "circle\n", "triangle\n", "square\n", "pentagon" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### compress()\n", "\n", "Filters one iterable with another." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.compress(data, selectors)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> shapes = ['circle', 'triangle', 'square', 'pentagon']\n", ">>> selections = [True, False, True, False]\n", ">>> result = itertools.compress(shapes, selections)\n", ">>> for each in result:\n", ">>> print(each)\n", "circle\n", "square" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### dropwhile()\n", "\n", "Make an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every element." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.dropwhile(predicate, iterable)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1]\n", ">>> result = itertools.dropwhile(lambda x: x<5, data)\n", ">>> for each in result:\n", ">>> print(each)\n", "5\n", "6\n", "7\n", "8\n", "9\n", "10\n", "1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### filterfalse()\n", "\n", "Makes an iterator that filters elements from iterable returning only those for which the predicate is False." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.filterfalse(predicate, iterable)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n", ">>> result = itertools.filterfalse(lambda x: x<5, data)\n", ">>> for each in result:\n", ">>> print(each)\n", "5\n", "6\n", "7\n", "8\n", "9\n", "10" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### groupby()\n", "\n", "Simply put, this function groups things together." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.groupby(iterable, key=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> robots = [{\n", " 'name': 'blaster',\n", " 'faction': 'autobot'\n", "}, {\n", " 'name': 'galvatron',\n", " 'faction': 'decepticon'\n", "}, {\n", " 'name': 'jazz',\n", " 'faction': 'autobot'\n", "}, {\n", " 'name': 'metroplex',\n", " 'faction': 'autobot'\n", "}, {\n", " 'name': 'megatron',\n", " 'faction': 'decepticon'\n", "}, {\n", " 'name': 'starcream',\n", " 'faction': 'decepticon'\n", "}]\n", ">>> for key, group in itertools.groupby(robots, key=lambda x: x['faction']):\n", ">>> print(key)\n", ">>> print(list(group))\n", "autobot\n", "[{'name': 'blaster', 'faction': 'autobot'}]\n", "decepticon\n", "[{'name': 'galvatron', 'faction': 'decepticon'}]\n", "autobot\n", "[{'name': 'jazz', 'faction': 'autobot'}, {'name': 'metroplex', 'faction': 'autobot'}]\n", "decepticon\n", "[{'name': 'megatron', 'faction': 'decepticon'}, {'name': 'starcream', 'faction': 'decepticon'}]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### islice()\n", "\n", "This function is very much like slices. This allows you to cut out a piece of an iterable." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.islice(iterable, start, stop[, step])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> colors = ['red', 'orange', 'yellow', 'green', 'blue',]\n", ">>> few_colors = itertools.islice(colors, 2)\n", ">>> for each in few_colors:\n", ">>> print(each)\n", "red\n", "orange" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### permutations()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.permutations(iterable, r=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> alpha_data = ['a', 'b', 'c']\n", ">>> result = itertools.permutations(alpha_data)\n", ">>> for each in result:\n", ">>> print(each)\n", "('a', 'b', 'c')\n", "('a', 'c', 'b')\n", "('b', 'a', 'c')\n", "('b', 'c', 'a')\n", "('c', 'a', 'b')\n", "('c', 'b', 'a')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### product()\n", "\n", "Creates the cartesian products from a series of iterables." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> num_data = [1, 2, 3]\n", ">>> alpha_data = ['a', 'b', 'c']\n", ">>> result = itertools.product(num_data, alpha_data)\n", ">>> for each in result:\n", " print(each)\n", "(1, 'a')\n", "(1, 'b')\n", "(1, 'c')\n", "(2, 'a')\n", "(2, 'b')\n", "(2, 'c')\n", "(3, 'a')\n", "(3, 'b')\n", "(3, 'c')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### repeat()\n", "\n", "This function will repeat an object over and over again. Unless, there is a times argument." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.repeat(object[, times])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> for i in itertools.repeat(\"spam\", 3):\n", " print(i)\n", "spam\n", "spam\n", "spam" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### starmap()\n", "\n", "Makes an iterator that computes the function using arguments obtained from the iterable." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.starmap(function, iterable)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> data = [(2, 6), (8, 4), (7, 3)]\n", ">>> result = itertools.starmap(operator.mul, data)\n", ">>> for each in result:\n", ">>> print(each)\n", "12\n", "32\n", "21" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### takewhile()\n", "\n", "The opposite of dropwhile(). Makes an iterator and returns elements from the iterable as long as the predicate is true." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.takwwhile(predicate, iterable)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1]\n", ">>> result = itertools.takewhile(lambda x: x<5, data)\n", ">>> for each in result:\n", ">>> print(each)\n", "1\n", "2\n", "3\n", "4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### tee()\n", "\n", "Return n independent iterators from a single iterable." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.tee(iterable, n=2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> colors = ['red', 'orange', 'yellow', 'green', 'blue']\n", ">>> alpha_colors, beta_colors = itertools.tee(colors)\n", ">>> for each in alpha_colors:\n", ">>> print(each)\n", "red\n", "orange\n", "yellow\n", "green\n", "blue" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> colors = ['red', 'orange', 'yellow', 'green', 'blue']\n", ">>> alpha_colors, beta_colors = itertools.tee(colors)\n", ">>> for each in beta_colors:\n", ">>> print(each)\n", "red\n", "orange\n", "yellow\n", "green\n", "blue" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### zip_longest()\n", "\n", "Makes an iterator that aggregates elements from each of the iterables. If the iterables are of uneven length, missing values are filled-in with fillvalue. Iteration continues until the longest iterable is exhausted." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itertools.zip_longest(*iterables, fillvalue=None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> colors = ['red', 'orange', 'yellow', 'green', 'blue',]\n", ">>> data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,]\n", ">>> for each in itertools.zip_longest(colors, data, fillvalue=None):\n", ">>> print(each)\n", "('red', 1)\n", "('orange', 2)\n", "('yellow', 3)\n", "('green', 4)\n", "('blue', 5)\n", "(None, 6)\n", "(None, 7)\n", "(None, 8)\n", "(None, 9)\n", "(None, 10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Comprehensions\n", "\n", "### List comprehension" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> a = [1, 3, 5, 7, 9, 11]\n", "\n", ">>> [i - 1 for i in a]\n", "[0, 2, 4, 6, 8, 10]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Set comprehension" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> b = {\"abc\", \"def\"}\n", ">>> {s.upper() for s in b}\n", "{\"ABC\", \"DEF}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dict comprehension" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> c = {'name': 'Pooka', 'age': 5}\n", ">>> {v, k for k, v in c.items()}\n", "{'Pooka': 'name', 5: 'age'}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A List comprehension can be generated from a dictionary:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> c = {'name': 'Pooka', 'first_name': 'Oooka'}\n", ">>> [\"{}:{}\".format(k.upper(), v.upper()) for k, v in c.items()]\n", "['NAME:POOKA', 'FIRST_NAME:OOOKA']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Manipulating Strings\n", "\n", "### Escape Characters\n", "\n", "| Escape character | Prints as |\n", "| ---------------- | -------------------- |\n", "| `\\'` | Single quote |\n", "| `\\\"` | Double quote |\n", "| `\\t` | Tab |\n", "| `\\n` | Newline (line break) |\n", "| `\\\\` | Backslash |\n", "\n", "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print(\"Hello there!\\nHow are you?\\nI\\'m doing fine.\")\n", "Hello there!\n", "How are you?\n", "I'm doing fine." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Raw Strings\n", "\n", "A raw string completely ignores all escape characters and prints any backslash that appears in the string." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print(r'That is Carol\\'s cat.')\n", "That is Carol\\'s cat." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: mostly used for regular expression definition (see `re` package)\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Multiline Strings with Triple Quotes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> print('''Dear Alice,\n", ">>>\n", ">>> Eve's cat has been arrested for catnapping, cat burglary, and extortion.\n", ">>>\n", ">>> Sincerely,\n", ">>> Bob''')\n", "Dear Alice,\n", "\n", "Eve's cat has been arrested for catnapping, cat burglary, and extortion.\n", "\n", "Sincerely,\n", "Bob" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To keep a nicer flow in your code, you can use the `dedent` function from the `textwrap` standard package." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from textwrap import dedent\n", ">>>\n", ">>> def my_function():\n", ">>> print('''\n", ">>> Dear Alice,\n", ">>>\n", ">>> Eve's cat has been arrested for catnapping, cat burglary, and extortion.\n", ">>>\n", ">>> Sincerely,\n", ">>> Bob\n", ">>> ''').strip()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This generates the same string than before.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Indexing and Slicing Strings" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "H e l l o w o r l d !\n", "0 1 2 3 4 5 6 7 8 9 10 11" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = 'Hello world!'\n", "\n", ">>> spam[0]\n", "'H'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[4]\n", "'o'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[-1]\n", "'!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Slicing:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", ">>> spam[0:5]\n", "'Hello'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[:5]\n", "'Hello'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[6:]\n", "'world!'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[6:-1]\n", "'world'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[:-1]\n", "'Hello world'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam[::-1]\n", "'!dlrow olleH'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = 'Hello world!'\n", ">>> fizz = spam[0:5]\n", ">>> fizz\n", "'Hello'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The in and not in Operators with Strings" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello' in 'Hello World'\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello' in 'Hello'\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'HELLO' in 'Hello World'\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> '' in 'spam'\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'cats' not in 'cats and dogs'\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The in and not in Operators with list" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> a = [1, 2, 3, 4]\n", ">>> 5 in a\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 2 in a\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The upper(), lower(), isupper(), and islower() String Methods\n", "\n", "`upper()` and `lower()`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = 'Hello world!'\n", ">>> spam = spam.upper()\n", ">>> spam\n", "'HELLO WORLD!'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = spam.lower()\n", ">>> spam\n", "'hello world!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "isupper() and islower():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = 'Hello world!'\n", ">>> spam.islower()\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam.isupper()\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'HELLO'.isupper()\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'abc12345'.islower()\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> '12345'.islower()\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> '12345'.isupper()\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The isX String Methods\n", "\n", "- **isalpha()** returns True if the string consists only of letters and is not blank.\n", "- **isalnum()** returns True if the string consists only of lettersand numbers and is not blank.\n", "- **isdecimal()** returns True if the string consists only ofnumeric characters and is not blank.\n", "- **isspace()** returns True if the string consists only of spaces,tabs, and new-lines and is not blank.\n", "- **istitle()** returns True if the string consists only of wordsthat begin with an uppercase letter followed by onlylowercase letters.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The startswith() and endswith() String Methods" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello world!'.startswith('Hello')\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello world!'.endswith('world!')\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'abc123'.startswith('abcdef')\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'abc123'.endswith('12')\n", "False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello world!'.startswith('Hello world!')\n", "True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello world!'.endswith('Hello world!')\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The join() and split() String Methods\n", "\n", "join():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> ', '.join(['cats', 'rats', 'bats'])\n", "'cats, rats, bats'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> ' '.join(['My', 'name', 'is', 'Simon'])\n", "'My name is Simon'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'ABC'.join(['My', 'name', 'is', 'Simon'])\n", "'MyABCnameABCisABCSimon'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "split():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'My name is Simon'.split()\n", "['My', 'name', 'is', 'Simon']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'MyABCnameABCisABCSimon'.split('ABC')\n", "['My', 'name', 'is', 'Simon']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'My name is Simon'.split('m')\n", "['My na', 'e is Si', 'on']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Justifying Text with rjust(), ljust(), and center()\n", "\n", "rjust() and ljust():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello'.rjust(10)\n", "' Hello'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello'.rjust(20)\n", "' Hello'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello World'.rjust(20)\n", "' Hello World'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello'.ljust(10)\n", "'Hello '" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An optional second argument to rjust() and ljust() will specify a fill character other than a space character. Enter the following into the interactive shell:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello'.rjust(20, '*')\n", "'***************Hello'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello'.ljust(20, '-')\n", "'Hello---------------'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "center():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello'.center(20)\n", "' Hello '" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> 'Hello'.center(20, '=')\n", "'=======Hello========'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Removing Whitespace with strip(), rstrip(), and lstrip()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = ' Hello World '\n", ">>> spam.strip()\n", "'Hello World'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam.lstrip()\n", "'Hello World '" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam.rstrip()\n", "' Hello World'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> spam = 'SpamSpamBaconSpamEggsSpamSpam'\n", ">>> spam.strip('ampS')\n", "'BaconSpamEggs'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Copying and Pasting Strings with the pyperclip Module (need pip install)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import pyperclip\n", "\n", ">>> pyperclip.copy('Hello world!')\n", "\n", ">>> pyperclip.paste()\n", "'Hello world!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## String Formatting\n", "\n", "### % operator" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> name = 'Pete'\n", ">>> 'Hello %s' % name\n", "\"Hello Pete\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use the `%x` format specifier to convert an int value to a string:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> num = 5\n", ">>> 'I have %x apples' % num\n", "\"I have 5 apples\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: For new code, using [str.format](#string-formatting-strformat) or [f-strings](#formatted-string-literals-or-f-strings-python-36) (Python 3.6+) is strongly recommended over the `%` operator.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### String Formatting (str.format)\n", "\n", "Python 3 introduced a new way to do string formatting that was later back-ported to Python 2.7. This makes the syntax for string formatting more regular." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> name = 'John'\n", ">>> age = 20'\n", "\n", ">>> \"Hello I'm {}, my age is {}\".format(name, age)\n", "\"Hello I'm John, my age is 20\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> \"Hello I'm {0}, my age is {1}\".format(name, age)\n", "\"Hello I'm John, my age is 20\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The official [Python 3.x documentation](https://docs.python.org/3/library/stdtypes.html?highlight=sprintf#printf-style-string-formatting) recommend `str.format` over the `%` operator:\n", "\n", "> The formatting operations described here exhibit a variety of quirks that lead to a number of common errors (such as failing to display tuples and dictionaries correctly). Using the newer formatted string literals or the str.format() interface helps avoid these errors. These alternatives also provide more powerful, flexible and extensible approaches to formatting text.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Lazy string formatting\n", "\n", "You would only use `%s` string formatting on functions that can do lazy parameters evaluation,\n", "the most common being logging:\n", "\n", "Prefer:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> name = \"alice\"\n", ">>> logging.debug(\"User name: %s\", name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Over:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> logging.debug(\"User name: {}\".format(name))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> logging.debug(\"User name: \" + name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Formatted String Literals or f-strings (Python 3.6+)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> name = 'Elizabeth'\n", ">>> f'Hello {name}!'\n", "'Hello Elizabeth!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is even possible to do inline arithmetic with it:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> a = 5\n", ">>> b = 10\n", ">>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'\n", "'Five plus ten is 15 and not 30.'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Template Strings\n", "\n", " A simpler and less powerful mechanism, but it is recommended when handling format strings generated by users. Due to their reduced complexity template strings are a safer choice." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from string import Template\n", ">>> name = 'Elizabeth'\n", ">>> t = Template('Hey $name!')\n", ">>> t.substitute(name=name)\n", "'Hey Elizabeth!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Regular Expressions\n", "\n", "1. Import the regex module with `import re`.\n", "1. Create a Regex object with the `re.compile()` function. (Remember to use a raw string.)\n", "1. Pass the string you want to search into the Regex object’s `search()` method. This returns a `Match` object.\n", "1. Call the Match object’s `group()` method to return a string of the actual matched text.\n", "\n", "All the regex functions in Python are in the re module:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import re" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Matching Regex Objects" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> phone_num_regex = re.compile(r'\\d\\d\\d-\\d\\d\\d-\\d\\d\\d\\d')\n", "\n", ">>> mo = phone_num_regex.search('My number is 415-555-4242.')\n", "\n", ">>> print('Phone number found: {}'.format(mo.group()))\n", "Phone number found: 415-555-4242" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Grouping with Parentheses" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> phone_num_regex = re.compile(r'(\\d\\d\\d)-(\\d\\d\\d-\\d\\d\\d\\d)')\n", "\n", ">>> mo = phone_num_regex.search('My number is 415-555-4242.')\n", "\n", ">>> mo.group(1)\n", "'415'\n", "\n", ">>> mo.group(2)\n", "'555-4242'\n", "\n", ">>> mo.group(0)\n", "'415-555-4242'\n", "\n", ">>> mo.group()\n", "'415-555-4242'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To retrieve all the groups at once: use the groups() method—note the plural form for the name." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> mo.groups()\n", "('415', '555-4242')\n", "\n", ">>> area_code, main_number = mo.groups()\n", "\n", ">>> print(area_code)\n", "415\n", "\n", ">>> print(main_number)\n", "555-4242" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Matching Multiple Groups with the Pipe\n", "\n", "The | character is called a pipe. You can use it anywhere you want to match one of many expressions. For example, the regular expression r'Batman|Tina Fey' will match either 'Batman' or 'Tina Fey'." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> hero_regex = re.compile (r'Batman|Tina Fey')\n", "\n", ">>> mo1 = hero_regex.search('Batman and Tina Fey.')\n", "\n", ">>> mo1.group()\n", "'Batman'\n", "\n", ">>> mo2 = hero_regex.search('Tina Fey and Batman.')\n", "\n", ">>> mo2.group()\n", "'Tina Fey'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also use the pipe to match one of several patterns as part of your regex:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> bat_regex = re.compile(r'Bat(man|mobile|copter|bat)')\n", "\n", ">>> mo = bat_regex.search('Batmobile lost a wheel')\n", "\n", ">>> mo.group()\n", "'Batmobile'\n", "\n", ">>> mo.group(1)\n", "'mobile'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Optional Matching with the Question Mark\n", "\n", "The ? character flags the group that precedes it as an optional part of the pattern." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> bat_regex = re.compile(r'Bat(wo)?man')\n", ">>> mo1 = bat_regex.search('The Adventures of Batman')\n", ">>> mo1.group()\n", "'Batman'\n", "\n", ">>> mo2 = bat_regex.search('The Adventures of Batwoman')\n", ">>> mo2.group()\n", "'Batwoman'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Matching Zero or More with the Star\n", "\n", "The * (called the star or asterisk) means “match zero or more”—the group that precedes the star can occur any number of times in the text." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> bat_regex = re.compile(r'Bat(wo)*man')\n", ">>> mo1 = bat_regex.search('The Adventures of Batman')\n", ">>> mo1.group()\n", "'Batman'\n", "\n", ">>> mo2 = bat_regex.search('The Adventures of Batwoman')\n", ">>> mo2.group()\n", "'Batwoman'\n", "\n", ">>> mo3 = bat_regex.search('The Adventures of Batwowowowoman')\n", ">>> mo3.group()\n", "'Batwowowowoman'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Matching One or More with the Plus\n", "\n", "While * means “match zero or more,” the + (or plus) means “match one or more”. The group preceding a plus must appear at least once. It is not optional:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> bat_regex = re.compile(r'Bat(wo)+man')\n", ">>> mo1 = bat_regex.search('The Adventures of Batwoman')\n", ">>> mo1.group()\n", "'Batwoman'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> mo2 = bat_regex.search('The Adventures of Batwowowowoman')\n", ">>> mo2.group()\n", "'Batwowowowoman'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> mo3 = bat_regex.search('The Adventures of Batman')\n", ">>> mo3 is None\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Matching Specific Repetitions with Curly Brackets\n", "\n", "If you have a group that you want to repeat a specific number of times, follow the group in your regex with a number in curly brackets. For example, the regex (Ha){3} will match the string 'HaHaHa', but it will not match 'HaHa', since the latter has only two repeats of the (Ha) group.\n", "\n", "Instead of one number, you can specify a range by writing a minimum, a comma, and a maximum in between the curly brackets. For example, the regex (Ha){3,5} will match 'HaHaHa', 'HaHaHaHa', and 'HaHaHaHaHa'." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> ha_regex = re.compile(r'(Ha){3}')\n", ">>> mo1 = ha_regex.search('HaHaHa')\n", ">>> mo1.group()\n", "'HaHaHa'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> mo2 = ha_regex.search('Ha')\n", ">>> mo2 is None\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Greedy and Nongreedy Matching\n", "\n", "Python’s regular expressions are greedy by default, which means that in ambiguous situations they will match the longest string possible. The non-greedy version of the curly brackets, which matches the shortest string possible, has the closing curly bracket followed by a question mark." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> greedy_ha_regex = re.compile(r'(Ha){3,5}')\n", ">>> mo1 = greedy_ha_regex.search('HaHaHaHaHa')\n", ">>> mo1.group()\n", "'HaHaHaHaHa'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> nongreedy_ha_regex = re.compile(r'(Ha){3,5}?')\n", ">>> mo2 = nongreedy_ha_regex.search('HaHaHaHaHa')\n", ">>> mo2.group()\n", "'HaHaHa'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The findall() Method\n", "\n", "In addition to the search() method, Regex objects also have a findall() method. While search() will return a Match object of the first matched text in the searched string, the findall() method will return the strings of every match in the searched string." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> phone_num_regex = re.compile(r'\\d\\d\\d-\\d\\d\\d-\\d\\d\\d\\d') # has no groups\n", "\n", ">>> phone_num_regex.findall('Cell: 415-555-9999 Work: 212-555-0000')\n", "['415-555-9999', '212-555-0000']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To summarize what the findall() method returns, remember the following:\n", "\n", "- When called on a regex with no groups, such as \\d-\\d\\d\\d-\\d\\d\\d\\d, the method findall() returns a list of ng matches, such as ['415-555-9999', '212-555-0000'].\n", "\n", "- When called on a regex that has groups, such as (\\d\\d\\d)-d\\d)-(\\d\\ d\\d\\d), the method findall() returns a list of es of strings (one string for each group), such as [('415', ', '9999'), ('212', '555', '0000')].\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Making Your Own Character Classes\n", "\n", "There are times when you want to match a set of characters but the shorthand character classes (\\d, \\w, \\s, and so on) are too broad. You can define your own character class using square brackets. For example, the character class [aeiouAEIOU] will match any vowel, both lowercase and uppercase." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> vowel_regex = re.compile(r'[aeiouAEIOU]')\n", "\n", ">>> vowel_regex.findall('Robocop eats baby food. BABY FOOD.')\n", "['o', 'o', 'o', 'e', 'a', 'a', 'o', 'o', 'A', 'O', 'O']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also include ranges of letters or numbers by using a hyphen. For example, the character class [a-zA-Z0-9] will match all lowercase letters, uppercase letters, and numbers.\n", "\n", "By placing a caret character (^) just after the character class’s opening bracket, you can make a negative character class. A negative character class will match all the characters that are not in the character class. For example, enter the following into the interactive shell:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> consonant_regex = re.compile(r'[^aeiouAEIOU]')\n", "\n", ">>> consonant_regex.findall('Robocop eats baby food. BABY FOOD.')\n", "['R', 'b', 'c', 'p', ' ', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', '\n", "', 'B', 'B', 'Y', ' ', 'F', 'D', '.']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The Caret and Dollar Sign Characters\n", "\n", "- You can also use the caret symbol (^) at the start of a regex to indicate that a match must occur at the beginning of the searched text.\n", "\n", "- Likewise, you can put a dollar sign ($) at the end of the regex to indicate the string must end with this regex pattern.\n", "\n", "- And you can use the ^ and $ together to indicate that the entire string must match the regex—that is, it’s not enough for a match to be made on some subset of the string.\n", "\n", "The r'^Hello' regular expression string matches strings that begin with 'Hello':" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> begins_with_hello = re.compile(r'^Hello')\n", "\n", ">>> begins_with_hello.search('Hello world!')\n", "<_sre.SRE_Match object; span=(0, 5), match='Hello'>\n", "\n", ">>> begins_with_hello.search('He said hello.') is None\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The r'\\d$' regular expression string matches strings that end with a numeric character from 0 to 9:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> whole_string_is_num = re.compile(r'^\\d+$')\n", "\n", ">>> whole_string_is_num.search('1234567890')\n", "<_sre.SRE_Match object; span=(0, 10), match='1234567890'>\n", "\n", ">>> whole_string_is_num.search('12345xyz67890') is None\n", "True\n", "\n", ">>> whole_string_is_num.search('12 34567890') is None\n", "True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The Wildcard Character\n", "\n", "The . (or dot) character in a regular expression is called a wildcard and will match any character except for a newline:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> at_regex = re.compile(r'.at')\n", "\n", ">>> at_regex.findall('The cat in the hat sat on the flat mat.')\n", "['cat', 'hat', 'sat', 'lat', 'mat']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Matching Everything with Dot-Star" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> name_regex = re.compile(r'First Name: (.*) Last Name: (.*)')\n", "\n", ">>> mo = name_regex.search('First Name: Al Last Name: Sweigart')\n", "\n", ">>> mo.group(1)\n", "'Al'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> mo.group(2)\n", "'Sweigart'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The dot-star uses greedy mode: It will always try to match as much text as possible. To match any and all text in a nongreedy fashion, use the dot, star, and question mark (.*?). The question mark tells Python to match in a nongreedy way:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> nongreedy_regex = re.compile(r'<.*?>')\n", ">>> mo = nongreedy_regex.search(' for dinner.>')\n", ">>> mo.group()\n", "''" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> greedy_regex = re.compile(r'<.*>')\n", ">>> mo = greedy_regex.search(' for dinner.>')\n", ">>> mo.group()\n", "' for dinner.>'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Matching Newlines with the Dot Character\n", "\n", "The dot-star will match everything except a newline. By passing re.DOTALL as the second argument to re.compile(), you can make the dot character match all characters, including the newline character:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> no_newline_regex = re.compile('.*')\n", ">>> no_newline_regex.search('Serve the public trust.\\nProtect the innocent.\\nUphold the law.').group()\n", "'Serve the public trust.'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> newline_regex = re.compile('.*', re.DOTALL)\n", ">>> newline_regex.search('Serve the public trust.\\nProtect the innocent.\\nUphold the law.').group()\n", "'Serve the public trust.\\nProtect the innocent.\\nUphold the law.'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Review of Regex Symbols\n", "\n", "| Symbol | Matches |\n", "| ------------------------ | ------------------------------------------------------------ |\n", "| `?` | zero or one of the preceding group. |\n", "| `*` | zero or more of the preceding group. |\n", "| `+` | one or more of the preceding group. |\n", "| `{n}` | exactly n of the preceding group. |\n", "| `{n,}` | n or more of the preceding group. |\n", "| `{,m}` | 0 to m of the preceding group. |\n", "| `{n,m}` | at least n and at most m of the preceding p. |\n", "| `{n,m}?` or `*?` or `+?` | performs a nongreedy match of the preceding p. |\n", "| `^spam` | means the string must begin with spam. |\n", "| `spam$` | means the string must end with spam. |\n", "| `.` | any character, except newline characters. |\n", "| `\\d`, `\\w`, and `\\s` | a digit, word, or space character, ectively. |\n", "| `\\D`, `\\W`, and `\\S` | anything except a digit, word, or space acter, respectively. |\n", "| `[abc]` | any character between the brackets (such as a, b, ). |\n", "| `[^abc]` | any character that isn’t between the brackets. |\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Case-Insensitive Matching\n", "\n", "To make your regex case-insensitive, you can pass re.IGNORECASE or re.I as a second argument to re.compile():" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> robocop = re.compile(r'robocop', re.I)\n", "\n", ">>> robocop.search('Robocop is part man, part machine, all cop.').group()\n", "'Robocop'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> robocop.search('ROBOCOP protects the innocent.').group()\n", "'ROBOCOP'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> robocop.search('Al, why does your programming book talk about robocop so much?').group()\n", "'robocop'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Substituting Strings with the sub() Method\n", "\n", "The sub() method for Regex objects is passed two arguments:\n", "\n", "1. The first argument is a string to replace any matches.\n", "1. The second is the string for the regular expression.\n", "\n", "The sub() method returns a string with the substitutions applied:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> names_regex = re.compile(r'Agent \\w+')\n", "\n", ">>> names_regex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.')\n", "'CENSORED gave the secret documents to CENSORED.'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> agent_names_regex = re.compile(r'Agent (\\w)\\w*')\n", "\n", ">>> agent_names_regex.sub(r'\\1****', 'Agent Alice told Agent Carol that Agent Eve knew Agent Bob was a double agent.')\n", "A**** told C**** that E**** knew B**** was a double agent.'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Managing Complex Regexes\n", "\n", "To tell the re.compile() function to ignore whitespace and comments inside the regular expression string, “verbose mode” can be enabled by passing the variable re.VERBOSE as the second argument to re.compile().\n", "\n", "Now instead of a hard-to-read regular expression like this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "phone_regex = re.compile(r'((\\d{3}|\\(\\d{3}\\))?(\\s|-|\\.)?\\d{3}(\\s|-|\\.)\\d{4}(\\s*(ext|x|ext.)\\s*\\d{2,5})?)')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "you can spread the regular expression over multiple lines with comments like this:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "phone_regex = re.compile(r'''(\n", " (\\d{3}|\\(\\d{3}\\))? # area code\n", " (\\s|-|\\.)? # separator\n", " \\d{3} # first 3 digits\n", " (\\s|-|\\.) # separator\n", " \\d{4} # last 4 digits\n", " (\\s*(ext|x|ext.)\\s*\\d{2,5})? # extension\n", " )''', re.VERBOSE)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Handling File and Directory Paths\n", "\n", "There are two main modules in Python that deals with path manipulation.\n", "One is the `os.path` module and the other is the `pathlib` module.\n", "The `pathlib` module was added in Python 3.4, offering an object-oriented way\n", "to handle file system paths.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Backslash on Windows and Forward Slash on OS X and Linux\n", "\n", "On Windows, paths are written using backslashes (\\) as the separator between\n", "folder names. On Unix based operating system such as macOS, Linux, and BSDs,\n", "the forward slash (/) is used as the path separator. Joining paths can be\n", "a headache if your code needs to work on different platforms.\n", "\n", "Fortunately, Python provides easy ways to handle this. We will showcase\n", "how to deal with this with both `os.path.join` and `pathlib.Path.joinpath`\n", "\n", "Using `os.path.join` on Windows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", "\n", ">>> os.path.join('usr', 'bin', 'spam')\n", "'usr\\\\bin\\\\spam'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", "\n", ">>> print(Path('usr').joinpath('bin').joinpath('spam'))\n", "usr/bin/spam" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`pathlib` also provides a shortcut to joinpath using the `/` operator:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", "\n", ">>> print(Path('usr') / 'bin' / 'spam')\n", "usr/bin/spam" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice the path separator is different between Windows and Unix based operating\n", "system, that's why you want to use one of the above methods instead of\n", "adding strings together to join paths together.\n", "\n", "Joining paths is helpful if you need to create different file paths under\n", "the same directory.\n", "\n", "Using `os.path.join` on Windows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> my_files = ['accounts.txt', 'details.csv', 'invite.docx']\n", "\n", ">>> for filename in my_files:\n", ">>> print(os.path.join('C:\\\\Users\\\\asweigart', filename))\n", "C:\\Users\\asweigart\\accounts.txt\n", "C:\\Users\\asweigart\\details.csv\n", "C:\\Users\\asweigart\\invite.docx" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> my_files = ['accounts.txt', 'details.csv', 'invite.docx']\n", ">>> home = Path.home()\n", ">>> for filename in my_files:\n", ">>> print(home / filename)\n", "/home/asweigart/accounts.txt\n", "/home/asweigart/details.csv\n", "/home/asweigart/invite.docx" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### The Current Working Directory\n", "\n", "Using `os` on Windows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", "\n", ">>> os.getcwd()\n", "'C:\\\\Python34'\n", ">>> os.chdir('C:\\\\Windows\\\\System32')\n", "\n", ">>> os.getcwd()\n", "'C:\\\\Windows\\\\System32'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> from os import chdir\n", "\n", ">>> print(Path.cwd())\n", "/home/asweigart\n", "\n", ">>> chdir('/usr/lib/python3.6')\n", ">>> print(Path.cwd())\n", "/usr/lib/python3.6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Creating New Folders\n", "\n", "Using `os` on Windows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>> os.makedirs('C:\\\\delicious\\\\walnut\\\\waffles')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> cwd = Path.cwd()\n", ">>> (cwd / 'delicious' / 'walnut' / 'waffles').mkdir()\n", "Traceback (most recent call last):\n", " File \"\", line 1, in \n", " File \"/usr/lib/python3.6/pathlib.py\", line 1226, in mkdir\n", " self._accessor.mkdir(self, mode)\n", " File \"/usr/lib/python3.6/pathlib.py\", line 387, in wrapped\n", " return strfunc(str(pathobj), *args)\n", "FileNotFoundError: [Errno 2] No such file or directory: '/home/asweigart/delicious/walnut/waffles'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Oh no, we got a nasty error! The reason is that the 'delicious' directory does\n", "not exist, so we cannot make the 'walnut' and the 'waffles' directories under\n", "it. To fix this, do:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> cwd = Path.cwd()\n", ">>> (cwd / 'delicious' / 'walnut' / 'waffles').mkdir(parents=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And all is good :)\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Absolute vs. Relative Paths\n", "\n", "There are two ways to specify a file path.\n", "\n", "- An absolute path, which always begins with the root folder\n", "- A relative path, which is relative to the program’s current working directory\n", "\n", "There are also the dot (.) and dot-dot (..) folders. These are not real folders but special names that can be used in a path. A single period (“dot”) for a folder name is shorthand for “this directory.” Two periods (“dot-dot”) means “the parent folder.”\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Handling Absolute and Relative Paths\n", "\n", "To see if a path is an absolute path:\n", "\n", "Using `os.path` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>> os.path.isabs('/')\n", "True\n", ">>> os.path.isabs('..')\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> Path('/').is_absolute()\n", "True\n", ">>> Path('..').is_absolute()\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can extract an absolute path with both `os.path` and `pathlib`\n", "\n", "Using `os.path` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>> os.getcwd()\n", "'/home/asweigart'\n", ">>> os.path.abspath('..')\n", "'/home'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", "print(Path.cwd())\n", "/home/asweigart\n", "print(Path('..').resolve())\n", "/home" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can get a relative path from a starting path to another path.\n", "\n", "Using `os.path` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>> os.path.relpath('/etc/passwd', '/')\n", "'etc/passwd'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> print(Path('/etc/passwd').relative_to('/'))\n", "etc/passwd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Checking Path Validity\n", "\n", "Checking if a file/directory exists:\n", "\n", "Using `os.path` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", ">>> os.path.exists('.')\n", "True\n", ">>> os.path.exists('setup.py')\n", "True\n", ">>> os.path.exists('/etc')\n", "True\n", ">>> os.path.exists('nonexistentfile')\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", ">>> Path('.').exists()\n", "True\n", ">>> Path('setup.py').exists()\n", "True\n", ">>> Path('/etc').exists()\n", "True\n", ">>> Path('nonexistentfile').exists()\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Checking if a path is a file:\n", "\n", "Using `os.path` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>> os.path.isfile('setup.py')\n", "True\n", ">>> os.path.isfile('/home')\n", "False\n", ">>> os.path.isfile('nonexistentfile')\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> Path('setup.py').is_file()\n", "True\n", ">>> Path('/home').is_file()\n", "False\n", ">>> Path('nonexistentfile').is_file()\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Checking if a path is a directory:\n", "\n", "Using `os.path` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>> os.path.isdir('/')\n", "True\n", ">>> os.path.isdir('setup.py')\n", "False\n", ">>> os.path.isdir('/spam')\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> Path('/').is_dir()\n", "True\n", ">>> Path('setup.py').is_dir()\n", "False\n", ">>> Path('/spam').is_dir()\n", "False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Finding File Sizes and Folder Contents\n", "\n", "Getting a file's size in bytes:\n", "\n", "Using `os.path` on Windows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>> os.path.getsize('C:\\\\Windows\\\\System32\\\\calc.exe')\n", "776192" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> stat = Path('/bin/python3.6').stat()\n", ">>> print(stat) # stat contains some other information about the file as well\n", "os.stat_result(st_mode=33261, st_ino=141087, st_dev=2051, st_nlink=2, st_uid=0,\n", "--snip--\n", "st_gid=0, st_size=10024, st_atime=1517725562, st_mtime=1515119809, st_ctime=1517261276)\n", ">>> print(stat.st_size) # size in bytes\n", "10024" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Listing directory contents using `os.listdir` on Windows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>> os.listdir('C:\\\\Windows\\\\System32')\n", "['0409', '12520437.cpx', '12520850.cpx', '5U877.ax', 'aaclient.dll',\n", "--snip--\n", "'xwtpdui.dll', 'xwtpw32.dll', 'zh-CN', 'zh-HK', 'zh-TW', 'zipfldr.dll']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Listing directory contents using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> for f in Path('/usr/bin').iterdir():\n", ">>> print(f)\n", "...\n", "/usr/bin/tiff2rgba\n", "/usr/bin/iconv\n", "/usr/bin/ldd\n", "/usr/bin/cache_restore\n", "/usr/bin/udiskie\n", "/usr/bin/unix2dos\n", "/usr/bin/t1reencode\n", "/usr/bin/epstopdf\n", "/usr/bin/idle3\n", "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To find the total size of all the files in this directory:\n", "\n", "**WARNING**: Directories themselves also have a size! So you might want to\n", "check for whether a path is a file or directory using the methods in the methods discussed in the above section!\n", "\n", "Using `os.path.getsize()` and `os.listdir()` together on Windows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>> total_size = 0\n", "\n", ">>> for filename in os.listdir('C:\\\\Windows\\\\System32'):\n", " total_size = total_size + os.path.getsize(os.path.join('C:\\\\Windows\\\\System32', filename))\n", "\n", ">>> print(total_size)\n", "1117846456" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `pathlib` on \\*nix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from pathlib import Path\n", ">>> total_size = 0\n", "\n", ">>> for sub_path in Path('/usr/bin').iterdir():\n", "... total_size += sub_path.stat().st_size\n", ">>>\n", ">>> print(total_size)\n", "1903178911" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Copying Files and Folders\n", "\n", "The shutil module provides functions for copying files, as well as entire folders." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import shutil, os\n", "\n", ">>> os.chdir('C:\\\\')\n", "\n", ">>> shutil.copy('C:\\\\spam.txt', 'C:\\\\delicious')\n", " 'C:\\\\delicious\\\\spam.txt'\n", "\n", ">>> shutil.copy('eggs.txt', 'C:\\\\delicious\\\\eggs2.txt')\n", " 'C:\\\\delicious\\\\eggs2.txt'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "While shutil.copy() will copy a single file, shutil.copytree() will copy an entire folder and every folder and file contained in it:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import shutil, os\n", "\n", ">>> os.chdir('C:\\\\')\n", "\n", ">>> shutil.copytree('C:\\\\bacon', 'C:\\\\bacon_backup')\n", "'C:\\\\bacon_backup'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Moving and Renaming Files and Folders" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import shutil\n", ">>> shutil.move('C:\\\\bacon.txt', 'C:\\\\eggs')\n", "'C:\\\\eggs\\\\bacon.txt'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The destination path can also specify a filename. In the following example, the source file is moved and renamed:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> shutil.move('C:\\\\bacon.txt', 'C:\\\\eggs\\\\new_bacon.txt')\n", "'C:\\\\eggs\\\\new_bacon.txt'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If there is no eggs folder, then move() will rename bacon.txt to a file named eggs." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> shutil.move('C:\\\\bacon.txt', 'C:\\\\eggs')\n", "'C:\\\\eggs'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Permanently Deleting Files and Folders\n", "\n", "- Calling os.unlink(path) or Path.unlink() will delete the file at path.\n", "\n", "- Calling os.rmdir(path) or Path.rmdir() will delete the folder at path. This folder must be empty of any files or folders.\n", "\n", "- Calling shutil.rmtree(path) will remove the folder at path, and all files and folders it contains will also be deleted.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Safe Deletes with the send2trash Module\n", "\n", " You can install this module by running pip install send2trash from a Terminal window." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import send2trash\n", "\n", ">>> with open('bacon.txt', 'a') as bacon_file: # creates the file\n", "... bacon_file.write('Bacon is not a vegetable.')\n", "25\n", "\n", ">>> send2trash.send2trash('bacon.txt')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Walking a Directory Tree" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import os\n", ">>>\n", ">>> for folder_name, subfolders, filenames in os.walk('C:\\\\delicious'):\n", ">>> print('The current folder is {}'.format(folder_name))\n", ">>>\n", ">>> for subfolder in subfolders:\n", ">>> print('SUBFOLDER OF {}: {}'.format(folder_name, subfolder))\n", ">>> for filename in filenames:\n", ">>> print('FILE INSIDE {}: {}'.format(folder_name, filename))\n", ">>>\n", ">>> print('')\n", "The current folder is C:\\delicious\n", "SUBFOLDER OF C:\\delicious: cats\n", "SUBFOLDER OF C:\\delicious: walnut\n", "FILE INSIDE C:\\delicious: spam.txt\n", "\n", "The current folder is C:\\delicious\\cats\n", "FILE INSIDE C:\\delicious\\cats: catnames.txt\n", "FILE INSIDE C:\\delicious\\cats: zophie.jpg\n", "\n", "The current folder is C:\\delicious\\walnut\n", "SUBFOLDER OF C:\\delicious\\walnut: waffles\n", "\n", "The current folder is C:\\delicious\\walnut\\waffles\n", "FILE INSIDE C:\\delicious\\walnut\\waffles: butter.txt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "`pathlib` provides a lot more functionality than the ones listed above,\n", "like getting file name, getting file extension, reading/writing a file without\n", "manually opening it, etc. Check out the\n", "[official documentation](https://docs.python.org/3/library/pathlib.html)\n", "if you want to know more!\n", "\n", "## Reading and Writing Files\n", "\n", "### The File Reading/Writing Process\n", "\n", "To read/write to a file in Python, you will want to use the `with`\n", "statement, which will close the file for you after you are done.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Opening and reading files with the open() function" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> with open('C:\\\\Users\\\\your_home_folder\\\\hello.txt') as hello_file:\n", "... hello_content = hello_file.read()\n", ">>> hello_content\n", "'Hello World!'\n", "\n", ">>> # Alternatively, you can use the *readlines()* method to get a list of string values from the file, one string for each line of text:\n", "\n", ">>> with open('sonnet29.txt') as sonnet_file:\n", "... sonnet_file.readlines()\n", "[When, in disgrace with fortune and men's eyes,\\n', ' I all alone beweep my\n", "outcast state,\\n', And trouble deaf heaven with my bootless cries,\\n', And\n", "look upon myself and curse my fate,']\n", "\n", ">>> # You can also iterate through the file line by line:\n", ">>> with open('sonnet29.txt') as sonnet_file:\n", "... for line in sonnet_file: # note the new line character will be included in the line\n", "... print(line, end='')\n", "\n", "When, in disgrace with fortune and men's eyes,\n", "I all alone beweep my outcast state,\n", "And trouble deaf heaven with my bootless cries,\n", "And look upon myself and curse my fate," ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Writing to Files" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> with open('bacon.txt', 'w') as bacon_file:\n", "... bacon_file.write('Hello world!\\n')\n", "13\n", "\n", ">>> with open('bacon.txt', 'a') as bacon_file:\n", "... bacon_file.write('Bacon is not a vegetable.')\n", "25\n", "\n", ">>> with open('bacon.txt') as bacon_file:\n", "... content = bacon_file.read()\n", "\n", ">>> print(content)\n", "Hello world!\n", "Bacon is not a vegetable." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Saving Variables with the shelve Module\n", "\n", "To save variables:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import shelve\n", "\n", ">>> cats = ['Zophie', 'Pooka', 'Simon']\n", ">>> with shelve.open('mydata') as shelf_file:\n", "... shelf_file['cats'] = cats" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To open and read variables:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> with shelve.open('mydata') as shelf_file:\n", "... print(type(shelf_file))\n", "... print(shelf_file['cats'])\n", "\n", "['Zophie', 'Pooka', 'Simon']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just like dictionaries, shelf values have keys() and values() methods that will return list-like values of the keys and values in the shelf. Since these methods return list-like values instead of true lists, you should pass them to the list() function to get them in list form." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> with shelve.open('mydata') as shelf_file:\n", "... print(list(shelf_file.keys()))\n", "... print(list(shelf_file.values()))\n", "['cats']\n", "[['Zophie', 'Pooka', 'Simon']]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Saving Variables with the pprint.pformat() Function" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import pprint\n", "\n", ">>> cats = [{'name': 'Zophie', 'desc': 'chubby'}, {'name': 'Pooka', 'desc': 'fluffy'}]\n", "\n", ">>> pprint.pformat(cats)\n", "\"[{'desc': 'chubby', 'name': 'Zophie'}, {'desc': 'fluffy', 'name': 'Pooka'}]\"\n", "\n", ">>> with open('myCats.py', 'w') as file_obj:\n", "... file_obj.write('cats = {}\\n'.format(pprint.pformat(cats)))\n", "83" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Reading ZIP Files" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import zipfile, os\n", "\n", ">>> os.chdir('C:\\\\') # move to the folder with example.zip\n", ">>> with zipfile.ZipFile('example.zip') as example_zip:\n", "... print(example_zip.namelist())\n", "... spam_info = example_zip.getinfo('spam.txt')\n", "... print(spam_info.file_size)\n", "... print(spam_info.compress_size)\n", "... print('Compressed file is %sx smaller!' % (round(spam_info.file_size / spam_info.compress_size, 2)))\n", "\n", "['spam.txt', 'cats/', 'cats/catnames.txt', 'cats/zophie.jpg']\n", "13908\n", "3828\n", "'Compressed file is 3.63x smaller!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Extracting from ZIP Files\n", "\n", "The extractall() method for ZipFile objects extracts all the files and folders from a ZIP file into the current working directory." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import zipfile, os\n", "\n", ">>> os.chdir('C:\\\\') # move to the folder with example.zip\n", "\n", ">>> with zipfile.ZipFile('example.zip') as example_zip:\n", "... example_zip.extractall()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The extract() method for ZipFile objects will extract a single file from the ZIP file. Continue the interactive shell example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> with zipfile.ZipFile('example.zip') as example_zip:\n", "... print(example_zip.extract('spam.txt'))\n", "... print(example_zip.extract('spam.txt', 'C:\\\\some\\\\new\\\\folders'))\n", "'C:\\\\spam.txt'\n", "'C:\\\\some\\\\new\\\\folders\\\\spam.txt'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Creating and Adding to ZIP Files" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import zipfile\n", "\n", ">>> with zipfile.ZipFile('new.zip', 'w') as new_zip:\n", "... new_zip.write('spam.txt', compress_type=zipfile.ZIP_DEFLATED)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This code will create a new ZIP file named new.zip that has the compressed contents of spam.txt.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## JSON, YAML and configuration files\n", "\n", "### JSON\n", "\n", "Open a JSON file with:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import json\n", "with open(\"filename.json\", \"r\") as f:\n", " content = json.loads(f.read())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Write a JSON file with:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import json\n", "\n", "content = {\"name\": \"Joe\", \"age\": 20}\n", "with open(\"filename.json\", \"w\") as f:\n", " f.write(json.dumps(content, indent=2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### YAML\n", "\n", "Compared to JSON, YAML allows a much better humain maintainance and gives ability to add comments.\n", "It is a convinient choice for configuration files where human will have to edit.\n", "\n", "There are two main librairies allowing to access to YAML files:\n", "\n", "- [PyYaml](https://pypi.python.org/pypi/PyYAML)\n", "- [Ruamel.yaml](https://pypi.python.org/pypi/ruamel.yaml)\n", "\n", "Install them using `pip install` in your virtual environment.\n", "\n", "The first one it easier to use but the second one, Ruamel, implements much better the YAML\n", "specification, and allow for example to modify a YAML content without altering comments.\n", "\n", "Open a YAML file with:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ruamel.yaml import YAML\n", "\n", "with open(\"filename.yaml\") as f:\n", " yaml=YAML()\n", " yaml.load(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Anyconfig\n", "\n", "[Anyconfig](https://pypi.python.org/pypi/anyconfig) is a very handy package allowing to abstract completly the underlying configuration file format. It allows to load a Python dictionary from JSON, YAML, TOML, and so on.\n", "\n", "Install it with:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%bash\n", "pip install anyconfig" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Usage:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import anyconfig\n", "\n", "conf1 = anyconfig.load(\"/path/to/foo/conf.d/a.yml\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Debugging\n", "\n", "### Raising Exceptions\n", "\n", "Exceptions are raised with a raise statement. In code, a raise statement consists of the following:\n", "\n", "- The raise keyword\n", "- A call to the Exception() function\n", "- A string with a helpful error message passed to the Exception() function" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> raise Exception('This is the error message.')\n", "Traceback (most recent call last):\n", " File \"\", line 1, in \n", " raise Exception('This is the error message.')\n", "Exception: This is the error message." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Often it’s the code that calls the function, not the function itself, that knows how to handle an expection. So you will commonly see a raise statement inside a function and the try and except statements in the code calling the function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def box_print(symbol, width, height):\n", " if len(symbol) != 1:\n", " raise Exception('Symbol must be a single character string.')\n", " if width <= 2:\n", " raise Exception('Width must be greater than 2.')\n", " if height <= 2:\n", " raise Exception('Height must be greater than 2.')\n", " print(symbol * width)\n", " for i in range(height - 2):\n", " print(symbol + (' ' * (width - 2)) + symbol)\n", " print(symbol * width)\n", "for sym, w, h in (('*', 4, 4), ('O', 20, 5), ('x', 1, 3), ('ZZ', 3, 3)):\n", " try:\n", " box_print(sym, w, h)\n", " except Exception as err:\n", " print('An exception happened: ' + str(err))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Getting the Traceback as a String\n", "\n", "The traceback is displayed by Python whenever a raised exception goes unhandled. But can also obtain it as a string by calling traceback.format_exc(). This function is useful if you want the information from an exception’s traceback but also want an except statement to gracefully handle the exception. You will need to import Python’s traceback module before calling this function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import traceback\n", "\n", ">>> try:\n", ">>> raise Exception('This is the error message.')\n", ">>> except:\n", ">>> with open('errorInfo.txt', 'w') as error_file:\n", ">>> error_file.write(traceback.format_exc())\n", ">>> print('The traceback info was written to errorInfo.txt.')\n", "116\n", "The traceback info was written to errorInfo.txt." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The 116 is the return value from the write() method, since 116 characters were written to the file. The traceback text was written to errorInfo.txt." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Traceback (most recent call last):\n", " File \"\", line 2, in \n", "Exception: This is the error message." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Assertions\n", "\n", "An assertion is a sanity check to make sure your code isn’t doing something obviously wrong. These sanity checks are performed by assert statements. If the sanity check fails, then an AssertionError exception is raised. In code, an assert statement consists of the following:\n", "\n", "- The assert keyword\n", "- A condition (that is, an expression that evaluates to True or False)\n", "- A comma\n", "- A string to display when the condition is False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> pod_bay_door_status = 'open'\n", "\n", ">>> assert pod_bay_door_status == 'open', 'The pod bay doors need to be \"open\".'\n", "\n", ">>> pod_bay_door_status = 'I\\'m sorry, Dave. I\\'m afraid I can\\'t do that.'\n", "\n", ">>> assert pod_bay_door_status == 'open', 'The pod bay doors need to be \"open\".'\n", "\n", "Traceback (most recent call last):\n", " File \"\", line 1, in \n", " assert pod_bay_door_status == 'open', 'The pod bay doors need to be \"open\".'\n", "AssertionError: The pod bay doors need to be \"open\"." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In plain English, an assert statement says, “I assert that this condition holds true, and if not, there is a bug somewhere in the program.” Unlike exceptions, your code should not handle assert statements with try and except; if an assert fails, your program should crash. By failing fast like this, you shorten the time between the original cause of the bug and when you first notice the bug. This will reduce the amount of code you will have to check before finding the code that’s causing the bug.\n", "\n", "Disabling Assertions\n", "\n", "Assertions can be disabled by passing the -O option when running Python.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Logging\n", "\n", "To enable the logging module to display log messages on your screen as your program runs, copy the following to the top of your program (but under the #! python shebang line):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import logging\n", "\n", "logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s- %(message)s')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Say you wrote a function to calculate the factorial of a number. In mathematics, factorial 4 is 1 × 2 × 3 × 4, or 24. Factorial 7 is 1 × 2 × 3 × 4 × 5 × 6 × 7, or 5,040. Open a new file editor window and enter the following code. It has a bug in it, but you will also enter several log messages to help yourself figure out what is going wrong. Save the program as factorialLog.py." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import logging\n", ">>>\n", ">>> logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s- %(message)s')\n", ">>>\n", ">>> logging.debug('Start of program')\n", ">>>\n", ">>> def factorial(n):\n", ">>>\n", ">>> logging.debug('Start of factorial(%s)' % (n))\n", ">>> total = 1\n", ">>>\n", ">>> for i in range(1, n + 1):\n", ">>> total *= i\n", ">>> logging.debug('i is ' + str(i) + ', total is ' + str(total))\n", ">>>\n", ">>> logging.debug('End of factorial(%s)' % (n))\n", ">>>\n", ">>> return total\n", ">>>\n", ">>> print(factorial(5))\n", ">>> logging.debug('End of program')\n", "2015-05-23 16:20:12,664 - DEBUG - Start of program\n", "2015-05-23 16:20:12,664 - DEBUG - Start of factorial(5)\n", "2015-05-23 16:20:12,665 - DEBUG - i is 0, total is 0\n", "2015-05-23 16:20:12,668 - DEBUG - i is 1, total is 0\n", "2015-05-23 16:20:12,670 - DEBUG - i is 2, total is 0\n", "2015-05-23 16:20:12,673 - DEBUG - i is 3, total is 0\n", "2015-05-23 16:20:12,675 - DEBUG - i is 4, total is 0\n", "2015-05-23 16:20:12,678 - DEBUG - i is 5, total is 0\n", "2015-05-23 16:20:12,680 - DEBUG - End of factorial(5)\n", "0\n", "2015-05-23 16:20:12,684 - DEBUG - End of program" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Logging Levels\n", "\n", "Logging levels provide a way to categorize your log messages by importance. There are five logging levels, described in Table 10-1 from least to most important. Messages can be logged at each level using a different logging function.\n", "\n", "| Level | Logging Function | Description |\n", "| ---------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------ |\n", "| `DEBUG` | `logging.debug()` | The lowest level. Used for small details. Usually you care about these messages only when diagnosing problems. |\n", "| `INFO` | `logging.info()` | Used to record information on general events in your program or confirm that things are working at their point in the program. |\n", "| `WARNING` | `logging.warning()` | Used to indicate a potential problem that doesn’t prevent the program from working but might do so in the future. |\n", "| `ERROR` | `logging.error()` | Used to record an error that caused the program to fail to do something. |\n", "| `CRITICAL` | `logging.critical()` | The highest level. Used to indicate a fatal error that has caused or is about to cause the program to stop running entirely. |\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Disabling Logging\n", "\n", "After you’ve debugged your program, you probably don’t want all these log messages cluttering the screen. The logging.disable() function disables these so that you don’t have to go into your program and remove all the logging calls by hand." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import logging\n", "\n", ">>> logging.basicConfig(level=logging.INFO, format=' %(asctime)s -%(levelname)s - %(message)s')\n", "\n", ">>> logging.critical('Critical error! Critical error!')\n", "2015-05-22 11:10:48,054 - CRITICAL - Critical error! Critical error!\n", "\n", ">>> logging.disable(logging.CRITICAL)\n", "\n", ">>> logging.critical('Critical error! Critical error!')\n", "\n", ">>> logging.error('Error! Error!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Logging to a File\n", "\n", "Instead of displaying the log messages to the screen, you can write them to a text file. The logging.basicConfig() function takes a filename keyword argument, like so:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import logging\n", "\n", "logging.basicConfig(filename='myProgramLog.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Lambda Functions\n", "\n", "This function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def add(x, y):\n", " return x + y\n", "\n", ">>> add(5, 3)\n", "8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Is equivalent to the *lambda* function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> add = lambda x, y: x + y\n", ">>> add(5, 3)\n", "8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's not even need to bind it to a name like add before:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> (lambda x, y: x + y)(5, 3)\n", "8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like regular nested functions, lambdas also work as lexical closures:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def make_adder(n):\n", " return lambda x: x + n\n", "\n", ">>> plus_3 = make_adder(3)\n", ">>> plus_5 = make_adder(5)\n", "\n", ">>> plus_3(4)\n", "7\n", ">>> plus_5(4)\n", "9" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: lambda can only evaluate an expression, like a single line of code.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Ternary Conditional Operator\n", "\n", "Many programming languages have a ternary operator, which define a conditional expression. The most common usage is to make a terse simple conditional assignment statement. In other words, it offers one-line code to evaluate the first expression if the condition is true, otherwise it evaluates the second expression." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ " if else " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> age = 15\n", "\n", ">>> print('kid' if age < 18 else 'adult')\n", "kid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ternary operators can be changed:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> age = 15\n", "\n", ">>> print('kid' if age < 13 else 'teenager' if age < 18 else 'adult')\n", "teenager" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The code above is equivalent to:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "if age < 18:\n", " if age < 12:\n", " print('kid')\n", " else:\n", " print('teenager')\n", "else:\n", " print('adult')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## args and kwargs\n", "\n", "The names ```args and kwargs``` are arbitrary - the important thing are the ```*``` and ```**``` operators. They can mean:\n", "\n", "1. In a function declaration, ```*``` means “pack all remaining positional arguments into a tuple named ``”, while ```**``` is the same for keyword arguments (except it uses a dictionary, not a tuple).\n", "\n", "2. In a function call, ```*``` means “unpack tuple or list named `` to positional arguments at this position”, while ```**``` is the same for keyword arguments.\n", "\n", "For example you can make a function that you can use to call any other function, no matter what parameters it has:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def forward(f, *args, **kwargs):\n", " return f(*args, **kwargs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Inside forward, args is a tuple (of all positional arguments except the first one, because we specified it - the f), kwargs is a dict. Then we call f and unpack them so they become normal arguments to f.\n", "\n", "You use ```*args``` when you have an indefinite amount of positional arguments." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def fruits(*args):\n", ">>> for fruit in args:\n", ">>> print(fruit)\n", "\n", ">>> fruits(\"apples\", \"bananas\", \"grapes\")\n", "\n", "\"apples\"\n", "\"bananas\"\n", "\"grapes\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, you use ```**kwargs``` when you have an indefinite number of keyword arguments." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def fruit(**kwargs):\n", ">>> for key, value in kwargs.items():\n", ">>> print(\"{0}: {1}\".format(key, value))\n", "\n", ">>> fruit(name = \"apple\", color = \"red\")\n", "\n", "name: apple\n", "color: red" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> def show(arg1, arg2, *args, kwarg1=None, kwarg2=None, **kwargs):\n", ">>> print(arg1)\n", ">>> print(arg2)\n", ">>> print(args)\n", ">>> print(kwarg1)\n", ">>> print(kwarg2)\n", ">>> print(kwargs)\n", "\n", ">>> data1 = [1,2,3]\n", ">>> data2 = [4,5,6]\n", ">>> data3 = {'a':7,'b':8,'c':9}\n", "\n", ">>> show(*data1,*data2, kwarg1=\"python\",kwarg2=\"cheatsheet\",**data3)\n", "1\n", "2\n", "(3, 4, 5, 6)\n", "python\n", "cheatsheet\n", "{'a': 7, 'b': 8, 'c': 9}\n", "\n", ">>> show(*data1, *data2, **data3)\n", "1\n", "2\n", "(3, 4, 5, 6)\n", "None\n", "None\n", "{'a': 7, 'b': 8, 'c': 9}\n", "\n", "# If you do not specify ** for kwargs\n", ">>> show(*data1, *data2, *data3)\n", "1\n", "2\n", "(3, 4, 5, 6, \"a\", \"b\", \"c\")\n", "None\n", "None\n", "{}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Thinks to Remember(args)\n", "\n", "1. Functions can accept a variable number of positional arguments by using ```*args``` in the def statement.\n", "2. You can use the items from a sequence as the positional arguments for a function with the ```*``` operator.\n", "3. Using the ```*``` operator with a generator may cause your program to run out of memory and crash.\n", "4. Adding new positional parameters to functions that accept ```*args``` can introduce hard-to-find bugs.\n", "\n", "### Thinks to remember(kwargs)\n", "\n", "1. Function arguments can be specified by position or by keyword.\n", "2. Keywords make it clear what the purpose of each argument is when it would be confusing with only positional arguments.\n", "3. Keyword arguments with default values make it easy to add new behaviors to a function, especially when the function has existing callers.\n", "4. Optional keyword arguments should always be passed by keyword instead of by position.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Context Manager\n", "\n", "While Python's context managers are widely used, few understand the purpose behind their use. These statements, commonly used with reading and writing files, assist the application in conserving system memory and improve resource management by ensuring specific resources are only in use for certain processes.\n", "\n", "### with statement\n", "\n", "A context manager is an object that is notified when a context (a block of code) starts and ends. You commonly use one with the with statement. It takes care of the notifying.\n", "\n", "For example, file objects are context managers. When a context ends, the file object is closed automatically:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> with open(filename) as f:\n", ">>> file_contents = f.read()\n", "\n", "# the open_file object has automatically been closed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Anything that ends execution of the block causes the context manager's exit method to be called. This includes exceptions, and can be useful when an error causes you to prematurely exit from an open file or connection. Exiting a script without properly closing files/connections is a bad idea, that may cause data loss or other problems. By using a context manager you can ensure that precautions are always taken to prevent damage or loss in this way.\n", "\n", "### Writing your own contextmanager using generator syntax\n", "\n", "It is also possible to write a context manager using generator syntax thanks to the ```contextlib.contextmanager``` decorator:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> import contextlib\n", ">>> @contextlib.contextmanager\n", "... def context_manager(num):\n", "... print('Enter')\n", "... yield num + 1\n", "... print('Exit')\n", ">>> with context_manager(2) as cm:\n", "... # the following instructions are run when the 'yield' point of the context\n", "... # manager is reached.\n", "... # 'cm' will have the value that was yielded\n", "... print('Right in the middle with cm = {}'.format(cm))\n", "Enter\n", "Right in the middle with cm = 3\n", "Exit\n", "\n", ">>>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## `__main__` Top-level script environment\n", "\n", "`__main__` is the name of the scope in which top-level code executes.\n", "A module’s __name__ is set equal to `__main__` when read from standard input, a script, or from an interactive prompt.\n", "\n", "A module can discover whether or not it is running in the main scope by checking its own `__name__`, which allows a common idiom for conditionally executing code in a module when it is run as a script or with `python -m` but not when it is imported:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> if __name__ == \"__main__\":\n", "... # execute only if run as a script\n", "... main()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a package, the same effect can be achieved by including a __main__.py module, the contents of which will be executed when the module is run with -m\n", "\n", "For example we are developing script which is designed to be used as module, we should do:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> # Python program to execute function directly\n", ">>> def add(a, b):\n", "... return a+b\n", "...\n", ">>> add(10, 20) # we can test it by calling the function save it as calculate.py\n", "30\n", ">>> # Now if we want to use that module by importing we have to comment out our call,\n", ">>> # Instead we can write like this in calculate.py\n", ">>> if __name__ == \"__main__\":\n", "... add(3, 5)\n", "...\n", ">>> import calculate\n", ">>> calculate.add(3, 5)\n", "8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Advantages\n", "\n", "1. Every Python module has it’s `__name__` defined and if this is `__main__`, it implies that the module is being run standalone by the user and we can do corresponding appropriate actions.\n", "2. If you import this script as a module in another script, the __name__ is set to the name of the script/module.\n", "3. Python files can act as either reusable modules, or as standalone programs.\n", "4. if `__name__ == “main”:` is used to execute some code only if the file was run directly, and not imported.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## setup.py\n", "\n", "The setup script is the centre of all activity in building, distributing, and installing modules using the Distutils. The main purpose of the setup script is to describe your module distribution to the Distutils, so that the various commands that operate on your modules do the right thing.\n", "\n", "The `setup.py` file is at the heart of a Python project. It describes all of the metadata about your project. There a quite a few fields you can add to a project to give it a rich set of metadata describing the project. However, there are only three required fields: name, version, and packages. The name field must be unique if you wish to publish your package on the Python Package Index (PyPI). The version field keeps track of different releases of the project. The packages field describes where you’ve put the Python source code within your project.\n", "\n", "This allows you to easily install Python packages. Often it's enough to write:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%bash\n", "python setup.py install" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and module will install itself.\n", "\n", "Our initial setup.py will also include information about the license and will re-use the README.txt file for the long_description field. This will look like:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from distutils.core import setup\n", ">>> setup(\n", "... name='pythonCheatsheet',\n", "... version='0.1',\n", "... packages=['pipenv',],\n", "... license='MIT',\n", "... long_description=open('README.txt').read(),\n", "... )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Find more information visit [http://docs.python.org/install/index.html](http://docs.python.org/install/index.html).\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Dataclasses\n", "\n", "`Dataclasses` are python classes but are suited for storing data objects.\n", "This module provides a decorator and functions for automatically adding generated special methods such as `__init__()` and `__repr__()` to user-defined classes.\n", "\n", "### Features\n", "\n", "1. They store data and represent a certain data type. Ex: A number. For people familiar with ORMs, a model instance is a data object. It represents a specific kind of entity. It holds attributes that define or represent the entity.\n", "\n", "2. They can be compared to other objects of the same type. Ex: A number can be greater than, less than, or equal to another number.\n", "\n", "Python 3.7 provides a decorator dataclass that is used to convert a class into a dataclass.\n", "\n", "python 2.7" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> class Number:\n", "... def __init__(self, val):\n", "... self.val = val\n", "...\n", ">>> obj = Number(2)\n", ">>> obj.val\n", "2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "with dataclass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> @dataclass\n", "... class Number:\n", "... val: int\n", "...\n", ">>> obj = Number(2)\n", ">>> obj.val\n", "2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### Default values\n", "\n", "It is easy to add default values to the fields of your data class." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> @dataclass\n", "... class Product:\n", "... name: str\n", "... count: int = 0\n", "... price: float = 0.0\n", "...\n", ">>> obj = Product(\"Python\")\n", ">>> obj.name\n", "Python\n", ">>> obj.count\n", "0\n", ">>> obj.price\n", "0.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Type hints\n", "\n", "It is mandatory to define the data type in dataclass. However, If you don't want specify the datatype then, use ```typing.Any```." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ ">>> from dataclasses import dataclass\n", ">>> from typing import Any\n", "\n", ">>> @dataclass\n", "... class WithoutExplicitTypes:\n", "... name: Any\n", "... value: Any = 42\n", "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "## Virtual Environment\n", "\n", "The use of a Virtual Environment is to test python code in encapsulated environments and to also avoid filling the base Python installation with libraries we might use for only one project.\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### virtualenv\n", "\n", "1. Install virtualenv" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pip install virtualenv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Install virtualenvwrapper-win (Windows)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pip install virtualenvwrapper-win" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Usage:\n", "\n", "1. Make a Virtual Environment" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mkvirtualenv HelloWold" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Anything we install now will be specific to this project. And available to the projects we connect to this environment.\n", "\n", "1. Set Project Directory" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "To bind our virtualenv with our current working directory we simply enter:\n", "\n", " setprojectdir ." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Deactivate" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "To move onto something else in the command line type ‘deactivate’ to deactivate your environment.\n", "\n", " deactivate\n", "\n", "Notice how the parenthesis disappear." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Workon" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Open up the command prompt and type ‘workon HelloWold’ to activate the environment and move into your root project folder\n", "\n", " workon HelloWold" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### pipenv\n", "\n", "> [Pipenv](https://pipenv.readthedocs.io/en/latest/) is a tool that aims to bring the best of all packaging worlds (bundler, composer, npm, cargo, yarn, etc.) to the Python world. Windows is a first-class citizen, in our world.\n", "\n", "1. Install pipenv" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pip install pipenv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Enter your Project directory and install the Packages for your project" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cd my_project\n", "pipenv install " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pipenv will install your package and create a Pipfile for you in your project’s directory. The Pipfile is used to track which dependencies your project needs in case you need to re-install them.\n", "\n", "1. Uninstall Packages" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pipenv uninstall " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Activate the Virtual Environment associated with your Python project" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pipenv shell" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. Exit the Virtual Environment" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "exit" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Find more information and a video in [docs.pipenv.org](https://docs.pipenv.org/).\n", "\n", "[*Return to the Top*](#python-cheatsheet)\n", "\n", "### anaconda\n", "\n", "[Anaconda](https://anaconda.org/) is another popular tool to manage python packages.\n", "\n", "> Where packages, notebooks, projects and environments are shared. \n", "Your place for free public conda package hosting.\n", "\n", "Usage:\n", "\n", "1. Make a Virtual Environment" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "conda create -n HelloWorld" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2. To use the Virtual Environment, activate it by:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "conda activate HelloWorld" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Anything installed now will be specific to the project HelloWorld\n", "\n", "3. Exit the Virtual Environment" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "conda deactivate\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[*Return to the Top*](#python-cheatsheet)" ] } ], "metadata": {}, "nbformat": 4, "nbformat_minor": 2 } ================================================ FILE: README.md ================================================ # Cheat-Sheets

A cheat sheets can be really helpful when you're trying a set of exercises related to a specific topic, or working on a project. Because you can only fit so much information on a single sheet of paper, most cheat sheets are a simple listing of syntax rules. This set of cheat sheets aims to remind you of syntax rules, but also remind you of important concepts as well. # Table of Contents * [Angular](https://github.com/black-shadows/Cheat-Sheets/tree/master/Angular) * [BigO](https://github.com/black-shadows/Cheat-Sheets/tree/master/BigO) * [Bits](https://github.com/black-shadows/Cheat-Sheets/tree/master/Bits) * [C++](https://github.com/black-shadows/Cheat-Sheets/tree/master/C%2B%2B) * [C](https://github.com/black-shadows/Cheat-Sheets/tree/master/C) * [Command Line](https://github.com/black-shadows/Cheat-Sheets/tree/master/Command%20Line) * [Django](https://github.com/black-shadows/Cheat-Sheets/tree/master/Django) * [Elixir](https://github.com/black-shadows/Cheat-Sheets/tree/master/Elixir) * [Git](https://github.com/black-shadows/Cheat-Sheets/tree/master/Git) * [Golang](https://github.com/black-shadows/Cheat-Sheets/tree/master/Golang) * [Java](https://github.com/black-shadows/Cheat-Sheets/tree/master/Java) * [JavaScript](https://github.com/black-shadows/Cheat-Sheets/tree/master/JavaScript) * [Kotlin](https://github.com/black-shadows/Cheat-Sheets/tree/master/Kotlin) * [MATLAB](https://github.com/black-shadows/Cheat-Sheets/tree/master/MATLAB) * [Markdown](https://github.com/black-shadows/Cheat-Sheets/tree/master/Markdown) * [Oracle SQL](https://github.com/black-shadows/Cheat-Sheets/tree/master/Oracle%20SQL) * [PHP](https://github.com/black-shadows/Cheat-Sheets/tree/master/PHP) * [Perl](https://github.com/black-shadows/Cheat-Sheets/tree/master/Perl) * [Python](https://github.com/black-shadows/Cheat-Sheets/tree/master/Python) * [React](https://github.com/black-shadows/Cheat-Sheets/tree/master/React) * [Ruby on Rails](https://github.com/black-shadows/Cheat-Sheets/tree/master/Ruby%20on%20Rails) * [Ruby](https://github.com/black-shadows/Cheat-Sheets/tree/master/Ruby) * [Scala](https://github.com/black-shadows/Cheat-Sheets/tree/master/Scala) * [Swift](https://github.com/black-shadows/Cheat-Sheets/tree/master/Swift) * [System Design](https://github.com/black-shadows/Cheat-Sheets/tree/master/System%20Design) # Contribute All contributions are welcome: * Read the issues, Fork the repository and do a Pull Request. * Request a new topic creating a New issue with the enhancement tag. * Find any kind of errors in the cheat sheets and create a New issue with the details or fork the repository and do a Pull Request. * Suggest a better or more organized way for existing examples. If you have any questions about the cheat sheets you can find here, feel free to contact me **abhisheksharma.0517@gmail.com**. ================================================ FILE: React/README.md ================================================ # 🌈 React Cheat Sheet > A simple cheat sheet for facilitate the process in the workshops and event about React. Let me know if you see any problem, I'll love a pull request for improve this document. ## Table of contents - [x] [Installation](#installation) - [x] [No configuration](#no-configuration) - [x] [ReactDOM](#reactdom) - [x] [Functional Stateless Component](#functional-stateless-component) - [x] [Class Component](#class-component) - [x] [Composition](#composition) - [x] [Module component](#module-component) - [x] [Hot Module Replacement](#hot-module-replacement) - [x] [Props](#props) - [x] [State](#state) - [x] [Methods and Events](#methods-and-events) - [x] [State manipulation](#state-manipulation) - [x] [Bindings](#bindings) - [ ] [Refs](#refs) - [ ] [Keys](#keys) - [ ] [Component Lifecycle](#component-lifecycle) - [ ] [Inline Styles](#inline-styles) - [ ] [React Router](#react-router) - [ ] [Storybook](#storybook) - [ ] [Tests](#tests) - [ ] [a11y](#a11y) - [ ] [API comunication](#api-comunication) - [ ] [Flux](#flux) - [ ] [Redux](#redux) - [ ] [MobX](#mobx) - [ ] [Best Practices](#best-practices) - [ ] [Concepts](Concepts) - [ ] [Immutable](#immutable) - [ ] [Functionnal programing](#functionnal-programing) - [ ] [Virtual Dom](#virtual-dom) - [x] [ES6](#es6) - [x] [Arrow Functions](#arrow-functions) - [x] [Syntax](#syntax) - [x] [Advanced Syntax](#advanced-syntax) - [x] [Spread Operations](#spread-operations) - [x] [Spread in array literals](#spread-in-array-literals) - [x] [Spread in object literals](#spread-in-object-literals) --- ## Installation * Add the tags in your HTML ```HTML ``` * Run this scripts in your terminal ```SSH $ npm install react react-dom ``` **[⬆ back to top](#table-of-contents)** --- ## No configuration Just start with React no configuration (run the scripts bellow in your terminal) * Install the React ```SSH $ npm install -g create-react-app ``` * Create your application (change `myApp` to your application name) ``` $ create-react-app myApp ``` * Go to the application folder and install the dependencies ``` $ cd myApp $ npm install ``` * Start your application ``` $ npm start ``` * Go to the browser by `URL` bellow and see your beautiful application - [localhost:8080](http://localhost:8080) **[⬆ back to top](#table-of-contents)** --- ## ReactDOM ```JS import React, { Component } from 'react'; import ReactDOM from 'react-dom'; ReactDOM.render(

Hello React Ladies

, document.getElementById('root') ); ``` **[⬆ back to top](#table-of-contents)** --- ## Functional Stateless Component ```JS import React from 'react'; const Button = () => export default Button; ``` ```JS import React from 'react'; const Button = ({ onClick, className = 'button', children }) => export default Button; ``` **[⬆ back to top](#table-of-contents)** --- ## Class Component ```JS import React, { Component } from 'react'; class MyComponent extends Component { render() { return (

Helo Devas

); } } export default MyComponent; ``` ```JS import React, { Component } from 'react'; class MyComponent () extends Compnent { constructor ( props ) { super(props); this.state = { message: 'Helo Devas' } }; render() { return (

{ this.state.message }

); } } export default MyComponent; ``` **[⬆ back to top](#table-of-contents)** --- ## Composition ```JS import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class Love extends Component { render() { return (

My love

); } } class LoveList extends Component { render() { return (
); } } ReactDOM.render( , document.getElementById(´root´) ); **[⬆ back to top](#table-of-contents)** ``` ## Module component ```JS //App.js import React, { Component } from 'react'; class App extends Component { render() { return (

My App

); } } export default App ``` ```JS //Index.js import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; class Index extends Component { render() { return (
); } } ReactDOM.render ( , document.getElementById('root') ); ``` **[⬆ back to top](#table-of-contents)** --- ## Hot Module Replacement * Retain application state which is lost during a full reload. * Save valuable development time by only updating what's changed. * Tweak styling faster -- almost comparable to changing styles in the browser's debugger. ```JS import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import MyComponent from './MyComponent'; ReactDOM.render( , document.getElementById('root') ); if (module.hot) { module.hot.accept(); } ``` **[⬆ back to top](#table-of-contents)** --- ## Props ```JS import React, { Component } from 'react'; class App extends Component { render() { return (

My App {this.props.name}

); } } class Index extends Component { render() { return (
); } } export default Index; ``` **[⬆ back to top](#table-of-contents)** --- ## State ```JS import React, { Component } from 'react'; class App extends Component { constructor(props) { super(props); this.state = {messages: 0}; } render() { return (

My messages: {this.state.messages}

); } } export default App; ``` **[⬆ back to top](#table-of-contents)** --- ## Methods and Events ```JS import React, { Component } from 'react'; class App extends Component { escreve() { console.log("Eu te amo"); } render() { return (
); } } export default App; ``` **[⬆ back to top](#table-of-contents)** --- ## State manipulation ```JS import React, { Component } from 'react'; class App extends Component { constructor() { super(); this.state = { like: 0 }; } isLiked = () => { this.setState({ like: this.state.like + 1}); } render() { return (
); } } export default App; ``` ```JS import React, { Component } from 'react'; class App extends Component { constructor() { super(); this.state = { messages: ['JS', 'React'] }; } addMessages = () => { const updateMessages = [...this.state.messages, 'Polymer'] this.setState({ messages: [...updateMessages] }) } render() { return (
{console.log(this.state.messages) /* ['JS', 'React', 'Polymer'] */}
); } } export default App; ``` **[⬆ back to top](#table-of-contents)** --- d ## Bindings ```JS import React, { Component } from 'react'; class MyComponent extends Component { constructor () { super(); this.state = { list: list }; this.doSomethingElse = this.doSomethingElse.bind(this); }; doSomething = () => { // do something /* if don't have a parameter, you can use arrow function and don't need to use bind */ } doSomethingElse ( itemId ) { // do something else } render() { return (
{this.state.list.map( item => ... ... )}
); } } export default MyComponent; ``` --- # ES6 ## Arrow Functions ### Syntax #### Basic syntax ```JS ( param1, param2, ..., paramN ) => { statements } ( param1, param2, ..., paramN ) => expression ( singleParam ) => { statements } singleParam => { statements } () => { statements } ``` #### Advanced Syntax ```JS params => ({ foo: bar }) /* return an object literal expression */ ( param1, param2, ...ladies ) => { statements } /* rest parameters */ ( language = JS, ladies, ..., framework = React ) => { statements } /* default parameters */ const sum = ( [num1, num2] = [1, 2], { x: num3 } = { x : num1 + num2 } ) => num1 + num2 + num3 /* destructuring within the parameter list */ sum() /* 6 */ ``` --- ## Spread Operations ### Spread in array literals ```JS const basics = [ 'JS', 'HTML', 'CSS' ]; const frameworks = [ 'React', 'Vue' ]; const web = [ ...basics, ...frameworks ]; console.log(web); /* ['JS', 'HTML', 'CSS', 'React', 'Vue'] */ const addWeb = [ ...web, 'al11' ]; console.log(addWeb); /* ['JS', 'HTML', 'CSS', 'React', 'Vue', 'al11'] */ ``` ### Spread in object literals ```JS const basics = { behavior: 'JS', markup: 'HTML' }; const style = 'CSS'; const web = { ...basics, style }; console.log(web); /* { behavior: "JS", markup: "HTML", style: "CSS" } */ const devFront = { framework: 'react', event: 'React Conf' }; const devBack = { framework: 'django', state: 'cool' }; const cloneDev = { ...devFront }; console.log(cloneDev); /* { framework: 'react', event: 'React Conf' } */ const merged = { ...devFront, ...devBack }; console.log(cloneDev); /* { framework: 'django', event: 'React Conf', state: 'cool' } */ ``` ================================================ FILE: React/react-placar.md ================================================ ![template-placar](img/template-placar.PNG) # React Placar > Um Simples exemplo de uso da biblioteca React.js by [Aprendendo React na prática - Props (Parte 8)](https://www.youtube.com/watch?v=eQV-UV0oz9k) Passos dos componentes: - Tudo começa no `App.js` que é o componente que possui os dados - Esses dados são passados como propriedade para o componente `PlacarContainer` - O componente `PlacarContainer` contém dois estados `gols_casa` e `gols_visitante` que são manipulados pelos métodos `marcarGolCasa` e `marcarGolVisitante` - O componente `PlacarContainer` contém mais dois componentes `Partida` e `Time` que recebem as propriedades que o componente `PlacarContainer` herdou do componente `App.js` - O componente `Time` utiliza a informação recebida por `PlacarContainer`, renderiza e repassa uma função para o componente `BotaoGol` informando como ele deve marcar um gol - O componente `BotaoGol` recebe a informação através de propriedade e segue os comandos repassados, que na verdade altera o estada do componente `PlacarContainer` ```JS `src/app.js` import React from 'react'; import ReactDOM from 'react-dom'; import App from './src/components/App'; ReactDOM.render(, document.getElementById('root')); ``` ```JS `src/components/App.js` import React, { Component } from 'react'; import PlacarContainer from './src/components/PlacarContainer'; class App extends Component { const dados = { partida: { estadio: "Maracanã/RJ", data: "22/05/2017", horario: "19h" }, casa: { nome: "Vasco" }, visitante: { nome: "Flamengo" } } render() { //- passando as propriedades do componente `App` para o componente `PlacarContainer` return ; } export default App; ``` ```JS `src/components/PlacarContainer.js` import React, { Component } from 'react'; import Time from './src/components/Time'; import Partida from './src/components/Partida'; class PlacarContainer extends Component { constructor() { super(); this.state = { gols_casa: 0, gols_visitante: 0 } marcarGolCasa() { this.setState({ gols_casa: this.setState.gols_casa + 1 }) } marcarGolVisitante() { this.setState({ gols_visitante: this.setState.gols_visitante + 1 }) } } render() { return (

casa

Visitante

) } export default PlacarContainer; ``` ```JS `src/components/Time.js` import React, { Component } from 'react'; import BotaoGol from './src/components/BotaoGol'; class Time extends Component { render() { return (

{this.props.nome}

{this.props.gols}

) } export default Time; ``` ```JS `src/components/Partida.js` import React, { Component } from 'react'; class Partida extends Component { render() { return (
h2>{this.props.estadio}
{this.props.data} - {this.props.horario}
) } export default Partida; ``` ```JS `src/components/BotaoGol.js` import React, { Component } from 'react'; class BotaoGol extends Component { thishandleClick(event) { event.preventDefault(); //- ação para cancelar o evento padrão do botão. this.props.marcarGol(); //- ao clicar irá acionar esse método que pertence ao componente PlacarContainer } render() { return (