摘要:上一章我们谈了构造函数,他的唯一特点就是比较了地址不相同,因为大家知道引用类型是比较的引用。也就是说不用在构造函数中定义对象实例,而是直接将这些添加到原型当中。如果构造函数实例里面没有,就去原型里面查找,如果有就立即返回。
上一章我们谈了构造函数,他的唯一特点就是比较了地址不相同,因为大家知道引用类型是比较的引用。我们来谈谈原型。
原型
我们每创建一个函数都有一个原型(prototype)属性,这个属性是一个对象,他的特点是共享。也就是说不用在构造函数中定义对象实例,而是直接将这些添加到原型当中。
function Create () {} //声明一个构造函数 Create.prototype.a = "abc"; //在原型中添加属性 Create.prototype.b = 10; Create.prototype.c = function () { //在原型中添加方法 return this.a + this.b; }; var create = new Create(); alert(create.c()); //返回abc10
我们这次再来比较一下原型中方法的地址是否一致:
var create = new Create(); var create1 = new Create(); alert(create.c == create1.c); //true
是不是还没明白?我们用一张图来告诉大家:
这个__proto__就相当于指针,指向了原型对象的constructor,而constructor就相当于将构造函数对象和原型对象相关联。
那么我们要用构造函数对象去给重写属性或者方法会怎么样呢?
var create = new Create(); create.a = "EFD"; alert(create.a); //返回EFD
真的将原型对象里面的a给覆盖了么?并没有:
var create1 = new Create(); alert(create.a); //返回abc
原型模式的执行过程:
1.先去查找构造函数里面的属性和方法 ,如果有就立即返回。
2.如果构造函数实例里面没有,就去原型里面查找,如果有就立即返回。
因为我们在构造函数添加了属性,所以它会自动去查找,构造函数里面的属性也就立即返回了!
原型的字面量
在原型中,我们也可以使用字面量的方式去创建,可以让属性和方法体现出更好的封装效果。
function Create(a,b){}; //声明一个构造函数 Create.prototype = { //字面量方式 a:"abc", b:10, c:function () { return this.a + this.b; } };
不知道大家有没有发现,我们用字面量的方式是这样的:Create.prototype ={};
大家都知道,用一个{}就等同于new Create();这样,我们就相当于新声明的一个对象,我们原型对象里面的constructor还会指向Create么?
var create = new Create(); alert(create.constructor == Create); //false alert(create.constructor == Object); //true
(我们来解释一下为什么用create.constructor,因为我们打印constructor就会将整个构造函数打印出来,因为上面讲过它是将构造函数对象和原型对象相关联的属性。)
通过上面的例子可以看出,它已经指向了新的实例对象。
constructor的巧妙用法:
我们可以使用constructor来强制指回原来的实例对象:
function Create(a,b){}; Create.prototype = { constructor:Create, a:"abc", b:10, c:function () { return this.a + this.b; } };
原型对象的重写问题:
大家都知道,构造函数的属性和方法重写是无伤大雅的,但是原型对象中可以重写么?
function Create(a,b){}; Create.prototype = { constructor:Create, a:"abc", b:10, c:function () { return this.a + this.b; } }; Create.prototype = { a:"EFD", }; var create = new Create(); alert(create.c()); //create.c is not a function
不难看出,我们重写了原型会将之前的原型指向切断!!!
原型模式的缺点:
其实它的缺点也是它优点:共享。
我们在字面量里面给原型对象添加一个数组就很容易的看出来了:
function Create(a,b){}; Create.prototype = { constructor:Create, a:"abc", b:10, c:[第一个,第二个,第三个], d:function () { return this.a + this.b + this.c; } }; var create = new Create(); create.c.push("第四个"); alert(create.run()); //返回abc10第一个第二个第三个第四个
我们看得出这时候push添加已经生效了,在数组的末尾添加了“第四个”
我们再来实例一个对象就能看得出他的共享问题了:
var create1 = new Create(); alert(create1.run()); //返回abc10第一个第二个第三个第四个
这就是共享问题。下面新实例化一个对象也会将上面添加的字符串给共享到这里来。
这一章就到这里。欢迎所有阅读文章的人指正错误!
Brian Lee
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/91136.html
摘要:构造函数通过原型继承了构造函数和原型,这就形成了一个链条,通俗的讲就是原型链继承。而且方法只能冒充构造函数里面的属性和方法而无法冒充原型对象里面的属性和方法还有最大的问题就是重复使用。 前言: 写到这里,差不多就把OOP完结了,写了几篇OOP的文章,但是只是略懂皮毛,可能深入的OOP还有很多,但是我感觉写到这里也算是差不多完结了。 继承 继承是面向对象比较核心的概念,其他语言可能实现...
摘要:构造函数上一章我们讲了工厂模式,它的缺点就是无法识别到底哪个属于哪个的问题。我们可以用构造函数来解决这个识别问题。来比较构造函数内的值就可以看出到底是什么类型。 构造函数 上一章我们讲了工厂模式,它的缺点就是无法识别到底哪个属于哪个的问题。我们可以用构造函数来解决这个识别问题。 //构造函数 function Create(a,b) { this.a =a; this...
摘要:面向对象面向对象编程的全称是,简称,面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式。面向对象编程的三个主要特征是封装继承多态。 面向对象 面向对象编程的全称是Object Oriented Programming,简称OOP,面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式。面向对象编程可以看做是使用一系列对象相互协作的软件设计,面向对象程序设计的目的是在编程中促...
摘要:注意这里跟原型链继承有个比较明显的区别是并没有使用继承而是在子类里面执行父类的构造函数相当于把父类的代码复制到子类里面执行一遍这样做的另一个好处就是可以给父类传参。 Javascript继承 学过后端语言的同学对继承并不陌生,但是对JS继承少许还是有些困惑,不要试图问我是如果知道的,其实javascript继承主要是基于原型prototype实现的。 其实当你真正了解了原型链时候,再看...
摘要:工厂模式优点集中实例化,可以传参等缺点分不清属于哪个对象我们先来谈谈优点,看例子集中实例化返回实例化对象返回返回不难看出,工厂模式比上面的例子减少了很多代码。 ECMAscript开发的两种模式:1.过程化 2.OOP(面向对象) 面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性的方法的对象。但是ECMAscript中没有类的概念! 又谈作用域 首先...
阅读 2060·2021-11-23 09:51
阅读 2202·2021-09-29 09:34
阅读 3694·2021-09-22 15:50
阅读 3556·2021-09-22 15:23
阅读 2556·2019-08-30 15:55
阅读 699·2019-08-30 15:53
阅读 3065·2019-08-29 17:09
阅读 2623·2019-08-29 13:57