JavaScript中protoType属性

在Javascript语言体系中,不存在类(Class)的概念的,javascript中不是基于‘类’的,而是通过构造函数(constructor)和原型链(prototype chains)实现的。
什么是构造函数?
构造函数,就是提供了一个生成对象的模板并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。总的来说,构造函数就是对象的模板,对象就是构造函数的实例。

构造函数的特点有:

  • 构造函数的函数名首字母必须大写。
  • 内部使用this对象,来指向将要生成的对象实例。
  • 使用new操作符来调用构造函数,并返回对象实例。
function Person(){
	this.name = 'zj';
}
var girl = new Person();
console.log(girl.name); //'zj'

所有的实例对象都可以继承构造函数中的属性和方法。但是,同一个对象实例之间,无法共享属性。

function Person(name,height){
	this.name=name;
	this.height=height;
	this.hobby=function(){
	return 'watching movies';
	}
 }
var boy=new Person('zdy',180);
var girl=new Person('wsh',160);
console.log(boy.name);     //'zdy'
console.log(girl.name);    //'wsh'
console.log(boy.hobby === girl.hobby);   //false

为了解决构造函数的对象实例之间无法共享属性的缺点,js提供了prototype属性。

protoType属性
js中每个数据类型都是对象(除了null和undefined),而每个对象都继承自另外一个对象,后者称为“原型”(prototype)对象,只有null除外,它没有自己的原型对象。 原型对象上的所有属性和方法,都会被对象实例所共享。 通过构造函数生成对象实例时,会将对象实例的原型指向构造函数的prototype属性。每一个构造函数都有一个prototype属性,这个属性就是对象实例的原型对象。也可以说原型对象的作用,就是定义所有对象实例所共享的属性和方法。

function Person(name,height){
	this.name=name;
	this.height=height;
}
Person.prototype.hobby=function(){
	return 'watching movies';
}
var boy=new Person('zdy',180);
var girl=new Person('wsh',160);
console.log(boy.name);     //'zdy'
console.log(girl.name);    //'wsh'
console.log(boy.hobby === girl.hobby);    //true

上面代码中,如果将hobby方法放在原型对象上,那么两个实例对象都共享着同一个方法。

对于构造函数来说,prototype是作为构造函数的属性;对于对象实例来说,prototype是对象实例的原型对象。所以prototype即是属性,又是对象。
原型对象的属性不是对象实例的属性。对象实例的属性是继承自构造函数定义的属性,因为构造函数内部有一个this关键字来指向将要生成的对象实例。对象实例的属性,其实就是构造函数内部定义的属性。只要修改原型对象上的属性和方法,变动就会立刻体现在所有对象实例上。

当某个实例对象的属性和方法定义在自身,就不会去原型对象上查找,如果某个对象实例没有该属性和方法时,就会到原型对象上去查找。由于原型对象本身对于对象实例来说也是对象,它也有自己的原型,所以形成了一条原型链(prototype chain)

原型链特点:

  • 读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。
  • 如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overiding)。
  • 一级级向上在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。

constructor属性
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
注:prototype是构造函数的属性,而constructor则是构造函数的prototype属性所指向的那个对象,也就是原型对象的属性。注意不要混淆。
由于constructor属性是定义在原型(prototype)对象上面,意味着可以被所有实例对象继承。

function A(){};
var a=new A();
console.log(a.constructor); //A()
console.log(a.constructor===A.prototype.constructor);//true

上面代码中,a是构造函数A的实例对象,但是a自身没有contructor属性,该属性其实是读取原型链上面的A.prototype.constructor属性。

//constructor属性的作用
function A(){};
var a = new A();

// 分辨原型对象到底属于哪个构造函数
console.log(a.constructor===A);   //true
console.log(a.constructor===Array);   //false

//从实例新建另一个实例
var b = new a.constructor();
console.log(b instanceof A);  //true

//调用自身的构造函数成为可能
A.prototype.hello = function() {
	return new this.constructor();
}

//提供了一种从构造函数继承另外一种构造函数的模式
function Father() {}
function Son() {
	Son.height.constructor.call(this);
}
Son.height = new Father();

instanceof运算符
instanceof运算符:表示指定对象是否为某个构造函数的实例,返回一个布尔值。由于instanceof对整个原型链上的对象都有效,所以同一个实例对象,可能会对多个构造函数都返回true。

注:instanceof对象只能用于复杂数据类型(数组,对象等),不能用于简单数据类型(布尔值,数字,字符串等)。null和undefined都不是对象,所以instanceof 总是返回false。

猜你喜欢

转载自blog.csdn.net/weixin_44242600/article/details/87931523