内容简介:工厂模式虽然解决了创建多个相似对象的问题,但是却没有解决对象识别的问题,即怎样知道一个对象的类型。构造函数和工厂函数不同之处在于:** 调用构造函数会经历下面4个步骤(即new干了什么)**:
var person = function(name,age){ var o = new Object(); o.name = name; o.age = age; o.sayName = function() { console.log(this.name) } return o; } var person1 = person('li', 20); var person2 = person('xiao', 18); person1.sayName(); //li person2.sayName(); //xiao 复制代码
- 先创建一个object
- object绑定属性和方法
- 返回这个object
缺点
工厂模式虽然解决了创建多个相似对象的问题,但是却没有解决对象识别的问题,即怎样知道一个对象的类型。
构造函数
var Person = function(name,age) { this.name = name; this.age = age; this.sayName = function() { console.log(this.name) } } var person1 = new Person('li',20) var person2 = new Person('xiao',18) person1.sayName() //li person2.sayName() //xiao 复制代码
构造函数和工厂函数不同之处在于:
- 没有显示的创建对象
- 直接将属性和方法赋给了this对象
- 没有return语句
- 函数名的首字母大写
- 要创建构造函数的实例,必须使用new操作符
** 调用构造函数会经历下面4个步骤(即new干了什么)**:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此this指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
上面的person1和person2分别保存Person的一个不同实例,这两个对象都有一个constructor(构造函数)属性,该属性执行Person
person1.constructor == person2.constructor == Person
可以用constructor来识别对象类型,但是用instanceof 更可靠
person1和person2同时也是object的实例,因为所有的对象都继承自Object
缺点
如果构造函数里面有方法,那方法都会在每个实例上都创建一遍,因此不同实例上的函数是不相等的
person1.sayName == person2.sayName // false
虽然可以把方法移到构造函数外部,设置成全局函数,但是如果对象需要定义很多方法,就要定义很多个全局函数,
原型模式
function Person(){}; Person.prototype.name = "li"; Person.prototype.age = 20; Person.prototype.sayName = function(){ console.log(this.name) }; var person1 = new Person() var person2 = new Person() person1.sayName() //li person2.sayName() //li person2.name = 'xiao' //person2这个实例加了一个name属性,重写name属性,但不会改变原型的值 person1.sayName() //li person2.sayName() //xiao //如果实例上有name属性,取的是实例上的 复制代码
好处
可以让所有对象实例共享它所包含的属性和方法。
person1.sayName !== person2.sayName //true
原型对象
只要创建了一个函数,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针(妈呀,很拗口,看代码和图比较直观)
创建了自定义的构造函数后,其原型对象默认只会取得constructor属性,至于其他方法,都是从object继承而来。当调用构造函数创建一个实例,该实例内部将包含一个指针,指向构造函数的原型对象,可以用_proto_属性访问。这个链接存在与实例与构造函数的原型对象之间,而不存在于实例与构造函数之间。
Person.prototype.constructor = Person
person1._proto_ == Person.prototype
判断是不是对象的原型
- isPrototypeOf
Person.prototype.isPrototypeOf(person1) // true
- Object.getPrototypeOf可以取到一个实例的原型
Object.getPrototypeOf(person1) == Person.prototype // true
Object.getPrototypeOf(person1).name //li
判断一个属性是存在实例中还是原型中
- hasOwnProperty()只在给定属性存在实例中时,才返回true
person1.hasOwnProperty('name') // false person2.hasOwnProperty('name') //true 复制代码
- in 不管属性是存在实例上还是原型中,都返回true
'name' in Person // true
hasOwnProperty和in一起可以判断属性是不是在原型中
!object.hasOwnProperty(name) && ('name' in object)
对象字面量
我们将Person.prototype 设置为等于一个以对象字面量形式创建的新对象,最终结果相同,但是constructor属性不再指向Person。这里的语法,本质上完成重写了默认的portotype对象,因此它的原型是Object,constructor是指向Object的构造函数。但是用instanceof 操作符还能返回正确结果
function Person(){}; Person.prototype = { name: 'li', age: 20, sayName: function(){ console.log(this.name) } }; var person1 = new Person() console.log(Person.prototype.constructor == Person) //false console.log(Person.prototype.constructor == Object) //true console.log(person1 instanceof Person) // true 复制代码
原型的动态性
function Person(){}; var person1 = new Person() Person.prototype = { name: 'li', age: 20, sayName: function(){ console.log(this.name) } }; person1.sayName() //person1.sayName is not a function 复制代码
先创建实例,在重写其原型对象,会切断现有原型与之前任何已经存在的对象实例之间的联系。person1引用的还是原来的原型。可以用下面这种写法
function Person(){}; var person1 = new Person() Person.prototype.sayName = function(name){ console.log(name) } person1.sayName('li') //li 复制代码
原型对象的缺点
- 省略了为构造函数传递初始化参数,所有实例在默认情况下都取得相同的属性值。
- 如果有引用类型的属性,会导致在一个实例里修改引用类型的值,会把原型上的也修改了
组合使用构造函数模式和原型模式
- 构造函数模式用于定义实例属性
- 原型模式用于定义方法和共享的属性
var Person = function(name,age) { this.name = name; this.age = age; } Person.prototype.sayName = function(){ console.log(this.name) }; var person1 = new Person('li',20) var person2 = new Person('xiao',18) person1.sayName() //li person2.sayName() //xiao 复制代码
- 动态原型模式
function Person(name, age){ this.name = name; this.age = age if(typeof this.sayName != function) { Person.prototype.sayName = function(name){ console.log(this.name) } } }; 复制代码
判断这个代码只会在初次调用构造函数时执行
- 寄生构造函数模式
- 委托构造函数模式 不引用this
继承
js只支持实现继承 主要是依靠 原型链 来实现的.
利用原型让一个引用类型继承另一个引用类型的属性和方法
方法:
- 原型链
- 借用构造函数
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合式继承
原型链
每一个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例都包含一个指向原型对象的指针。那么,如果我们让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应的,另一个原型中也包含着一个指向另一个构造函数的指针,假如另一个原型又是另一个类型的实例。。。如此层层递进,就构成了实例和原型的链条
如果引用对象(实例instance)的某个属性,会现在这个对象内找,如果找不到,就会到这个对象的原型上去找,原型上找不到,就到原型的原型上去找,直到找到这个属性或者返回null为止
以上所述就是小编给大家介绍的《创建对象、原型、原型链》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 对象.原型链,函数.原型对象
- 【前端基础进阶】JS原型、原型链、对象详解
- 说说JS中的原型对象和原型链
- 《JavaScript面向对象精要》之四:构造函数和原型对象
- 由对象到原型
- 前端进击的巨人(七):走进面向对象,原型与原型链,继承方式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据结构与算法分析
Mark Allen Weiss / 冯舜玺 / 电子工业出版社 / 2016-8 / 89.00元
本书是数据结构和算法分析的经典教材,书中使用主流的程序设计语言C++作为具体的实现语言。书中内容包括表、栈、队列、树、散列表、优先队列、排序、不相交集算法、图论算法、算法分析、算法设计、摊还分析、查找树算法、k-d树和配对堆等。本书把算法分析与C++程序的开发有机地结合起来,深入分析每种算法,内容全面、缜密严格,并细致讲解精心构造程序的方法。一起来看看 《数据结构与算法分析》 这本书的介绍吧!