Q:

O que é o JSONP e como funciona?

O que é JSONP, como se usa e porque usar JSONP em vez de AJAX?

A:

JSONP (JSON com padding) é uma técnica destinada a contornar uma limitação do uso de Ajax nos browsers: o fato de que a Política de Mesma Origem não permite que o domínio A faça uma requisição Ajax pro domínio B. Antes do CORS ("compartilhamento de recursos de origem cruzada") ser proposto - e suportado pelos principais browsers - não havia um meio fácil e seguro de se contornar essa limitação, e mesmo nos dias de hoje o suporte a essa técnica é relativamente raro.
Dada essa limitação, concebeu-se uma maneira de contorná-la aproveitando-se do fato de que a tag script é uma das poucas que está isenta da Política de Mesma Origem (e assim permanece por razões históricas, apesar do impacto negativo que isso tem na segurança da web em geral). Ora, se o interesse principal do Ajax é dar acesso programático a um determinado conteúdo, e um site pode incluir scripts de outro site sem nenhuma restrição, então por que não enviar esse conteúdo na forma de um script? Como todo JavaScript na página possui o mesmo contexto de execução (não importando sua origem), o código vindo do site B pode chamar funções definidas pelo site A, usando essas funções para comunicar o conteúdo consultado.
Uma descrição detalhada da técnica, com exemplos, pode ser vista na resposta do Sergio. Quanto a por que usar, é necessário se observar alguns pontos:

O nome JSONP é inapropriado, pois embora os dados retornados sejam referidos como "JSON" na realidade são apenas literais para objetos JavaScript, e não strings (texto), que costumam ser incluídos no script. E de todo modo, o "combinado" é que o retorno seja apenas o objeto (o "JSON") dentro de uma chamada de função (o "padding"), tipo:

Mas se o site quiser "fugir do combinado" - por exemplo usando algum outro código que construa esse objeto e repasse-o à função indicada como callback - nada o impede de fazer isso. E isso é relevante porque...
Um script em uma página é um código arbitrário executando no computador do usuário; e mais, todo script tem acesso irrestrito não só ao DOM mas também ao contexto de execução (compartilhado pelos demais scripts) e também aos cookies (com exceção dos marcados como HttpOnly), histórico de navegação, armazenamento permanente (local storage, IndexedDB, etc) e até mesmo a capacidade de navegar o browser para outra página de sua escolha (dentro ou fora do site), dentre outras capacidades.
Por essa razão, a primeira pergunta a se fazer antes de usar JSONP é se você confia no domínio consultado, ou se é o seu domínio que oferecerá suporte a JSONP, como fazer com que os terceiros que irão consumir seu conteúdo confiem no seu site. Lembrando que não basta o conteúdo servido por esse domínio ser correto hoje, se no futuro ele tiver seu servidor comprometido, por exemplo, os usuários de todos os sites que consomem seu conteúdo por JSONP estarão vulneráveis a um ataque arbitrário e indeterminado.
Sendo assim, minha resposta a por que usar é simplesmente: só use se não tiver outro jeito...
A forma preferencial de se fazer requisições a domínios diferentes é mesmo o CORS. Dá um trabalhinho extra configurá-lo corretamente, e agentes de usuário mais antigos podem não dar suporte apropriado a essa técnica, mas à medida que o tempo passa esse problema se torna cada vez menor (tanto pela fração de usuários que utilizam browsers modernos, como pela evolução das plataformas no lado servidor no sentido de dar esse suporte e facilitar a configuração). Se for possível usar CORS, use.
Muitos sites não foram feitos pensando em compartilhar seu conteúdo através de uma API Ajax. O uso de JSONP exige suporte do servidor, não é algo que possa ser feito somente no lado consumidor da informação. De modo que se esse suporte não existe atualmente, temos duas opções principais:

Usar seu próprio domínio como proxy para o domínio externo; nesse caso não é necessário usar JSONP, CORS, nem nada de especial, pois o seu servidor consultará o domínio externo como se fosse um usuário pelo browser, e repassará ao usuário real via Ajax comum. Não é o ideal, dada a carga extra que isso coloca no seu servidor, mas em algumas circunstâncias pode ser a única opção.
Pedir ao domínio externo que atualize seu sistema para dar suporte a requisições Ajax de fora do seu domínio. Aí entra a seguinte questão: se uma funcionalidade nova está sendo implementada, pra quer usar a abordagem insegura quando é não só preferível mas também muito mais fácil (já que basta incluir alguns headers adicionas, sem mudança no código Ajax existente) simplesmente habilitar CORS? De novo, a menos que seja um requisito explícito do seu projeto dar suporte a browsers antigos, não há razão pra se usar JSONP.

Por fim, algumas coisas poderiam ser feitas para mitigar os riscos de se usar JSONP, mas nada 100% à prova de falhas, e de todo modo as soluções mais seguras demandariam suporte a recursos modernos de HTML5 de qualquer forma, e um browser que suporte esses recursos provavelmente também suportará CORS. Um exemplo (disclaimer: não estou sugerindo usar esse código na prática!) seria delegar a um iframe a tarefa de fazer a chamada JSONP, numa tentativa de isolar o código do restante da página:
teste_jsonp.html
function testeJSONP(url, callback) {
    var iframe = document.createElement("iframe");
    iframe.style.display = "none";
    iframe.src = "jsonp_seguro.html";
    iframe.sandbox = "allow-scripts"; // Proíbe tudo, exceto a execução de scripts
    iframe.onload = function() {
        // Se comunica com o iframe através de postMessage
        window.addEventListener("message", function(event) {
            callback(JSON.parse(event.data));
        }, false);
        iframe.contentWindow.postMessage(url, "*");
    };
    document.body.appendChild(iframe);
}

testeJSONP('http://ip.jsontest.com/?callback=showIP', function(dados) {
    console.log(dados);
});

jsonp_seguro.html
window.addEventListener("message", function(event) {
    window.showIP = function(dados) {
        // Repassa os dados recebidos para a página principal
        // (note que isso força esses dados a serem passados como string)
        event.source.postMessage(JSON.stringify(dados), "*");

        /**** E se o domínio for desonesto? E em vez de retornar um JSON: ****/

        // Tenta fazer várias coisas maliciosas
        try { var target = window.opener || top; target.location.href = "http://google.com"; } catch(e) { console.log(e); }
        try { var cookies = document.cookie; } catch(e) { console.log(e); }
        try { var teste = localStorage.getItem('teste'); } catch(e) { console.log(e); }

        // Essas ele ainda consegue... :(
        /*try { alert("SPAM!"); } catch(e) { console.log(e); }
        try { history.go(-1); } catch(e) { console.log(e); }*/
    };

    // Aqui é feita a chamada JSONP de fato; fonte: resposta do Sergio
    var script = document.createElement('script');
    script.src = event.data;
    document.body.appendChild(script);

}, false);

Exemplo (abra o console se quiser ver como as ações maliciosas foram bloqueadas).
Reiterando: não tente "emendar" medidas de segurança pra proteger o JSONP, só use essa técnica em conjunto com sites em que você confia.

A:

O JSONP é uma alternativa para enviar e receber dados em browsers antigos, e/ou sites que têm CORS desativado.
Se o browser estiver por exmeplo no dominio meusite.com e quisermos receber dados de outro dominio (por exemplo: teusite.net) muitos browsers vão dar erro (versões antigas do IE não conseguiam fazer chamadas AJAX para domínios diferentes). O erro pode ser porque o CORS está desativado, ou porque o browser é velhinho e não pode fazer pedidos a domínios diferentes. Sites com CORS desativado não permitem trocar dados via AJAX.
Mas há uma excepção nos browsers para ir buscar conteúdo a sites de outros domínios. As tags <script> permitem ir buscar JavaScript a outros domínios.
O JSONP explora exatamente esta possibilidade.
Se adicionarmos um script à página o browser vai correr esse script. Então o que temos de fazer é que o servidor retorne algo que dê para correr.
A maneira que se encontrou foi via callback defenida no query string do url do script e completada pelo servidor. Ou seja, o cliente procura por exemplo este url:
http://teusite.net/?cliente=2336&produto=45&quantidade=73&callback=temp_callback

Neste url em cima juntei alguns dados na query string para o servidor processar. Juntei também um parâmetro temp_callback que é o nome que dei a uma função que criei só para este fim.
O servidor irá responder uma string que o browser usa como JavaScript, e agora já sabe qual o nome da função que eu quero usar e retorna-me este texto:
temp_callback({preco: 300});

Quando isto é inserido no script da página, é corrido e pode ser usado no resto do JavaScript. Note-se que essa função temp_callback tem de estar defenida na página e no escopo global para o browser a poder correr.
Exemplo no lado do cliente
window.showIP = function (resposta) {
    alert('O seu IP é: ' + resposta.ip);
};

var src = 'http://ip.jsontest.com/?callback=showIP'; // este é um exemplo que funciona, mas aqui deve ser o url que queres usar
var script = document.createElement('script');
script.src = src;
document.body.appendChild(script);

jsFiddle: http://jsfiddle.net/s14totoy/
Exemplo de código no lado do servidor:
(o servidor retorna uma string que deve ser JavaScript válido, ou seja: o nome da função, abrir parentesis, o que é passado à função, fechar parentesis).
PHP:
$resposta = '{preco:'.$preco.'}';
echo $_REQUEST["callback_a"].'('.$resposta.')';

NodeJS (com express.js):
res.jsonp(req.query.callback + '('+ objPreco + ');');

Para terminar e se fôr uma opção deve usar-se CORS em vêz de JSONP pois uma chamada AJAX é um interface mais completo que permite métodos diferentes e dá códigos de erro e estado da ligação que o JSONP nõ permite.

Extras:

evitar duplicados:

Por vezes há vários pedidos JSONP a correr perto uns dos outros eu costumo defenir a callback assim, para evitar duplicados e erros no código:
var callbackName = 'temp_callback_' + new Date().getTime() + Math.floor(Math.random() * 100);

exemplo completo:

Uma versão completa pronta a usar:
function jsonp(url, dados, callback) {
    function toQueryString(object) {
        return Object.keys(object).map(function (prop) {
            return prop + '=' + object[prop];
        }).join('&');
    }

    var resposta;
    var queryStr = dados ? toQueryString(dados) + '&' : '';
    var nomeDaCallback = 'temp_callback_' + new Date().getTime() + Math.floor(Math.random() * 100);
    window[nomeDaCallback] = function (res) {
        delete window[nomeDaCallback];
        document.body.removeChild(script);
        resposta = res;
    };

    var src = [url, '?', queryStr, 'callback=', nomeDaCallback].join('');
    var script = document.createElement('script');
    script.src = src;
    script.onload = function (e) {
        callback(resposta, true, e);
    }
    script.onerror = function (e) {
        callback(resposta, false, e);
    }
    document.body.appendChild(script);
}

jsFiddle: http://jsfiddle.net/kdyfq2mz/1

