js基础_36、原型对象
将saynaem在全局作用域里定义
将函数定义在全局作用域,污染了全局作用域的命名空间,而且定义在全局作用域也很不安全,
<script>
function Person(naem,age,gender){
this.name=naem;
this.age=age;
this.gender=gender;
this.sayname=fun;
}
var fun=function(){
console.log(this.name);
}
var per=new Person('孙悟空',18,'男');
var per2=new Person('猪八戒',28,'男');
var per3=new Person('白骨精',20,'女');
per.sayname();
per2.sayname();
per3.sayname();
console.log(per.sayname==per2.sayname);
</script>
原型prototype
我们所创建的每一个函数,解析器(浏览器)都会向函数中添加一个属性prototype
这个属性对应着一个对象,这个对象就是我们所谓的原型对象
比如:
<script>
function fun(){
}
function fun2(){
}
console.log(fun.prototype);
console.log(fun2.prototype);
</script>
结果如下图:
而且这个每个函数里都是唯一的。
<script>
function fun(){
}
function fun2(){
}
console.log(fun.prototype==fun2.prototype);
</script>
如果函数作为普通函数调用,prototype没有任何作用。
当函数以构造函数形式调用时,它所创建的对象中都会有一个隐含的属性,该属性指向构造函数的原型对象,我们可以通过两个下划线proto两个下划线的格式来访问该属性。
原型对象就相当于一个公共的区域,所有的同一个类的实例都可以访问到这个原型对象。
<script>
function fun(){
}
var obj1=new fun();
console.log(obj1.__proto__);
</script>
结果是一个原型对象
如下代码证明了函数的prototype指向的和使用该函数实例化的对象中的proto属性指向的是同一个原型对象,但是必须是同一个类实例化的对象。
<script>
function fun(){
}
var obj1=new fun();
var obj2=new fun();
console.log(obj1.__proto__==fun.prototype);
console.log(obj2.__proto__==fun.prototype);
console.log(obj1.__proto__==obj2.__proto__);
</script>
我们可以将对象中共有的内容,统一设置到原型对象中。
当我们访问对象的一个属性或方法时,它会先在自身对象中去找,如果有则直接使用,如果没有就去原型对象中找,如果找到则直接使用。
原型对象中声明变量
<script>
function MyClass(){
}
//往原型对象中添加属性a
MyClass.prototype.a=123;
var mc=new MyClass();
console.log(mc.a);
</script>
可以看到构造函数里并没有属性a,但是在构造函数的原型对象里声明了变量a,构造函数的实例也能输出变量a,因为它会去找先去构造函数声明的实例里并没有a,它去对象的原型对象里找了。
如果构造函数的实例里有变量a,则不会去原型对象里找了。
<script>
function MyClass(){
}
//往原型对象中添加属性a
MyClass.prototype.a=123;
var mc=new MyClass();
//向mc对象中添加属性a
mc.a='我是mc中的a';
console.log(mc.a);
</script>
在对象本身找到了直接输出,不会去原型对象里找了。
构造函数与原型对象及实例对象图示原理:
总结,原型对象里可以存属性和方法,如果构造函数实例的对象里添加了和原型对象中相同的属性和方法,则会使用当前对象中的同名属性和方法,不过不会改变原型对象,如果其它实例没有和构造函数的原型对象一样的名字的属性和方法则可以继续使用原型对象里的变量和方法。
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每个对象添加属性和方法,同时也不会污染(影响)到全局作用域就可以使每个对象都具有这些属性和方法了