原型
什么是原型?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function Handphone(color, brand){
this.color = color;
this.brand = brand;
this.screen = "18:9" ;
this.system = " Android";
}
Handphone.prototype.rom= '64G';
Handphone .prototype.ram = '6G" ;
Handphone.prototype.screen = "16:9';
var hp1 = new Handphone( 'red' ,'小米');
var hp2 = new Handphone( 'black' ,'华为');
console.log(hp1.rom); // 输出64G
console.log(hp2.ram); // 6G
consoLe.log(hp1.screen); // 18:9
consoLe.log(hp2.screen); // 18:9看了上面的代码,可能对prototype有了初步的认识。
- 可以说prototype是构造函数构造出的每一个对象的公共祖先
- 所有被该构造函数构造出的对象都继承prototype上的属性和方法
- 实例中已有的属性若与其prototype重名,则使用实例自己的属性
原型可以用来干什么?
在上述的代码中构造函数中,有的属性是写死的值,像这样的参数就可以写到prototype中。而需要配置的参数放入this中
能在实例上对prototype实现增删改查吗?
- 查
1 | function Car(){ |
增 ✖ 不能实现
1
2
3
4
5
6function Car(){
}
Car.prototype.name = 'BenBen';
var car = new Car();
car.size = 1222;
Car.prototype.size; // undefined删 ✖ 不能实现
1
2
3
4
5
6function Car(){
}
Car.prototype.name = 'BenBen';
var car = new Car();
delete car.name;
Car.prototype.name; //BenBen改 ✖ 不能实现
1
2
3
4
5function Car(){
}
Car.prototype.name = 'BenBen';
var car = new Car();
car.name = 'sasa';
prototype中的constructor属性

- prototype.constructor仍然指向构造函数本身
- 而构造函数中又有prototype属性,这样就形成了一个链。
constructor可以被修改吗?
1 | function Car(){ |

- 由此可以看出constructor是可以被修改的
实例中的__proto__是什么?
1 | function Car(){ |

由上图可知__proto__是属于每一个实例的,是实例化以后的结果
那么__proto__是怎么产生的呢?
1
2
3
4
5
6
7
8
9
10
11function Car(){
this.size = 122;
}
var car = new Car();
/*
* 当实例化的时候,给this隐式地添加__proto__属性,而__proto__只是一个系统定义的属性名而已
* this:{
* __proto__:Car.prototype
* }
*/__proto__属性是可以更改吗?
1
2
3
4
5
6
7
8
9
10
11
12
13function Car(){
this.size = 122;
}
var car = new Car();
car.__proto__ = {
re:1
}
car.__proto__;// { re: 1 }
/*
* 说明__proto__和普通属性一样可以被赋值修改
* }
*/
关于原型的深入理解
1 | Car.prototype.name = 'A'; |
- 上面的代码就体现出了实例化的时候__proto__的赋值细节
在car实例化的时候 this.proto = Car.prototype,这个时候的原型还未被修改,所以在使用car.name访问的时候,其实是查找的this.proto__中保存的属性。所以之后的原型改了不影响已赋值的__proto
而car.__proto__却是:
constructor中的prototype.name = ‘B’,这是为什么?
对于实例car来说,__proto__指向的仍是旧的原型。但是Car.prototype.constructor = Car。而Car中又有Car.prototype,它已经被更新了所以name是’B’
1 | Car.prototype.name = 'A'; |
可以看出car2.__proto__中的保存的prototype中的constructor丢失了
原型的__proto__属性
1 | function Car(){} |

可以看出Car.prototype也有__proto__属性

总结一句话所有的对象都有自己的原型,包括原型对象(prototype)自己
原型链:沿着__proto__一层一城去找prototype的链条式的继承关系
例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 Professor.prototype.p = 'JAVA';
function Professor(){}
var professor = new Professor();
Teacher.prototype = new Professor();
function Teacher(){
this.t = 'JS';
>}
var teacher = new Teacher();
Student.prototype = new Teacher();
function Student(){
this.s = 'CSS';
>}
var student = new Student();
console.log(student);
打印出的结果:
student对象可以访问student.s student.t student.p 就是通过原型链进行查找的。
通过以上可得结论原型链的顶端: Object.prototype
- 那么所有的对象会不会都继承Object.prototype呢?
- 答:用Object.create(null)创建的对象不继承Object.prototype。所以不是所有的对象都继承于Object.prototype
__proto__的赋值产生的问题
1 | var obj = {}; |
继承-原型继承
原型继承的问题
- 修改原型的原始值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18Professor.prototype.p = 'JAVA';
function Professor(){}
var professor = new Professor();
Teacher.prototype = new Professor();
function Teacher(){
this.t = 'JS';
}
var teacher = new Teacher();
Student.prototype = teacher;
function Student(){
this.s = 'CSS';
}
var student = new Student();
// 修改student原型的原始值
student.t = 'stu-JS';
console.log(student, teacher);

可以看出student的prototype.t未被修改,且student也没有添加t属性。所以原型的原始值不能被修改
- 修改原型的引用值
1 | Professor.prototype.p = 'JAVA'; |

关于toString()的探究 和 方法重写的问题
Number上的toString和Object中的toString有什么不一样?
1 | Object.prototype.toString.call(1);// '[object Number]' |
可以看出,Number 的toString和 Object中的toString的定义是不一样的。也就是说Object.toString方法不能满足Number想要的功能,所以系统进行重写。这个就是原型方法的重写