Angular 2 学习笔记(二)

EcmaScript6

Classes

类是在ES6一个新功能,用来描述对象的蓝图,使ECMAScript中的原型继承模型的功能更像是一个传统的基于类的语言。

class Hamburger {

  constructor() {

    // This is the constructor.

  }

  listToppings() {

    // This is a method.

  }

}

 

Refresher on 'this'

(function() {

  'use strict';

  var myObject = {

    foo: 'bar',

    someMethod: function() {

      console.log(this);

    }

  };

 
  function someMethod() {

    console.log(this);

  }

 
  myObject.someMethod();

  someMethod(); // undefined

 
})();

 

View

class ServerRequest {

   notify() {

     ...

   }

   fetch() {

     getFromServer(function callback(err, data) {

        this.notify(); // this is not going to work

     });

   }

}

 

Arrow Function

class Toppings {

  toppings;

 

  constructor(toppings) {

    this.toppings = Array.isArray(toppings) ? toppings : [];

  }

 

  outputList(){

  //  this.toppings.forEach(function(topping, i) {

  //    console.log(topping, i + '/' + this.toppings.length); // no this

  //  })

    this.toppings

      .forEach((topping, i) => console.log(topping, i + '/' + this.toppings.length)) // `this` works

  }

}

 

var ctrl = new Toppings(['cheese','letture']);

 

ctrl.outputList();

View

Template Strings

var name = 'Sam';

var age = 42;

 

console.log('hello my name is ' + name + ', and I am ' + age + ' years old');

 

console.log(`hello my name is ${name}, and I am ${age} years old`);

View

Inheritance

JavaScript's inheritance works differently from inheritance in other languages, which can be very confusing. ES6 classes provide a syntactic sugar attempting to alleviate the issues with using prototypical inheritance present in ES5. Our recommendation is still to avoid using inheritance or at least deep inheritance hierarchies. Try solving the same problems through delegation instead.

Constants and Block Scope Veribles

var i;

for(i = 0; i < 10; i++) {

    var j = i;

    let k = i;

}

 

console.log(j); // 9

console.log(k); //undefined

for(var x=0; x<5; x++) {

  setTimeout(()=>console.log(x), 0)

}

for(let y=0; y<5; y++) {

  setTimeout(()=>console.log(y), 0)

}

View

...spread and ...rest

const add = (a, b) => a + b;

let args = [3, 5];

add(...args); // same as `add(args[0], args[1])`, or `add.apply(null, args)`

let cde = ['c', 'd', 'e'];

let scale = ['a', 'b', ...cde, 'f', 'g']; // ['a', 'b', 'c', 'd', 'e', 'f', 'g']

let mapABC  = { a: 5, b: 6, c: 3};

let mapABCD = { ...mapABC, d: 7}; // { a: 5, b: 6, c: 3, d: 7 }

function addSimple(a, b) {

  return a + b;

}

 

function add(...numbers) {

  return numbers[0] + numbers[1];

}

 

addSimple(3, 2);  // 5

add(3, 2);        // 5

 

// or in es6 style:

const addEs6 = (...numbers) => numbers.reduce((p, c) => p + c, 0);

 

addEs6(1, 2, 3);  // 6

function print(a, b, c, ...more) {

  console.log(more[0]);

  console.log(arguments[0]);

}

 

print(1, 2, 3, 4, 5);

View

Destructuring

let foo = ['one', 'two', 'three'];

 

let one   = foo[0];

let two   = foo[1];

let three = foo[2];

into

let foo = ['one', 'two', 'three'];

let [one, two, three] = foo;

console.log(one); // 'one'

let myModule = {

  drawSquare: function drawSquare(length) { /* implementation */ },

  drawCircle: function drawCircle(radius) { /* implementation */ },

  drawText: function drawText(text) { /* implementation */ },

};

 

let {drawSquare, drawText} = myModule;

 

drawSquare(5);

drawText('hello');

View

Modules

ES6 also introduces the concept of a module, which works similar to other languages. Defining an ES6 module is quite easy: each file is assumed to define a module and we specify its exported values using the export keyword.

Loading ES6 modules is a little trickier. In an ES6-compliant browser you use the System keyword to load modules asynchronously. To make our code work with current browsers, however, we will use SystemJS library as a polyfill:

<script src="/node_module/systemjs/dist/system.js"></script>

  <script>

    var promise = System.import('app')

      .then(function() {

        console.log('Loaded!');

      })

      .then(null, function(error) {

        console.error('Failed to load:', error);

      });

  </script>

TypeScript

Angular 2 is built in TypeScript

 

npm install -g typescript

Without TS:

function add(a, b) {

  return a + b;

}

 

add(1, 3);   // 4

add(1, '3'); // '13'

With TS:

function add(a: number, b: number) {

  return a + b;

}

 

add(1, 3);   // 4

// compiler error before JS is even produced

add(1, '3'); // '13'

Types

  • boolean (true/false)
  • number integers, floats, Infinity and NaN
  • string characters and strings of characters
  • [] Arrays of other types, like number[] or boolean[]
  • {} Object literal
  • undefined not set
  • enum enumerations like { Red, Blue, Green }
  • any use any type
  • void nothing

let isDone: boolean = false;

let height: number = 6;

let name: string = "bob";

let list: number[] = [1, 2, 3];

let list: Array<number> = [1, 2, 3];

enum Color {Red, Green, Blue};

let c: Color = Color.Green;

let notSure: any = 4;

notSure = "maybe a string instead";

notSure = false; // okay, definitely a boolean

 

function showMessage(data: string): void {

  alert(data);

}

showMessage('hello');

function logMessage(message: string, isDebug?: boolean) {

  if (isDebug) {

    console.log('Debug: ' + message);

  } else {

    console.log(message);

  }

}

logMessage('hi');         // 'hi'

logMessage('test', true); // 'Debug: test'

Using a ? lets tsc know that isDebug is an optional parameter. tsc will not complain if isDebug is omitted.

Classes

class Person {

  name: string;

  nickName?: string;

}

Interface

interface Callback {

  (error: Error, data: any): void;

}

 

function callServer(callback: Callback) {

  callback(null, 'hi');

}

callServer((error, data) => console.log(data)); // 'hi'

callServer('hi');                               // tsc error

interface PrintOutput {

  (message: string): void;    // common case

  (message: string[]): void// less common case

}

 

let printOut: PrintOutput = (message) => {

  if (Array.isArray(message)) {

    console.log(message.join(', '));

  } else {

    console.log(message);

  }

}

 

printOut('hello');       // 'hello'

printOut(['hi', 'bye']); // 'hi, bye'

interface Action {

  type: string;

}

 

let a: Action = {

    type: 'literal' 

}

Shapes

Underneath TypeScript is JavaScript, and underneath JavaScript is typically a JIT (Just-In-Time compiler). Given JavaScript's underlying semantics, types are typically reasoned about by "shapes". These underlying shapes work like TypeScript's interfaces, and are in fact how TypeScript compares custom types like classes and interfaces.

interface Action {

  type: string;

}

 

let a: Action = {

    type: 'literal' 

}

 

class NotAnAction {

  type: string;

  constructor() {

    this.type = 'Constructor function (class)';

  }

}

 

a = new NotAnAction(); // valid TypeScript!

Despite the fact that Action and NotAnAction have different identifiers, tsclets us assign an instance of NotAnAction to a which has a type of Action. This is because TypeScript only really cares that objects have the same shape. In other words if two objects have the same attributes, with the same typings, those two objects are considered to be of the same type.

Decorators

Property Decorators

function Override(label: string) {

  return function (target: any, key: string) {

    Object.defineProperty(target, key, { 

      configurable: false,

      get: () => label

    });

  }

}

 

class Test {

  @Override('test')      // invokes Override, which returns the decorator

  name: string = 'pat';

}

 

let t = new Test();

console.log(t.name);  // 'test'

function ReadOnly(target: any, key: string) {

  Object.defineProperty(target, key, { writable: false });

}

 

class Test {

  @ReadOnly             // notice there are no `()`

  name: string;

}

 

const t = new Test();

t.name = 'jan';         

console.log(t.name); // 'undefined'

Class Decorators

function log(prefix?: string) {

  return (target) => {

    // save a reference to the original constructor

    var original = target;

 

    // a utility function to generate instances of a class

    function construct(constructor, args) {

      var c : any = function () {

        return constructor.apply(this, args);

      }

      c.prototype = constructor.prototype;

      return new c();

    }

 

    // the new constructor behavior

    var f : any = function (...args) {

      console.log(prefix + original.name);

      return construct(original, args);

    }

 

    // copy prototype so instanceof operator still works

    f.prototype = original.prototype;

 

    // return new constructor (will override original)

    return f;

  };

}

 

@log('hello')

class World {

}

 

const w = new World(); // outputs "helloWorld"

In the example log is invoked using @, and passed a string as a parameter, @log() returns an anonymous function that is the actual decorator.

The decorator function takes a class, or constructor function (ES5) as an argument. The decorator function then returns a new class construction function that is used whenever World is instantiated.

This decorator does nothing other than log out its given parameter, and its target's class name to the console.

Parameter Decorators

function logPosition(target: any, propertyKey: string, parameterIndex: number) {

  console.log(parameterIndex);

}

 

class Cow {

  say(b: string, @logPosition c: boolean) {

    console.log(b); 

  }

}

 

new Cow().say('hello', false); // outputs 1 (newline) hello

The above demonstrates decorating method parameters. Readers familiar with Angular 2 can now imagine how Angular 2 implemented their @Inject() system.

posted @ 2016-04-25 16:43  Violet_QQY  阅读(189)  评论(0编辑  收藏  举报