I'd say functional programming is a tradition that draws from sources like denotational semantics, lambda calculus, Church, Landin, etc etc.
There are some different subspecies of functional programming: the Lisp family that draws from AI engineering, MIT, Emacs, actor research via Scheme, etc; the ML family that draws from typed lambda calculus, inductive definitions, and logical proof systems; and more, like concatenative languages.
JavaScript was always inspired by functional programming, as evident by Eich's claim to have tried to sneak in a variant of Scheme dressed up as Java. I always use lots of anonymous functions, higher order functions, and nonmutating transformations in my JS, without using any special immutability libraries, and I'm pretty happy with it.
As for JS, I've read "Javascript: The good parts" one day and realized that I can do everything I want using just functions and closures - it's really elegant imo. (even use this approach in Python sometimes)
This is called higher order functions (HOF).
FP is a --in my humble opinion-- broader topic describes a certain programming style. HOF is one thing in there, but so are "function+data rather then classes" and "favor immutability".
In contrast the imperative programming style is not merely about "not having HOF" or "mutable variables all over the place".
(these properties names can be wrong as I've not study calculus in English)
So on the machine, Immutability plays an important role on the first piece, uniqueness, so it tries to guarantee that results are not just "equal objects, but different instances", which breaks the function definition.
Of course that functions that return a new object for the same arguments, even if it's immutable, are not true math functions.
I will leave that last sentence as I wrote it, but it immediately leads me to wonder if functions that write functions have wandered into the self-modifying code realm?
Immutability and Referential Transparency help reduce that friction, but in the end we still have not found a real solution. That's why languages like Haskell require a bunch of gymnastics just to allow IO to be seen as pure functions.
FP isn't a technical definition. It's a cultural, family-resemblance definition that's driven by some mixture of fashion and genuine exploration into a niche of ideas in computing and formal languages.
The best you could hope for would be a set of shared values of the FP culture and then justifications for why various things that call themselves FP feel that are upholding those values. Even with a definition like this though, the values will shift and waver over time.
Here's my FP values:
* Simple over easy.
Rich Hickey's old egg. Favor abstractions with few moving parts,
reduced interactions, and more parsimonious overall models over
ones driven by metaphor or target use case alone. Result is
tools which are perhaps harder to get started using but have
better complexity scaling properties.
* Mathematics has been doing this a long time.
PLs are just formal languages and mathematicians have been working
seriously on formal languages for at least 150 years: steal their
ideas. From this we get ideas around comparative linguistics,
semantics, various proof/reasoning mechanisms and types.
* Readability counts, but not just in the sense of syntax.
Really this means "legibility" or even "static legibility". It's
another hint toward types, immutability, and general state space
reduction. It's a strong push away from "emergent behavior" to the
greatest degree possible. Things should endeavor to do what they
say on the tin... and to to the greatest degree reasonable say things
on the tin in such a way that the information is available from the get-go.
* Tradeoffs between power-to-construct and power-to-analyze.
This is everywhere in formal languages/PL, but it's especially strong
in FP since there's a focus on (simple over easy) semantics. It opens
the door for there to be mathematical semantics as opposed to just
operational semantics and this makes for rich opportunities for on-the-tin
static reasoning (equational reasoning, changing interpreters, embedded DSLs).
I think these values more or less were in place back in the old Lisp-y FP days, but they really are taken to new places by "more modern" takes on FP.For example, Common Lisp has two versions of list functions that modify list - one that returns a copy and another that returns mutated original list. (By the way, Paul Graham in his On Lisp, which is from 1993, mentions that functional programming style means that function doesn't modify its arguments and rather returns a copy.) Because once upon a time, the difference actually mattered. Today, mostly it doesn't.
Other languages delegate this stuff to the implementation language/runtime, for example Java/JVM.
Of course, even then, C was functional by that definition (as long as you could remember where the parens & asterisk went when defining your function!)...so what do I know.
On the other hand, if you have the attention span and interest, Li Haoyi has an interesting (and, in its conclusion, useful) take on this topic:
http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbo...
That said, and being a pedant, I must say that while English (or any language) does indeed change, it doesn't do so by any kind of consensus. People don't stop and give consent to a change in meanings, they roll along with it. There are some mechanisms in this shifting of meanings (needs to describe new concepts, fashion, immigration, etc) but consensus is not one of them.