prototype、getPrototype和__proto__之间的不同
1、C.prototype用于建立由new C() 创建的对象的原型
2、Object.getPrototypeOf(obj) 是ES5 中用来获取obj对象的原型对象的标准方法
3、obj. __proto__是获取obj对象的原型对象的非标准方法
| 12
 3
 4
 5
 6
 7
 
 | function User(name) {this.name = name;
 }
 var u = new User('hehe');
 
 console.log(Object.getPrototypeOf(u) === User.prototype);
 console.log(u.__proto__ === User.prototype);
 
 | 
使用Object.getPrototypeOf函数而不要使用__proto__属性。因为在一些环境中__proto__实现不一致(拥有null原型的对象没有__proto__属性)。
使构造函数与new操作符无关
1、如果调用者忘记使用new关键字,那么函数的接收者将是全局对象
| 12
 3
 4
 5
 6
 7
 
 | function User(name) {this.name = name;
 }
 
 var u = User('hehe');
 console.log(global.name);
 console.log(u.hehe);
 
 | 
2、如果将User函数定义为严格模式,那么它的接收者默认为undefined
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | function User(name) {'use strict';
 this.name = name;
 }
 
 var u = User('hehe');
 
 
 
 
 
 | 
3、不管是否new都能正常工作的函数
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | function User(name) {
 if (!(this instanceof User)) {
 return new User(name);
 }
 this.name = name;
 }
 
 var u = User('hehe');
 var u2 = new User('haha');
 console.log(u.name);
 console.log(u2.name);
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | function User(name) {
 var self = this instanceof User ? this : Object.create(User.prototype);
 self.name = name;
 return self;
 }
 
 var u = User('hehe');
 var u2 = new User('haha');
 
 console.log(u.name);
 console.log(u2.name);
 
 | 
Object.create需要一个原型对象作为参数,并返回一个继承自该原型对象的新对象。如下
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | var animal = {sayHi: function() {
 console.log('hi');
 }
 };
 
 var people = Object.create(animal);
 people.sayHi();
 console.log(Object.getPrototypeOf(people) === animal);
 
 | 
只将实例状态存储在实例对象中
1、理解原型对象与其实例之间是一对多的关系
认识到this变量的隐式绑定问题
1、this变量的作用域总是由其最近的封闭函数所确定
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | 
 
 function CSVReader(separators) {
 this.separators = separators || [','];
 this.regexp = new RegExp(this.separators.map(function(sep) {
 return '\\' + sep[0];
 }).join('|'));
 }
 
 CSVReader.prototype.read = function(str) {
 var lines = str.trim().split(/\n/);
 return lines.map(function(line) {
 console.log(this.regexp);
 return line.split(this.regexp);
 });
 };
 
 var reader = new CSVReader();
 console.log(reader.read('a,b,c\nd,e,f\n'));
 
 | 
2、解决方法一:数组的map方法可以传入一个可选的参数作为其回调函数的this绑定
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | CSVReader.prototype.read = function(str) {var lines = str.trim().split(/\n/);
 return lines.map(function(line) {
 console.log(this.regexp);
 return line.split(this.regexp);
 },this);
 };
 
 var reader = new CSVReader();
 console.log(reader.read('a,b,c\nd,e,f\n'));
 
 | 
3、解决方法二:使用词法作用域的变量来存储额外的外部this绑定的引用
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | CSVReader.prototype.read = function(str) {var lines = str.trim().split(/\n/);
 var self = this;
 return lines.map(function(line) {
 console.log(self.regexp);
 return line.split(self.regexp);
 });
 };
 
 var reader = new CSVReader();
 console.log(reader.read('a,b,c\nd,e,f\n'));
 
 | 
避免继承标准类
Array是一个很好的例子,一个操作系统的库可能希望创建一个抽象的目录,该目录继承了数组的所有行为。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | function Dir(path, entries) {this.path = path;
 for(var i = 0, n = entries.length; i<n; i++) {
 this[i] = entries[i];
 }
 }
 
 Dir.prototype = Object.create(Array.prototype);
 
 var dir = new Dir('/web/project',['index.html','script.js','style.css']);
 console.log(dir.length);
 
 console.log(Object.prototype.toString.call(dir));
 console.log(Object.prototype.toString.call([]));
 
 | 
失败的原因是length属性只对内部被标记为“真正的”数组的特殊对象起作用。ECMAScript标准规定它是一个不可见的内部属性,称为[[Class]],仅仅作为一个标签。
同理,函数被加上了值为“Function”的[[Class]]属性,依此类推