以下内容,来自于《JavaScript高级程序设计.第4版》,之前看网上的资料学习原型一直是一脸懵(自己基础太差)。这次通过工厂模式、构造函数引导到原型,算是对原型有了一定的了解,不过要想掌握,还是需要实践以及回顾。
工厂模式:
构造函数:
在Person()内部和createPerson()基本一样,有如下区别:
1.构造函数没有显示的创建对象
2.属性和方法直接赋值给了this
3.没有return
4.方法名首字母大写(构造函数必须,借鉴于面向对象编程语言,有助于区分构造函数和普通函数)
构造函数要创建Person实例,应使用new操作符。通过这种方式调用构造函数会执行如下操作:
①.在内存中创建一个新对象
②.新对象内部的[[Prototype]]特征被赋值为构造函数的prototype属性
③.构造函数内部的this被赋值为这个新对象。
④.执行构造函数内部的代码(给新对象添加属性)
⑤.如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
定义自定义构造函数可以确保实例被标识为特定类型。
构造函数的主要问题在于,其定义的方法会在每个实例上都创建一遍。
通过将函数定义转移到构造函数外部,可以解决这个问题。
sayName()定义在了构造函数外部。在构造函数内部,sayName属性等于全局sayName()函数。因为它只包含一个指向外部函数的指针。但是这样,全局作用域也会变得混乱,就会出现新的问题。
为了解决这个问题,可以通过原型来解决。
原型模式:
1.理解原型
创建对象,就会为这个函数创建一个prototype属性(指向原型对象)。所有的原型对象自动获得一个名为constructor的属性,指回与之关联的构造函数。如上图的例子,Person.prototype.constructor指向Person。
在自定义构造函数时,原型对象默认只会获得constructor属性,其他的所有方法都继承自Object。每次调用构造函数创建一个新实例,这个实例内部[[Prototype]]指针就会被赋值为构造函数的原型对象。在脚本中无法访问[[Prototype]]特性,但是浏览器会在每个对象上暴露_proto_属性,来访问对象的原型。
注:实例与构造函数原型之间有直接的联系,但是实例与构造函数之间没有直接联系。
2.原型层级
再通过对象访问属性时,会先搜索对象实例本身,如果在这个实例上发现了给定的属性名称,就会返回该名称对应的值。如果没有找到,就会沿着指针进入原型对象并进行搜索。找到属性后,在返回对应的值。
可以通过实例读取原型对象上的值,但是不能通过实例修改这些值。
当给实例添加属性时,就会遮蔽原型对象上的同名属性。
那么,要想再次获取到原型对象上的该属性,就需要delete person1.name 进行删除。
同时,可以通过hasOwnProPerty()方法判断某个属性是在实例上还是在原型对象上。该方法继承自Object,当属性存在于调用它的对象实例上时返回true。
还有一些方法就不列举了,下面说一说原型存在的问题。
首先,弱化了向构造函数传递初始化参数的能力,会导致所有实例默认都取得相同属性值。其次,原型的最主要问题源自共享特性。