You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
通过 new 操作符调用构造函数得到的对象,称之为实例。实例内部包含一个指针(内部属性),指向构造函数的原型对象。一般通过对象的 __proto__ 属性可以访问对象的原型。
构造函数、原型、实例的关系
构造函数的 prototype 属性指向 调用构造函数创建的实例 的原型对象;
原型的 constructor 属性指向 prototype 属性所在的构造函数;
实例的 __proto__ 属性指向原型对象。
functionPerson(name,age,job){this.name=name;this.age=age;this.job=job;}Person.prototype.sayName=function(){console.log(this.name);};varperson1=newPerson('Nicholas',29,'Software Engineer');console.log(Person.prototype.constructor===Person);// trueconsole.log(person1.__proto__===Person.prototype);// trueconsole.log(person1.sayName());// Nicholas
原型
构造函数
当用
new
运算符调用函数时,被调用的函数称作为构造函数(详情请看函数和构造函数
的构造函数
部分)。原型
每个构造函数都有一个
prototype
属性,这个属性指向一个对象,称之为函数的原型对象。函数的原型对象有一个
constructor
(构造函数)属性,这个属性包含一个指向prototype
属性所在函数的指针,即指向构造函数。实例
通过
new
操作符调用构造函数得到的对象,称之为实例
。实例内部包含一个指针(内部属性),指向构造函数的原型对象。一般通过对象的__proto__
属性可以访问对象的原型。构造函数、原型、实例的关系
prototype
属性指向 调用构造函数创建的实例 的原型对象;constructor
属性指向prototype
属性所在的构造函数;__proto__
属性指向原型对象。当读取实例的属性或方法时,如果找不到,就会查找实例的原型中的属性,如果还查不到,就去找原型的原型,一直向上找到最顶层为止。
实例
person1
的sayName
实际上是继承了它的原型的sayName
方法。原型链
先看下面的代码:
myDog
是Dog
的实例,调用myDog.makeSound()
方法时,先在myDog
实例上寻找makeSound
方法,没有找到,继续在myDog
的原型上查找,myDog
的原型是Animal
的一个实例,Animal
实例上也没有makeSound
方法,于是继续向上查找Animal
实例的原型,Animal
实例的原型是Animal.prototype
,它有makeSound
方法,于是执行了Animal.prototype.makeSound
方法。像这样,实例与原型之间的层层递进形成的链条一样的关系,称之为原型链。
默认原型
需要知道的是,js中的引用类型都继承了
Object
类型,这个继承也是通过原型链实现的。引用类型都可以通过原型链继承Object.prototype
上的方法。这也正是所有自定义类型都会继承toString()
、valueOf()
等默认方法的原因。确定实例与原型的关系
使用 instanceof 运算符
instanceof
运算符用于检测构造函数的prototype
属性是否出现在某个实例对象的原型链上。使用 isPrototypeOf() 方法
isPrototypeOf()
方法用于测试一个对象是否存在于另一个对象的原型链上。原型链的问题
原型中引用类型的值
原型中如果存在引用类型的值,则会被所有实例共享。
如果原型的属性被所有的实例共享,就会存在一个实例修改了这个属性后,也会影响到其他实例,这往往会造成一些不必要的麻烦。因此,通常的做法是在构造函数中,而不是在原型对象中定义属性。
不能向超类型的构造函数中传递参数
原型链的第二个问题是:在创建子类型的实例时,不能向超类型的构造函数中传递参数。实际上,应该说是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。有鉴于此,再加上前面刚刚讨论过的由于原型中包含引用类型值所带来的问题,实践中很少会单独使用原型链。
为了解决这些问题,可以使用一种叫做 借用构造函数(constructor stealing)的技术(有时候也叫做伪造对象或经典继承)。这种技术的基本思想相当简单,即在子类型构造函数的内部调用超类型构造函数。
以上代码在 SubType 内部使用 call 实现了对 SuperType 的"继承",同时每个实例都有自己的实例属性,互不影响;而且创建实例时还可以向超类型 SuperType 传递参数。
经验
在使用原型链继承时,一般都是把所有实例都会用到都方法和属性定义在原型上,而实例本身都属性和方法,且需要和其他实例区分开的,则定义在实例自身上(即在构造函数中定义)。
原型链继承的方式和技巧远不止这些,更多的技巧方法和对应解决的问题,可以看 创建对象和原型链继承的多种模式。
The text was updated successfully, but these errors were encountered: