原型
定义
原型其实就是( prototype ),是function对象的一个属性,console出来,它的结果也是对象.
示例代码
function Handphone (color,brand){
this.color = color;
this.brand = brand;
this.screen = '18:9';
this.system = 'Android';
}
Handphone.prototype.rom = '64G';
Handphone.prototype.ram = '6G';
var hp1 = new Handphone('red','小米');
console.log(hp1);
console.log(hp1.rom);
结果
当使用了prototype之后,我们就能够访问到[ hp1.rom ]所以打印的 ' 64G '.这也就是说,
这个prototype是定义构造函数构造出来的每个对象的公共祖先.
所有该构造函数构造出的对象都可以继承原型上的属性和方法.
为了让开发的耦合度降低,其实所有的方法最后都会挂载到原型上去,例如我们上面的代码,screen和system就是写死了的,其实这样子是不好的,我们尝试改写一下:
Handphone.prototype.screen = '18 : 9';
Handphone.prototype.system = 'Android';
Handphone.prototype.rom = '64G';
Handphone.prototype.ram = '6G';
只有需要传参配置的部分,才会写在构造函数里,例如:
function Handphone (color,brand){
this.color = color;
this.brand = brand;
}
同时我们也可以在原型里增加方法:
Handphone.prototype.call = function(){
console.log('我在打电话');
}
// 一样可以使用:
hp1.call();
// 访问到
同时
console.log(Handphone.prototype);
如果是这个样子打印的话,结果就会是{ constructor f },在这个阶段面,我们只需要记住,constructor指向的是构造函数本身.
这时
// 我们可以将handphone里的构造函数,重新指向一个新的函数,如下:
function Telephone(){}
Handphone.prototype = {
constructor : Telephone
}
这个时候我们再打印出来,结果就会指向Telephone,而不是Handphone了.
额外总结
prototype其实是属于每一个实例化对象的,并不属于某一个构造函数.
所谓的"__ proto __:Car.prototype ",这种写法,其实是JS规定的,就是在强调这是源文件一样的东西,不要轻易的随便更改,我们其实可以将其看成键值对的形式来理解.
所以,__ proto __ ,就是每一个实例化对象的原型的容器,就是拿来装prototype的.
但是
prototype里面的属性也是可以更改的,例如:
function Person(){ }// 先定义一个函数
person.prototype.name = '233';
var P1 = {
name : 'www';
}
var person = new Person();
console.log (person.name); // 这里打印出来的就是233
person.__proto__ = P1;
// 在这里我们就将p1这个对象里面的属性,给赋值到proto里了,并且改写了name属性
console.log(person.name);//这里打印的就是改写过后的www
有关在原型中的继承
p.prototype.tSkill = 'java';
function p (){}
var P = new p();
T.prototype = P;
function T (){
this.mSkill = 'JS';
}
var t = new T();
s.prototype = t;
function s(){
this.pSkill = 'css';
}
var S = new s();
console.log(S.pSkill);
沿着proto这条线去找原型里的属性,一层一层去继承原型属性的这个链条,叫做原型链.
所以原型链的顶端,其实是Object.prototype
同时Object.prototype这个属性下,保存了toString ( ); 这个方法.
在原型链的继承里,下一级通常是无法往上增删改的,只能够查.但这也不是绝对的,例如:
p.prototype.tSkill = 'java';
function p (){}
var P = new p();
T.prototype = P;
function T (){
this.mSkill = 'JS';
this.sucess{
a:'28';
d:'30';
}
}
var t = new T();
s.prototype = t;
function s(){
this.pSkill = 'css';
}
var S = new s();
S.sucess.b = '100';
// 这个样子写的话,最后就会将b这个属性,加入到sucess这个对象中去了.
console.log(S.pSkill);
所以说引用值是可以的,但是不推荐这样子去做.
create方法
语法格式 : Object.creat ( ); 括号里只能放对象或则是null,必须放东西,不放不行.
// 或者我们可以这样:
var test = {
num:2
}
funtion Obj(){}
Obj.prototype.num = 1;
var obj1 = Object.create(Obj.prototype);
//var obj1 = Object.create(test); 也可以传入test对象.
var obj2 = new Obj();
// 上面这两种方式,结果其实都是一样的.
console.log(obj1);
console.log(obj2);
正是因为有了create方法,所以这里有一道面试题:
问,是不是所有的对象都继承于Object.prototype ?
//下面这种情况创建的对象,就不会继承于Object.prototype
var obj1 = Object.create(null);
那么我们可以自己加上proto这个属性吗,请看下面的代码:
var obj = Object.create(null);
obj.num = 1;
var obj1 = {
count:2
}
obj.__proto__ = obj1;
console.log(obj.count);
结果最终为
undefined
这就是说,只有系统加上的proto能正常的执行,如果是我们自己添加的,则不会生效.
( 系统自带的proto属性在console控制台的显示颜色偏浅,我们自己加的偏深. )