6-57 Function creator ‘new’, and the history of javascript

history time

  • javascript 之所以叫 javascript,為了吸引 Java programmer XDD
  • new constructor 也是從 Java 搬來的 (笑)

new

  • a operator
  • ‘new’ create a empty object
1
2
3
4
5
6
7
8
9
10
11
12
13

function Person(firstname, lastname){
console.log(this);//Person{}, a new empty object
this.firstname = firstname;
this.lastname = lastname;
console.log("this function is invoked");
}

var john = new Person('John', 'Doe');
console.log(john);

var jane = new Person('Jane', 'Doe');
console.log(jane);
  1. new create a brand new empty object
  2. the function Person() is called
  3. this in the function is point to the new empty object
  4. if the function doesn’t return a value, js engine return the new object

bigword alert : Function Constructors

  • A normal function that is used to construct objects.
  • ‘this’ points to a new empty object.
  • the new empty object is returned from the funciton automatically.

後記:
我到現在才知道在js裡,new後面的是一個function…囧


6-58 Function constructor and ‘.prototype’

Recall

  • .prototype (property) is used only by functions

  • .property is the prototype of any object created(use ‘new’)

  • __proto__ is in all objects(includeing functions)

  • __proto__ is the prototype of the the object

.prototype 是改變所有new 出來的新object 的 prototype

看下面例子,john.__proto__ 指向 Person.prototype

  • good js code sets properties inside the function constructor. But methods are set on the prototype.

∵ methods(function) 也是object,放在function contstrctor,變成每個new 出來的都有一份 methods 的copy
但它們只做一樣的事情 -> 浪費記憶體

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

function Person(firstname, lastname) {

console.log(this);
this.firstname = firstname;
this.lastname = lastname;
console.log('This function is invoked.');

}

Person.prototype.getFullName = function() {
return this.firstname + ' ' + this.lastname;
}

var john = new Person('John', 'Doe');
console.log(john);

var jane = new Person('Jane', 'Doe');
console.log(jane);



Person.prototype.getFormalFullName = function() {
return this.lastname + ', ' + this.firstname;
}

console.log(john.getFormalFullName());

6-59 Dangerous aside : new and function

  • if we invoked a function constructor without new , the function is still run. However, the function will return undefined in default.

  • use capital letter for function constructor

6-60 conceuptual Aside : build-in function constructor

autobox

build-in function constructor
1
2
3
4
5
6
7
8
9
10

var a = new String('John');
var b = new Number(3);
// creating Number object, not primitive type

"John".length //4
// primitive has no methods
//js engine autobox the primitive string into Object String

3.toFixed; //err, js doesn't do autobox on numbers
js easy enhance
1
2
3
4
5
6

// add new method to origin String Object
String.prototype.isLengthGreaterThan = function(limit){
return this.length > limit;
}
console.log('John'.isLengthGreaterThan(3)); //true

6-61 Dangerous Aside: build-in function constructor

  • is better not to use (primitive tpye) built-in function constructors
  • deal with date : moment.js
1
2
3
4
5
6
7
8
9

var a = 3;
var b = new Number(3);

a == b //true

a === b // false

var c = Number("3"); //convert string to primitive number

6-62 Dangerous Aside : Arrays and for…in

  • index(0,1,2…) is the property name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// Array.prototype.myCustomFeature = 'cool!';

var arr = ['John','Jane','Jim'];

for(var prop in arr){
console.log(prop + ' : ' + arr[prop]);
}

/*
0 : John
1 : Jane
2 : Jim
*/

/*
0 : John
1 : Jane
2 : Jim
myCustomFeature : cool!
*/

// use standard for loop to avoid this

6-63 Object.create and Pure Prototypal Inheritance

  • Pure Prototypal Inheritance
  • Object.create create a empty object with prototype point to the argument
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

var person = {
firstname : 'Default',
lastname : 'Default',
greet : function(){
return 'Hi' + this.firstname;
// this point to the object person
// if there is no this, js engine would find firstname in greet function's execution context
// then find firstname in outer environment(in this case, it's global object)
}
}

var john = Object.create(person);
console.log(john);
// john has default name!! because of the prototype

john.firstname = 'John';
john.lastname = 'Doe';
console.log(john);

if browser doesn’t support Object.create… Polyfill!!

bigword alert : Polyfill

  • code that adds a feature the engine may lack
object.create polyfill
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

//if object.create not exist, undefined
// undefined is coerced to boolean
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw new Error('Object.create implementation'
+ ' only accepts the first parameter.');
}
function F() {}
F.prototype = o;
return new F();
};
}

var person = {
firstname: 'Default',
lastname: 'Default',
greet: function() {
return 'Hi ' + this.firstname;
}
}

var john = Object.create(person);
john.firstname = 'John';
john.lastname = 'Doe';
console.log(john);

6-64 ES6 and Classes

  • ES6 has new keywords : class
  • 但作者認為這只是個syntatic sugur, 本質上還是 prototypal inheritance
  • 仍然建議使用prototypal inheritance 的方式
ES6 class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// note that this is a Object, a created object
// it exist in memory already
class Person{
constructor(firstname, lastname){
this.firstname = firstname;
this.lastname = lastname;
}

greet(){
return 'Hi ' + firstname;
}
}

var john = new Person('John', 'Doe');