ife task0003学习笔记(四):JavaScript构造函数
JavaScript创建对象主要是3种方法:工厂模式、构造函数模式、原型模式。其实对于构造函数的概念,我们并不陌生。在之前学习c++语言的时候,也有提到过构造函数的概念。除了创建对象,构造函数(constructor) 可以自动为创建的新对象设置原型对象(prototype object) ,原型对象存放于Constructor Function.prototype 属性中。
1.对象封装
如果一个对象具有属性"(property)和"方法"(method),我们希望封装成一个对象,甚至要从原型对象生成一个实例对象,那么就诞生了构造函数的思想。首先来看原始的实现方式:
var Cat = {
name : '',
color : ''
}
现在可以根据这个原型对象的规格(schema,生成两个实例:
var cat1 = {}; // 创建一个空对象
cat1.name = "大毛"; // 按照原型对象的属性赋值
cat1.color = "黄色";
var cat2 = {};
cat2.name = "二毛";
cat2.color = "黑色";
为了解决代码重复赘余问题,上述代码可以改进如下:
function Cat(name,color){
return {
name:name,
color:color
}
}
接下来是生成实例对象,即调用函数:
var cat1 = Cat("大毛","黄色");
var cat2 = Cat("二毛","黑色");
问题:at1和cat2之间没有内在的联系,不能反映出它们是同一个原型对象的实例
2.构造函数
为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。
所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。
function Cat(name,color){
this.name=name;
this.color=color;
}
生成实例对象:
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.name); // 大毛
alert(cat1.color); // 黄色
这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。
alert(cat1.constructor == Cat); //true
alert(cat2.constructor == Cat); //true
Javascript还提供了一个instanceof运算符,验证原型对象与实例对象之间的关系。
alert(cat1 instanceof Cat); //true
alert(cat2 instanceof Cat); //true
构造函数方法很好用,但是存在一个浪费内存的问题。
3.构造函数的深入理解
// 构造函数
function Foo(y) {
// 构造函数将会以特定模式创建对象:被创建的对象都会有"y"属性
this.y = y;
}
// "Foo.prototype"存放了新建对象的原型引用
// 所以我们可以将之用于定义继承和共享属性或方法
// 所以,和上例一样,我们有了如下代码:
// 继承属性"x"
Foo.prototype.x = 10;
// 继承方法"calculate"
Foo.prototype.calculate = function (z) {
return this.x + this.y + z;
};
// 使用foo模式创建 "b" and "c"
var b = new Foo(20);
var c = new Foo(30);
// 调用继承的方法
b.calculate(30); // 60
c.calculate(40); // 80
// 让我们看看是否使用了预期的属性
console.log(
b.__proto__ === Foo.prototype, // true
c.__proto__ === Foo.prototype, // true
// "Foo.prototype"自动创建了一个特殊的属性"constructor"
// 指向a的构造函数本身
// 实例"b"和"c"可以通过授权找到它并用以检测自己的构造函数
b.constructor === Foo, // true
c.constructor === Foo, // true
Foo.prototype.constructor === Foo // true
b.calculate === b.__proto__.calculate, // true
b.__proto__.calculate === Foo.prototype.calculate // true
);
上述代码可以表示关系为:
JavaScript 中的构造函数和其它语言中的构造函数是不同的。 通过 new 关键字方式调用的函数都被认为是构造函数。
在构造函数内部 - 也就是被调用的函数内 - this 指向新创建的对象 Object。 这个新创建的对象的 prototype 被指向到构造函数的 prototype。
如果被调用的函数没有显式的 return 表达式,则隐式的会返回 this 对象 - 也就是新创建的对象。
function Foo() {
this.bla = 1;
}
Foo.prototype.test = function() {
console.log(this.bla);
};
var test = new Foo();
上面代码把 Foo 作为构造函数调用,并设置新创建对象的 prototype 为 Foo.prototype。
显式的 return 表达式将会影响返回结果,但仅限于返回的是一个对象。
4.构造函数问题
可能会浪费内存。那就是对于每一个实例对象,如果这些实例的某些属性和方法都是一模一样的内容,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。能不能让一模一样的属性和方法在内存中只生成一次,然后所有实例都指向那个内存地址呢?回答是可以的,Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。
function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){alert("吃老鼠")};
生成实例:
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠
这时所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。
alert(cat1.eat == cat2.eat); //true
5. Prototype模式的验证方法
1.isPrototypeOf()
这个方法用来判断,某个proptotype对象和某个实例之间的关
alert(Cat.prototype.isPrototypeOf(cat1)); //true
alert(Cat.prototype.isPrototypeOf(cat2)); //true
2.hasOwnProperty()
每个实例对象都有一个hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。
alert(cat1.hasOwnProperty("name")); // true
alert(cat1.hasOwnProperty("type")); // false
3.in
in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。
alert("name" in cat1); // true
alert("type" in cat1); // true
参考资料:
阮一峰http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html
JavaScript探秘:构造函数 Constructorhttp://www.nowamagic.net/librarys/veda/detail/1642
ife task0003学习笔记(四):JavaScript构造函数的更多相关文章
- ife task0003学习笔记(一):JavaScript作用域
在学习JavaScript作用域概念之前,首先要明白几个概念:执行环境.变量对象.作用域链. 一.JavaScript执行环境(execution context): 在<Professiona ...
- ife task0003学习笔记(三):JavaScript闭包
一.this易错分析 在学习闭包的时候,有一个概念this很重要,关于this的理解,下面3种情况:this指向谁? fn.call(obj1); obj2.fn() fn() 答案是obj1 obj ...
- ife task0003学习笔记(五):JavaScript面向对象
JavaScript 支持函数式编程.闭包.基于原型的继承等高级功能.在 Java 等面向对象的语言中,this 关键字的含义是明确且具体的,即指代当前对象.而在 JavaScript 中,this ...
- ife task0003学习笔记(二):JavaScript原型
function aaa(){} aaa.prototype.bbb=function(){} var obj1=new aaa() var obj2=new aaa() obj1和obj2都有一个属 ...
- seaJs学习笔记之javascript的依赖问题
之前分别为大家介绍了有关javascript中的冲突和性能问题,今天为大家介绍一下有关javascript中的依赖问题.我们将继续就之前javascript中性能问题继续介绍. 先来回顾一下性能问题的 ...
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
- Typescript 学习笔记四:回忆ES5 中的类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- 【学习笔记】JavaScript的基础学习
[学习笔记]JavaScript的基础学习 一 变量 1 变量命名规则 Camel 标记法 首字母是小写的,接下来的字母都以大写字符开头.例如: var myTestValue = 0, mySeco ...
- C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻
前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...
随机推荐
- SharePoint 2013在浏览器中打开pdf文档
在没有安装Office Web Apps的情况下,SharePoint 2013是支持在IE上直接打开pdf和Excel文档的(只能查看,不能编辑,部分Excel会报错). 当然,需要现在管理中心做一 ...
- FileTracker:error FTK1011编译错误的原因和解决办法
原因: 今天创建好项目名字完成关了VS,后感觉文件夹名字不太对改了一下,后来程序就调试不了出现FileTracker:error FTK1011编译错误0.0,经过网络查询应该是路径问题 解决方法: ...
- 开启和查看mysql的bin-log日志
[root@VM_0_7_centos data]# vim /etc/my.cnf [root@VM_0_7_centos data]# vim /etc/my.cnf [root@VM_0_7_c ...
- IPython绘图和可视化---matplotlib 入门
最近总是需要用matplotlib绘制一些图,由于是新手,所以总是需要去翻书来找怎么用,即使刚用过的,也总是忘.所以,想写一个入门的教程,一方面帮助我自己熟悉这些函数,另一方面有比我还小白的新手可以借 ...
- SDUT OJ 数据结构实验之二叉树二:遍历二叉树
数据结构实验之二叉树二:遍历二叉树 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descr ...
- C++中define与const的区别
C++中不但可以用define定义常量还可以用const定义常量,它们的区别如下: 用#define MAX 255定义的常量是没有类型的,所给出的是一个立即数,编译器只是把所定义的常量值与所定义的常 ...
- SQL中删除重复的行(重复数据),只保留一行 转
方法一:使用在T-SQL的编程中 分配一个列号码,以COL1,COL2组合来分区排序,删除DATABASE重复的行(重复数据),只保留一行 // COL1,COL2是数据库DATABASE的栏位 de ...
- JUC包下CountDownLatch学习笔记
CountDownLatch的作用是能使用多个线程进来之后,且线程任务执行完毕之后,才执行, 闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态.通俗的讲就是,一个闭锁相当于 ...
- Services版本tomcat 内存和perm 设置
当在tomcat的webapps文件夹中部署需要大量资源的war包时,启动tomcat,war包将不能被成功部署. tomcat安装有services版安装和开发版安装. 本经验将介绍如何设置两种版本 ...
- LightOJ - 1032 数位DP
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #i ...