一、原型
- 定义:原型是 function 对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
- 利用原型特点和概念,
可以提取共有属性
。 - 对象属性的增删和原型上属性增删改查。
- 对象如何查看原型 ==> 隐式属性
__proto__
。 - 对象如何查看对象的构造函数 ==> constructor。
例
person.prototype //原型(描述一种继承关系),出生时就被定义好了
person.prototype ={} //是祖先
上面的 person 和 person1 都有一个共有的祖先 Person.prototype
自己身上有属性,原型上也有属性,取近的,用自己的
上面通过对象(后代)改原型(祖先)是不行的,在对象里面修改,只作用给自己
改原型都不行,增加肯定也不行。对象可以删除属性
// construnctor 是构造的意思(隐式是浅粉色)
浅粉色是系统帮你设置的,深紫色是自己设置的
在原型内部自带 constructor,指的是 Car。通过 constructor 能找的谁构造的自己
constructor 可以被人工手动更改
浅粉色的__proto__是系统的隐式的属性,前面两个_后面两个_,可以修改,尽量不改,在开发的时候,如果很私人的可以写成_private,告诉同事别动。
上面的__proto__放的是原型,__proto__存的是对象的原型
上面的var this ={__proto__
:person.prototype };这个对象并不是空的,这个proto,当你访问这个对象的属性时,如果对象没有这个属性,那么就会访问proto索引,看看有没有一个连接的关系,原型和自己连在一起
Person.prototype.name = 'abc';
function Person() {
//var this={
// __proto__=:Person.prototype
//}
}
var obj = {
name: "sunny"
}
var person = new Person();
person.__proto__ = obj;
Person 的原型是可以被修改的
Person.prototype.name = 'sunny';
function Person() {
//var this={
// __proto__=:Person.prototype
//}
}
var person = new Person();
Person.prototype.name = 'cherry';
Person.prototype.name = 'sunny';
function Person() {
//var this={
// __proto__=:Person.prototype
//}
}
Person.prototype.name = 'cherry';
var person = new Person();
Person.prototype.name = 'sunny';
function Person() {
//var this={
// __proto__=:Person.prototype
//}
}
var person = new Person();
Person.prototype = {
name: 'cherry'
}
Person.prototype.name这种.
的写法是在原有的基础上把值改了。改的是属性,也就是房间里面的东西。
而Person.prototype = {name: ‘cherry’ }是把原型改了,换了新的对象。改了个房间。
上面在new的时候var this={__proto__
:Person.prototype}里面的指向Person,此时Person.prototype与__proto__指向的是同一个空间,把他返回给var person
先new再Person.prototype={ name : ‘cherry’ } 已经晚了
在Person.prototype= { name : ‘cherry’ } 时,Person.prototype空间改了,但是__proto__指向的空间不变
上面的步骤实际上是
Person.prototype.name = {
name: "a"
};
__proto__ = Person.prototype;
Person.prototype = {
name: "b"
};
var obj = {
name: "a"
};
var obj1 = obj;
obj = {
name: "b"
}
上面这种思考过程:程序执行顺序
- 先把function Person(){}在预编译的过程中提到最上面
- 再执行Person.prototype.name=‘sunny’ 这一样行
- 再执行Person.prototype={name:‘cherry’}
- 最后执行var person=new Person();执行到new的时候,才会发生
var this={__proto__:Person.prototype}
- 下面的把上面的覆盖了
- 答案是cherry
function Person() {}
这说明原型里面有原型
Grand.prototype.lastName = "Deng";
function Grand() {
}
var grand = new Grand();
Father.prototype = grand;
function Father() {
this.name = "xuming";
}
var father = new Father();
Son.prototype = father;
function Son() {
this.hobbit = "smoke";
}
var son = new Son();
执行son.toString
//返回function toString(){[native code]},这里返回的是原型链终端的toString
Grand.prototype.__proto__=Object.prototype
//Object.prototype是原型链的终端
二、原型链
- 如何构成原型链?(见上一个例子)
- 原型链上属性的增删改查
原型链上的增删改查和原型基本上是一致的。只有本人有的权限,子孙是没有的 - 谁调用的方法内部this就是谁–原型案例
- 绝大多数对象的最终都会继承自Object.prototype
- Objcet.create(原型)
- 原型方法上的重写
son.fortune.card2='master'
这种改,这是引用值自己的修改。属于fortune.name给自己修改,这是一种调用方法的修改
Grand.prototype.lastName = "Deng";
function Grand() {
}
var grand = new Grand();
function Father() {
this.name = "xuming";
this.fortune = {
card1: "visa"
};
this.num = 100;
}
var father = new Father();
Son.prototype = father;
function Son() {
this.hobbit = "smoke";
}
var son = new Son();
son.num++是son.num=son.num+1
是先把父级的取过来再赋值+1
所以父亲的没变
<script>
Person.prototype = {
name: "a",
sayName: function() {
console.log(name);
}
}
function Person() {
}
var person = new Person();
</script>
console.log(name);写成name就会错,没有这个变量
console.log(this.name);写成this.name就会打印出a
Person.prototype = {
name: "a",
sayName: function() {
console.log(this.name);
}
}
function Person() {
this.name = "b";
}
var person = new Person();
a.sayName()方法调用,就是sayName里面的this指向,是谁调用的这个方法,this就指向谁
Person.prototype = {
height: 100
}
function Person() {
this.eat = function() {
this.height++;
}
}
var person = new Person();
this.height++;
这后面默认有一个return undefined
Person.prototype = {
height: 100
}
function Person() {
this.eat = function() {
this.height++;
return 123;
}
}
var person = new Person();
例:var obj={};也是有原型的
var obj={};与var obj1=new Object();效果是一样的
写var ovj={};系统会在内部来一个new Object();
obj1.__proto__
-------> Object.prototype;
但是在构造对象时,能用对象自变量var obj ={};就不要用var obj1=new Object();
Person.prototype = {}-- > Object.prototype
function Person() {
}
对象自变量的原型就是Object.prototype;
三、Object.create(原型)
//var obj = Object.create(原型);
Object.create 也能创建对象。var obj = Object.create(这里必须要有原型)
// var obj = Object.create(原型);
var obj = {
name: "sunny",
age: 123
};
var obj1 = Object.create(obj);
// var obj = Object.create(原型);
Person.prototype.name = "sunny";
function Person() {
}
var person = Object.create(Person.prototype);
四、绝大多数对象的最终都会继承自Object.prototype
html里面没有添加任何东西
这样就会报错
html里面没有添加任何东西
只在控制台加上null
// var obj = Object.create(原型);
var obj = Object.create(null);
原型是隐式的内部属性,你加是没有用的
// var obj = Object.create(原型);
var obj = Object.create(123);
Object.create()在括号里面只能放null或者Object,其余会报错
undefined和null没有原型,也就不可能有toString方法
下面 123.toString 首先会识别成浮点型,所以在后面直接加.toString 是不行的
数字想用toString方法,要经过包装类包装new Number(num)然后.toString
加深上面的理解
var num=123;
//num.toString();--->new Number(num).toString();
Number.prototype.toString=function(){
}
//Number.prototype.__proto__=Object.prototype
而new Number(num).toString的原型是Number.prototype,而Number.prototype上面有一个.toString方法,Number.prototype也有原型
Number.prototype.__proto__
,原型是Object.prototype
假如new Number上面的prototype上面有这个toString,那么就不用Object.prototype的 toString。而这个 number 上面有这个 toString。
然后number上面的toString调用的是自己重写的toString
原型上有这个方法,我自己又写了一个和原型上同一名字,但不同功能的方法,叫做重写(同一个名字的函数,不同重写方式)
通过返回值,形参列表不同传参
同样的名实现不同功能的,就是重写
// var obnj=Object.create(原型);
// Object.prototype.toString=function(){
// }
Person.prototype = {
}
function Person() {
}
var person = new Person();
和原型链上终端方法名字一样,但实现不同的功能,叫做方法的重写。也就是覆盖
下面这个也是重写
让object上面的toString重写了
所以num.toString()调用的是number.prototype.toString
如果调用的是object.prototype.toString结果会不一样
document.write会隐式的调用toString方法,其实打印的是 toString 的结果
没有原型就不能toString
上面这个例子表示:我要打印的是obj,实际上打印出来的是toString方法,也证明了document.write调用的是toString方法