Upload
mehdivk
View
577
Download
0
Embed Size (px)
DESCRIPTION
Citation preview
|
COFFEESCRIPTAN INTRODUCTION FOR NODE DEVELOPERS
BY: MEHDI VALIKHANISOFTWARE ENGINEER @ ALPHATISE
Follow me: @mehdivk [email protected]
IT'S JUST JAVASCRIPTCOFFEESCRIPT IS A PROGRAMMING LANGUAGE THAT
TRANSCOMPILES TO JAVASCRIPT.
SYNTACTIC SUGAR TO JAVASCRIPT
IT'S MATURE AND PRODUCTION-READY
DEVELOPED BY: JEREMY ASHKENAS
INITIAL COMMIT: DECEMBER 13TH, 2009FIRST RELEASE: DECEMBER 24H, 2009
VERSION 1.0: FEBRUARY 2010CURRENT VERSION: 1.8
WHO'S USINGCOFFEESCRIPT?
DROPBOXGITHUB
WRITE LESS, DO MOREHUMAN-READABLE CODE
STAY AWAY FROM WEIRD JS BEHAVIOUR
SAY GOODBYE TO PROTOTYPE! USE CLASSES
ANY MANY MORE ...
COFFEESCRIPT SYNTAX
NO MORE VAR ; ( )
async = require 'async' console.log async.VERSION
var async = require('async'); console.log(async.VERSION);
FUNCTIONSIT'S PART OF OUR EVERYDAY LIFE IN JS WORLD
LET'S BE AGILE!
addUser = (user, cb) -> model = new User #DO SOMETHING model.save (err, result) -> cb null, result
var addUser = function(user, cb) { var model = new User(); //DO SOMETHING model.save(function(err, result){ cb(err, result); }); }
IMPLICIT RETURN
someFunction = (param1, param2) -> param1 * param2 * param2 console.log someFunction 100, 200
var someFunction; someFunction = function(param1, param2) { return param1 * param2 * param2; } console.log(someFunction(100, 200));
OBJECTSGET RID OF THOSE { } ,
bus = routeNumber: 273 from: 'Wynyard' to: 'Chatswood' via: 'North Sydney, Pacific Highway'
var bus = { routerNumber: 273, from: 'Wynyad', to: 'Chatswood', via: 'North Sydney, Pacific Highway' }
query = status: $in: ['active', 'pending_for_approval'] payment: $nin: ['invoice', 'free'] tc: $exists: true
var query = { status: { $in: ['active', 'pending_for_approval'] }, payment: { $nin: ['invoice', 'free'] }, tc: { $exists: true } }
STRING INTERPOLOATION
meetup = 'Node' msg = "#{meetup} meeup is awsome!" console.log msg
var meetup = 'Node'; var msg = meetup + ' meetup is awsome!'; console.log(msg);
CLASSESBETTER INHERITANCE WITHOUT PROTOTYPE
WE SHOULDN'T USE LIBRARIES TO HAVE CLASSES IN JS
class Cache generateCacheKey: (key) -> throw new Error 'Not Implemented' getPeriod: -> 120 * 60 store: (key, data) -> throw new Error 'Not Implemented' clearCache: (key) -> #DO SOMETHING
class RedisCache extends Cache generateCacheKey: (key) -> "redis_cache_#{key}" store: (key, data) -> period = @.getPeriod() #STORE IN REDIS
DESTRUCTURING OBJECTS
{Router} = require 'express' router = new Router
var express = require('express'); var Router = experss.Router; router = new Router();
DESTRUCTURING ARRAYS
student = 'Mehdi Valikhani' [firstName, lastName] = student.split ' '
var student, ref, firstName, lastName; student = 'Mehdi Valikhani'; ref = student.split(' '); firstName = ref[0]; lastName = ref[1];
DESTRUCTING ARGUMENTS
calculator = ({width, height}) -> width * height options = width: 10 height: 5 alert calculator options
EXISTENTIAL OPERATOR ?REMOVE THOSE NULL OR UNDEFINED CHECKES FROM CODE
if err? #log to logger cb err
if (typeof err !== "undefined" && err !== null) //log to logger cb(err);
INSTALL COFFEESCRIPTnpm install -g coffee-script
EXECUTE A SCRIPTcoffee /path/to/script.coffee
COMPILE A SCRIPTcoffee -c /path/to/script.coffee
NODE + COFFEEFROM SCRATCH
REST API DEVELOPMENT USING EXPRESS + NODE + COFFEE
CODE STRUCTURE
+ lib + books Book.coffee //Our Mongoose Model router.coffee //router for books API+ node_modules + body-parser //from JSON responses + coffee-script //compiler of Coffee files + express //express frameworkapp.coffee //express app configpackage.json // NO DESCRIPTIONindex.js //ACTUAL MAGIC HAPPENS HERE!
app.coffee
bodyParser = require 'body-parser'express = require 'express'userRouter = require './lib/books/router'
app = express()app.use bodyParser.json()app.use '/users', userRouter
module.exports = app
lib/books/router.coffee
{Router} = require 'express'Book = require './Book'router = new Router
fetchBook = (req, res, next) -> req.paramBook = Book next()
getBook = (req, res) -> res.json(req.paramBook)
router.route('/:book_id') .all(fetchBook) .get(getBook)
module.exports = router
index.js
require('coffee-script/register'); var app = require('./app'); app.listen(1984, function(){ console.log('App is available via http://127.0.0.1:1984'); });
RUN THE APPnode index.js
nodemon -e js,coffee index.js
NODE + COFFEE
AN EXISTING PROJECT
ADD FOLLOWING CODE TO YOUR STARTER FILErequire('coffee-script/regiter');
THAT'S IT!Add .coffee files, write your code in coffeerequire other .js or .coffee files as always
RUN THE APPnode index.js
nodemon -e js,coffee index.js
DEBUGGINGCOFFEESCRIPTAPPLICATIONS
USE "DEBUGGER" AS ALWAYS
fetchBook = (req, res, next) -> debugger req.paramBook = Book next()
node debug index.js
BUT DON'T FORGET!in debug mode, you will be faced with compiled
JS code
break in lib/books/router.coffee:11 9 10 fetchBook = function(req, res, next) { 11 debugger; 12 req.paramBook = Book; 13 return next(); debug> repl Press Ctrl + C to leave debug repl > req.params.book_id '123' >
JAVASCRIPT SCOPINGin JavaScript, the scope of a variable is
defined by its location within the source code(it is apparent lexically) and nested
functions have access to variables declared intheir outer scope. - mozilla.org
Question: What's result of running this code?
name = 'Alex'
greeting = -> name = 'James' console.log "Hey #{name}!"
greeting() console.log "Hey #{name}!"
A:> Hey James!> Hey James!
B:> Hey James!> Hey Alex!
"A" IS CORRECT ANSWER> Hey James!> Hey James!
THIS IS COMPILED-TO-JS VERSION OF ABOVECODE
var greeting, name;
name = 'Alex';
greeting = function() { name = 'James'; return console.log("Hey " + name + "!");};
greeting();
console.log("Hey " + name + "!");
TWO IMPORTANT FACTS ABOUT COFEESCRIPT SCOPING
Variable shadowing is not allowed
variable is created at the moment of the first assignment to it
"VARIABLE SHADOWING IS NOT ALLOWED"
DOESN'T MEAN
YOU CAN'T DEFINE A VARIABLE MORE THANONCE IN DIFFERENT FILES
IT MEANS
YOU CAN'T DEFINE IT MORE THAN ONCE IN ASINGLE FILE
SO WHAT SHOULD I DO IF I WANT TO HAVESHADOWS?
It's not a good practice, don't do that!
It decreases readbility of your code!
Brings more confusion to your code
With shadowing you can't access our variables anymore (withsame name)
USE `` TO BRING VAR BACK
name = 'Alex'
greeting = -> ̀ ` name = 'James' console.log "Hey #{name}!"
greeting() console.log "Hey #{name}!"
var name
It a kind of hack! Don't do that!
SHADOW IT USING FUNCTION PARAMETER
name = 'Alex'
greeting = (name = '')-> name = 'James' console.log "Hey #{name}!"
greeting() console.log "Hey #{name}!"
Better first solution!
USE COFEESCRIPT'S CLOSURE FEATUREThis is much much better!
name = 'Alex'
greeting = -> do (name = '') -> name = 'James' console.log "Hey #{name}!"
greeting() console.log "Hey #{name}!"
MORE INFO ABOUT LEXICAL SCOPING:
https://github.com/raganwald-deprecated/homoiconic/blob/master/2012/09/actually-YOU-dont-understand-lexical-scope.md
https://github.com/raganwald-deprecated/homoiconic/blob/master/2012/09/lexical-scope-in-coffeescript.md
USEFUL RESOURCESYour best friend
Don't translate CoffeeScript to JS, try to learn as new langage
Teaches CoffeeScript as new language instrad of translating toJS
Best Practices
CoffeeScript Docs
CoffeeConsole: A Google Chrome Extention
CoffeeScript Ristretto
The Little Book On CoffeeScript
CoffeeScript Style Guide
Thank you!