...menustart
- A re-introduction to JavaScript (JS tutorial)
- tips
...menuend
- JS 的
&& ||
更像python里面的 and / or - blocks do not have scope (like python); only functions have a scope.
- 在ECMAScript 6中你可以通过使用let and const 来定义块级别的变量。
- for...of array
- for...in object
- function, Array 都是 Object, 所以都可以通过new 创建
- function 有很多手段支持变长参数
- call: func.apply(null, arg_array )
- or func( ... arg_array )
- 箭头函数没有自己的this
- 理解this
- JS(ES5)三种函数调用形式:
- func(p1, p2)
- obj.child.method(p1, p2)
- func.call(context, p1, p2) // 先不讲 apply
- 前两种是语法糖,第三种才是正确的调用方式
- func(p1, p2) 等价于 func.call(undefined, p1, p2)
- obj.child.method(p1, p2) 等价于obj.child.method.call(obj.child, p1, p2)
- 函数调用只有一种形式:
- func.call(context, p1, p2)
- this,就是上面代码中的 context
- 其他
new foo()
构造函数中,foo函数内部的this永远是new foo()返回的对象- 箭头函数没有自己的this, 箭头函数在设计中使用的是Lexical this
- JS(ES5)三种函数调用形式:
-
JavaScript's types are:
- Number : double-precision 64-bit
- String
- Boolean
- Symbol (new in ES6 2015)
- Object
- Function
- Array
- Date
- RegExp
- null
- lack of value
- undefined
- lack of definition
-
And there are some built-in Error types as well.
- Math
- Math.sin(3.5)
- convert a string to an integer
- parseInt('123', 10); // 123
- parseInt('010', 10); // 10
- In older browsers, strings beginning with a "0" are assumed to be in octal
- but this hasn't been the case since 2013 or so , octal has been removed.
- parseInt('0x10'); // 16
- parseInt('11', 2); // 3
- parse floating point numbers
- parseFloat() always uses base 10.
- You can also use the unary + operator to convert values to numbers:
+ '42'; // 42
+ '010'; // 10
+ '0x10'; // 16
- A special value called
NaN
(short for "Not a Number") is returned if the string is non-numeric:
parseInt('hello', 10); // NaN
- You can test for NaN using the built-in isNaN() function:
isNaN(NaN); // true
- JavaScript also has the special values Infinity and -Infinity:
1 / 0; // Infinity
-1 / 0; // -Infinity
- You can test for Infinity, -Infinity and NaN values using the built-in isFinite() function
isFinite(1 / 0); // false
isFinite(-Infinity); // false
isFinite(NaN); // false
- sequences of Unicode characters , More accurately, they are sequences of UTF-16 code units
'hello'.length; // 5
'hello'.charAt(0); // "h"
'hello, world'.replace('hello', 'goodbye'); // "goodbye, world"
'hello'.toUpperCase(); // "HELLO"
- javascript 区分 null 和 undefined
- boolean ( support
&& || !
,&& ||
更像python里面的 and / or )- false, 0, empty strings (""), NaN, null, and undefined all become false.
- All other values become true.
// rarely necessary,
// as JavaScript will silently perform this conversion
Boolean(''); // false
Boolean(234); // true
- The && and || operators use short-circuit logic
var name = o && o.getName();
var name = cachedName || (cachedName = getName());
- declared keywords
- let
- to declare block-level variables.
- available from the block it is enclosed in.
- const
- to declare variables whose values are never intended to change.
- available from the block it is declared in
- var
- available from the function it is declared in.
- let
// myLetVariable is *not* visible out here
for (let myLetVariable = 0; myLetVariable < 5; myLetVariable++) {
// myLetVariable is only visible in here
}
// myLetVariable is *not* visible out here
// myVarVariable *is* visible out here
for (var myVarVariable = 0; myVarVariable < 5; myVarVariable++) {
// myVarVariable is visible to the whole function
}
// myVarVariable *is* visible out here
- An important difference between JavaScript and other languages like Java is that:
- in JavaScript, blocks do not have scope; only functions have a scope.
- So if a variable is defined using var in a compound statement (for example inside an if control structure), it will be visible to the entire function.
- However, starting with ECMAScript 2015, let and const declarations allow you to create block-scoped variables.
Scope Chain
-
Everything is executed in an Execution Context
-
Function invocation creates a new Execution Context
-
Each Execution Context has:
- It's own Variable Environment
- Special 'this' object
- Reference to its Outer Environment
-
Global scope does not have an Outer Environment as it's the most outer there is.
-
How scope chain works
- Referenced ( not defined ) variable will be searched for in its current scope first.
- If not found, the Outer Reference will be searched, etc
- This will keep going until the Global scope.
- If not found in Global scope, the variable is undefined.
- Referenced ( not defined ) variable will be searched for in its current scope first.
-
Example
var x = 2; A(); function A() { var x = 5; B(); } function B() { console.log(x) } // Result: x=2
- Even though B is called within A, and A has its own x, what actually matters as far as resolving where x is coming from is its outer reference.
- And B is defined within the global scope. Therefore, the outer reference of function B is the global scope, not function A.
+, -, *, / , %
>= , <= , ==
'3' + 4 + 5; // "345"
3 + 4 + '5'; // "75"
==
operator performs type coercion if you give it different types
123 == '123'; // true
1 == true; // true
- To avoid type coercion, use the triple-equals operator:
123 === '123'; // false
1 === true; // false
-
There are also != and !== operators.
-
>
,<
等等 操作也会 做类型转换 -
bitwise operations also support
& |
- XOR
^
- NOT
~
<< >> >>>
- JavaScript has a similar set of control structures to other languages in the C family
if (name == 'puppies') {
name += ' woof';
} else if (name == 'kittens') {
name += ' meow';
} else {
name += '!';
}
while (true) {
// an infinite loop!
}
var input;
do {
input = get_input();
} while (inputIsNotValid(input));
// for loop is the same as that in C and Java
for (var i = 0; i < 5; i++) {
// Will execute 5 times
}
- JavaScript also contains two other prominent for loops: for...of
for (let value of array) {
// do something with value
}
- and for...in:
for (let property in object) {
// do something with object property
}
- 你也可以使用 for..in 来遍历数组,但是不推荐,原因见下面 Array 一节
- JavaScript has a ternary operator for conditional expressions:
var allowed = (age > 18) ? 'yes' : 'no';
- The switch statement can be used for multiple branches based on a number or string:
switch (action) {
case 'draw':
drawIt();
break;
case 'eat':
eatIt();
break;
default:
doNothing();
}
- JavaScript objects can be thought of as simple collections of name-value pairs
- As such, they are similar to: Dictionaries in Python.
- create an empty object:
var obj = new Object();
// or
var obj = {};
- This syntax is also the core of JSON format and should be preferred at all times.
var obj = {
name: 'Carrot',
for: 'Max', // 'for' is a reserved word, use '\_for' instead.
details: {
color: 'orange',
size: 12
}
};
obj.details.color; // orange
obj['details']['size']; // 12
// but there is something different
obj.for = 'Simon'; // Syntax error, because 'for' is a reserved word
obj['for'] = 'Simon'; // works fine
- The following example creates an object prototype, Person and an instance of that prototype, You.
function Person(name, age) {
this.name = name;
this.age = age;
}
// Define an object
var you = new Person('You', 24);
// We are creating a new person named "You" aged 24.
var a = new Array();
a[0] = 'dog';
a[1] = 'cat';
a[2] = 'hen';
a.length; // 3
var a = ['dog', 'cat', 'hen'];
a.length; // 3
- Note that array.length isn't necessarily the number of items in the array.
- the length of the array is one more than the highest index.
var a = ['dog', 'cat', 'hen'];
a[100] = 'fox';
a.length; // 101
- we can use for...of loop for iterable objects such as arrays:
- You could also iterate over an array using a for...in loop.
- But if someone added new properties to Array.prototype, they would also be iterated over by this loop for...in
- Therefore this loop type is not recommended for arrays.
- Another way of iterating over an array that was added with ECMAScript 5 is forEach():
['dog', 'cat', 'hen'].forEach(function(currentValue, index, array) {
// Do something with currentValue or array[index]
});
- append an item
a.push(item);
Method name | Description |
---|---|
a.toString() | Returns a string with the toString() of each element separated by commas. |
a.toLocaleString() | Returns a string with the toLocaleString() of each element separated by commas. |
a.concat(item1[, item2[, ...[, itemN]]]) | Returns a new array with the items added on to it. |
a.join(sep) | Converts the array to a string — with values delimited by the sep param |
a.pop() | Removes and returns the last item. |
a.push(item1, ..., itemN) | Appends items to the end of the array. |
a.reverse() | Reverses the array. |
a.shift() | Removes and returns the first item. |
a.slice(start[, end]) | Returns a sub-array. |
a.sort([cmpfn]) | Takes an optional comparison function. |
a.splice(start, delcount[, item1[, ...[, itemN]]]) | Lets you modify an array by deleting a section and replacing it with more items. |
a.unshift(item1[, item2[, ...[, itemN]]]) | Prepends items to the start of the array. |
- The most basic function couldn't be much simpler:
function add(x, y) {
var total = x + y;
return total;
}
- That may seem a little silly, but functions have access to an additional variable inside their body called arguments
function add() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum;
}
add(2, 3, 4, 5); // 14
- This is pretty useful, but it does seem a little verbose
- you can also use rest parameter operator to do same thing
function avg(...args) {
var sum = 0;
for (let value of args) {
sum += value;
}
return sum / args.length;
}
avg(2, 3, 4, 5); // 3.5
- but how do you calc average on all array's elements ?
- you may re-write another function like :
function avgArray(arr) { ... }
avgArray([2, 3, 4, 5]); // 3.5
- But it would be nice to be able to reuse the function that we've already created.
- Luckily, JavaScript lets you call a function with an arbitrary array of arguments,
- using the apply() method of any function object.
avg.apply(null, [2, 3, 4, 5]); // 3.5
- 你还可以使用 spread operator 把数组展开
const numbers = [1, 2, 3];
avg( ...numbers )
- anonymous functions
var avg = function() { ... }
- It's extremely powerful, as it lets you put a full function definition anywhere that you would normally put an expression.
- This enables all sorts of clever tricks.
- Here's a way of "hiding" some local variables — like block scope in C:
var a = 1;
var b = 2;
(function() {
var b = 3;
a += b;
})();
a; // 4
b; // 2
- 现在带来一个问题: 匿名函数如何递归调用?
- You can use named IIFEs (Immediately Invoked Function Expressions)
- see
counter
in above codes
var charsInBody = (function counter(elm) {
if (elm.nodeType == 3) { // TEXT_NODE
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++) {
count += counter(child);
}
return count;
})(document.body);
- JavaScript is a prototype-based language that contains no class statement
- Instead, JavaScript uses functions as classes.
function makePerson(first, last) {
return {
first: first,
last: last
};
}
function personFullName(person) {
return person.first + ' ' + person.last;
}
s = makePerson('Simon', 'Willison');
personFullName(s); // "Simon Willison"
- This works, but it's pretty ugly.
- You end up with dozens of functions in your global namespace.
- What we really need is a way to attach a function to an object.
- Since functions are objects, this is easy:
function makePerson(first, last) {
return {
first: first,
last: last,
fullName: function() {
return this.first + ' ' + this.last;
}
};
}
s = makePerson('Simon', 'Willison');
s.fullName(); // "Simon Willison"
- There's something here we haven't seen before: the this keyword
- Used inside a function,
this
refers to the current object.
- Used inside a function,
- Note that this is a frequent cause of mistakes
s = makePerson('Simon', 'Willison');
var fullName = s.fullName;
fullName(); // undefined undefined
- When we call fullName() alone, without using s.fullName(),
this
is bound to the global object. - We can take advantage of the this keyword to improve our makePerson function:
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = function() {
return this.first + ' ' + this.last;
};
this.fullNameReversed = function() {
return this.last + ', ' + this.first;
};
}
var s = new Person('Simon', 'Willison');
-
We have introduced another keyword: new.
- new is strongly related to this
- It creates a brand new empty object,
- and then calls the function specified,
- with
this
set to that new object.
-
Note: function specified with
this
does not return a value but merely modifies the this object.- It's
new
that returns thethis
object to the calling site.
- It's
-
Functions that are designed to be called by
new
are called constructor functions. -
我们的 Person 看起来已经不错了。但是每次创建一个 Person 对象,我们就会创建一个全新的 function 对象。
- function 应该是共享的才好
// try 1 function personFullName() { return this.first + ' ' + this.last; } function Person(first, last) { this.first = first; this.last = last; this.fullName = personFullName; }
-
更好的做法:
function Person(first, last) { this.first = first; this.last = last; } Person.prototype.fullName = function() { return this.first + ' ' + this.last; };
-
Person.prototype is an object shared by all instances of Person.
- 当你尝试 访问 没有设置的 Person属性时, Javascript 都会检查 Person.prototype 看属性是否存在。
-
Interestingly, you can also add things to the prototype of built-in JavaScript objects.
var s = 'Simon'; s.reversed(); // TypeError on line 1: s.reversed is not a function String.prototype.reversed = function() { var r = ''; for (var i = this.length - 1; i >= 0; i--) { r += this[i]; } return r; }; s.reversed(); // nomiS 'This can now be reversed'.reversed(); // desrever eb won nac sihT
-
the prototype forms part of a chain
- The root of that chain is Object.prototype, whose methods include toString()
- This is useful for debugging our Person objects:
var s = new Person('Simon', 'Willison'); s.toString(); // [object Object] Person.prototype.toString = function() { return '<Person: ' + this.fullName() + '>'; } s.toString(); // "<Person: Simon Willison>"
-
Remember how avg.apply() had a null first argument?
- The first argument to apply() is the object that should be treated as 'this'.
- For example, here's a trivial implementation of new:
function trivialNew(constructor, ...args) {
var o = {}; // Create an object
constructor.apply(o, args);
return o;
}
// Calling
var bill = trivialNew(Person, 'William', 'Orange');
// is therefore almost equivalent to
var bill = new Person('William', 'Orange');
- apply() has a sister function named
call
- which again lets you set
this
but takes an expanded argument list as opposed to an array.
- which again lets you set
function lastNameCaps() {
return this.last.toUpperCase();
}
var s = new Person('Simon', 'Willison');
lastNameCaps.call(s);
// Is the same as:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps(); // WILLISON
- An arrow function expression has a shorter syntax than a function expression and does not have its own
this, arguments, super, or new.target
. - These function expressions are best suited for non-method functions, and they cannot be used as constructors.
var materials = [
'Hydrogen',
'Helium',
'Lithium',
'Beryllium'
];
console.log(materials.map(material => material.length));
- 只是语法糖, 并没有引入任何新模型
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
// unnamed
var Rectangle = class {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
console.log(Rectangle.name);
// output: "Rectangle"
// named
var Rectangle = class Rectangle2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
console.log(Rectangle.name);
// output: "Rectangle2"
- Strict mode
- The bodies of class declarations and class expressions are executed in strict mode , i.e.:
- constructor, static and prototype methods, getter and setter functions
- The bodies of class declarations and class expressions are executed in strict mode , i.e.:
- Constructor
- constructor can use the super keyword to call the constructor of the super class.
- Prototype methods
- see method definitions
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100
- Static methods
- Static methods are called without instantiating their class and cannot be called through a class instance.
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
console.log(Point.distance(p1, p2));
Instance properties
- Instance properties must be defined inside of class methods:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
- Static class-side properties and prototype data properties must be defined outside of the ClassBody declaration:
Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
-
If there is a constructor present in subclass, it needs to first call super() before using "this".
-
One may also extend traditional function-based "classes":
function Animal (name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(this.name + ' makes a noise.');
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
- Note that classes cannot extend regular (non-constructible) objects.
- If you want to inherit from a regular object, you can instead use
Object.setPrototypeOf()
:
- If you want to inherit from a regular object, you can instead use
var Animal = {
speak() {
console.log(this.name + ' makes a noise.');
}
};
class Dog {
constructor(name) {
this.name = name;
}
}
// If you do not do this you will get a TypeError when you invoke speak
Object.setPrototypeOf(Dog.prototype, Animal);
var d = new Dog('Mitzie');
d.speak(); // Mitzie makes a noise.
- You might want to return
Array
objects in your derived array class MyArray. - The species pattern lets you override default constructors.
- For example, when using methods such as map() that returns the default constructor,
- you want these methods to return a parent Array object,
- instead of the MyArray object. The Symbol.species symbol lets you do this:
class MyArray extends Array {
// Overwrite species to the parent Array constructor
static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
- The super keyword is used to call corresponding methods of super class.
class Lion extends Cat {
speak() {
super.speak();
console.log(this.name + ' roars.');
}
}
npm install -g uglify-js
uglifyjs gd3d.js -c -m --keep-fnames -o xxx.min.js
<head>
<script src="js/script.js"> </script>
<script>
...
</script>
</head>
<body>
<script src="js/script.js"> </script>
<script>
...
</script>
</body>
- Immediately Invoked Function Expressions are usually used to place code into its own execution context not to conflict with the global scope.
- This can be used create fake namespace
// Immediately Invoked Function ( function(global) { function sayHi() { var name = "John"; var greeting = "Hi "; var sayHi = function() { console.log( greeting + name ) } } // end custom function // before the end of function(global) // Export something the global object global.sayHi = sayHi; } // end function(global) )(global); // for nodejs // )(window); // for browser