第五章 原型
- 在JavaScript中,所有函数都会拥有一个 prototype 的属性,默认初始值为空对象。
- 可以在相关的原型对象中添加新的方法和属性,甚至可以用自定义对象来完全替换掉原有的原型对象。
- 通过某个构造器函数来new一个对象时,这些对象就会自动拥有一个指向 prototype 属性的 __proto__链接,通过它可以访问相关原型对象的属性。
- 对象自身属性的优先级要高于其原型对象的同名属性。
- 扩展内建对象不是一个好主意,如果必须要采用的话一定要谨慎。
- 当我们对原型对象执行完全替换时,可能会触发原型链某种异常,prototype.constructor属性是不可靠的。
- Best Practice:当我们重写某对象的prototype时,重置相应的constructor属性是一个好习惯。
- 每个对象都会有一个isprototype()方法,这个方法会告诉我们当前对象是否是另一个对象的原型。
- 神秘的__proto__链接。
枚举属性
参考链接:JavaScript for...in循环。
第六章 继承
1 //6.1.1 原型链示例 2 //6.1.2 将共享属性迁移到原型中去 3 //6.2 只继承于原型 4 function Shape(){ 5 6 } 7 Shape.prototype.name = 'shape'; 8 Shape.prototype.toString = function(){ 9 return this.name; 10 } 11 function TwoDShape(){ 12 13 } 14 TwoDShape.prototype = Shape.prototype; 15 TwoDShape.prototype.constructor = TwoDShape; 16 TwoDShape.prototype.name = '2D shape'; 17 18 function Triangle(side, height){ 19 this.side = side; 20 this.height = height; 21 } 22 Triangle.prototype = TwoDShape.prototype; 23 Triangle.prototype.constructor = Triangle; 24 Triangle.prototype.name = 'Triangle'; 25 Triangle.prototype.getArea = function(){ 26 return this.side * this.height / 2; 27 } 28 //临时构造器 new F() 29 function Shape(){ 30 31 } 32 Shape.prototype.name = 'shape'; 33 Shape.prototype.toString = function(){ 34 return this.name; 35 } 36 function TwoDShape(){ 37 38 } 39 var F = function(){}; 40 F.prototype = Shape.prototype; 41 TwoDShape.prototype = new F(); 42 TwoDShape.prototype.constructor = TwoDShape; 43 TwoDShape.prototype.name = '2D shape'; 44 45 function Triangle(side, height){ 46 this.side = side; 47 this.height = height; 48 } 49 var F = function(){}; 50 F.prototype = TwoDShape.prototype; 51 Triangle.prototype = new F(); 52 Triangle.prototype.constructor = Triangle; 53 Triangle.prototype.name = 'Triangle'; 54 Triangle.prototype.getArea = function(){ 55 return this.side * this.height / 2; 56 } 57 58 //6.3 uber——子对象访问父对象的方式 59 function Shape(){} 60 Shape.prototype.name = 'shape'; 61 Shape.prototype.toString = function(){ 62 var result = []; 63 if (this.constructor.uber){ 64 result[result.length] = this.constructor.uber.toString(); 65 } 66 result[result.length] = this.name; 67 return result.join(', '); 68 } 69 function TwoDShape(){ 70 71 } 72 var F = function(){}; 73 F.prototype = Shape.prototype; 74 TwoDShape.prototype = new F(); 75 TwoDShape.prototype.constructor = TwoDShape; 76 TwoDShape.uber = Shape.prototype; 77 TwoDShape.prototype.name = '2D shape'; 78 79 function Triangle(side, height){ 80 this.side = side; 81 this.height = height; 82 } 83 var F = function(){}; 84 F.prototype = TwoDShape.prototype; 85 Triangle.prototype = new F(); 86 Triangle.prototype.constructor = Triangle; 87 Triangle.uber = TwoDShape.prototype; 88 Triangle.prototype.name = 'Triangle'; 89 Triangle.prototype.getArea = function(){ 90 return this.side * this.height / 2; 91 } 92 93 // 6.4 将继承部分封装成函数 94 function extend(Child, Parent){ 95 var F = function(){}; 96 F.prototype = Parent.prototype; 97 Child.prototype = new F(); 98 Child.prototype.constructor = Child; 99 Child.uber = Parent.prototype; 100 } 101 extend(TwoDShape, Shape); 102 extend(Triangle, TwoDShape); 103 104 //6.5 属性拷贝 105 function extend2(Child, Parent){ 106 var p = Parent.prototype; 107 var c = Child.prototype; 108 for (var i in p){ 109 c[i] = p[i]; 110 } 111 c.uber = p; 112 } 113 114 //6.6 小心处理引用拷贝 115 //6.7 对象之间的继承 116 function extendCopy(p){ 117 var c = {}; 118 for(var i in p){ 119 c[i] = p[i]; 120 } 121 c.uber = p; 122 return c; 123 } 124 125 //6.8 深拷贝 126 function deepCopy(c, p){ 127 var c = c || {}; 128 for (var i in p){ 129 if (typeof p[i] === 'object'){ 130 c[i] = (p[i].constructor === Array) ? [] : {}; 131 deepCopy(c[i], p[i]) 132 }else{ 133 c[i] = p[i]; 134 } 135 } 136 return c; 137 } 138 //6.9 object(),Douglas Crockford为我们提出了一个建议,既可以用object() 139 //函数来接受父对象,并返回一个以该对象为原型的新对象。 140 function object()(o){ 141 var n; 142 function F(){} 143 F.prototype = o; 144 n = new F(); 145 n.uber = o; 146 return n; 147 } 148 149 //6.10 原型继承于属性拷贝的混合使用 150 function objectPlus(o, stuff){ 151 var n; 152 function F(){}; 153 F.prototype = o; 154 n = new F(); 155 n.uber = o; 156 157 for(var i in stuff){ 158 n[i] = stuff[i]; 159 } 160 return n; 161 } 162 163 //6.11 多重继承 164 function multi(){ 165 var n = {}, stuff, j = 0, len = arguments.length; 166 for(j = 0; j < len; j++){ 167 stuff = arguments[j]; 168 for(var i in stuff){ 169 n[i] = stuff[i]; 170 } 171 } 172 return n; 173 } 174 175 //6.12 寄生式继承 176 var twoD = { 177 name : '2D shape', 178 dimensions : 2 179 } 180 function triangle(s, h){ 181 var that = object(twoD); 182 that.name = 'Triangle'; 183 that.getArea = function(){ 184 return this.side * this.height / 2 185 }; 186 that.side = s; 187 that.height = h; 188 return that; 189 } 190 191 //6.13 构造器借用 192 function Shape(id){ 193 this.id = id; 194 } 195 Shape.prototype.name = 'shape'; 196 Shape.prototype.toString = function(){ 197 return this.name; 198 } 199 function Triangle(){ 200 Shape.apply(this, arguments); 201 } 202 Triangle.prototype = new Shape(); 203 Triangle.prototype.name = 'Triangle'; 204 //消除双重继承 205 function Shape(id){ 206 this.id = id; 207 } 208 Shape.prototype.name = 'shape'; 209 Shape.prototype.toString = function(){ 210 return this.name; 211 } 212 function Triangle(){ 213 Shape.apply(this, arguments); 214 } 215 function extend2(Child, Parent){ 216 var p = Parent.prototype; 217 var c = Child.prototype; 218 for (var i in p){ 219 c[i] = p[i]; 220 c.uber = p;} 221 222 } 223 extend2(Triangle, Shape); 224 Triangle.prototype.name = 'Triangle';