JavaScript创建对象_动力节点Java学院整理


Posted in Javascript onJune 27, 2017

JavaScript对每个创建的对象都会设置一个原型,指向它的原型对象。

当我们用obj.xxx访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype对象,最后,如果还没有找到,就只能返回undefined。
例如,创建一个Array对象:

var arr = [1, 2, 3];

其原型链是:

arr ----> Array.prototype ----> Object.prototype ----> null

Array.prototype定义了indexOf()、shift()等方法,因此你可以在所有的Array对象上直接调用这些方法。
当我们创建一个函数时:

function foo() {
 return 0;
}

函数也是一个对象,它的原型链是:

foo ----> Function.prototype ----> Object.prototype ----> null

由于Function.prototype定义了apply()等方法,因此,所有函数都可以调用apply()方法。

很容易想到,如果原型链很长,那么访问一个对象的属性就会因为花更多的时间查找而变得更慢,因此要注意不要把原型链搞得太长。

构造函数

除了直接用{ ... }创建一个对象外,JavaScript还可以用一种构造函数的方法来创建对象。它的用法是,先定义一个构造函数:

function Student(name) {
 this.name = name;
 this.hello = function () {
  alert('Hello, ' + this.name + '!');
 }
}

你会问,咦,这不是一个普通函数吗?

这确实是一个普通函数,但是在JavaScript中,可以用关键字new来调用这个函数,并返回一个对象:

var xiaoming = new Student('小明');
xiaoming.name; // '小明'
xiaoming.hello(); // Hello, 小明!

注意,如果不写new,这就是一个普通函数,它返回undefined。但是,如果写了new,它就变成了一个构造函数,它绑定的this指向新创建的对象,并默认返回this,也就是说,不需要在最后写return this;。

新创建的xiaoming的原型链是:

xiaoming ----> Student.prototype ----> Object.prototype ----> null

也就是说,xiaoming的原型指向函数Student的原型。如果你又创建了xiaohong、xiaojun,那么这些对象的原型与xiaoming是一样的:
xiaoming ?
xiaohong -→ Student.prototype ----> Object.prototype ----> null
xiaojun  ?

用new Student()创建的对象还从原型上获得了一个constructor属性,它指向函数Student本身:

xiaoming.constructor === Student.prototype.constructor; // true
Student.prototype.constructor === Student; // true

Object.getPrototypeOf(xiaoming) === Student.prototype; // true

xiaoming instanceof Student; // true

看晕了吧?用一张图来表示这些乱七八糟的关系就是:

JavaScript创建对象_动力节点Java学院整理

红色箭头是原型链。注意,Student.prototype指向的对象就是xiaoming、xiaohong的原型对象,这个原型对象自己还有个属性constructor,指向Student函数本身。
另外,函数Student恰好有个属性prototype指向xiaoming、xiaohong的原型对象,但是xiaoming、xiaohong这些对象可没有prototype这个属性,不过可以用__proto__这个非标准用法来查看。
现在我们就认为xiaoming、xiaohong这些对象“继承”自Student。
不过还有一个小问题,注意观察:

xiaoming.name; // '小明'
xiaohong.name; // '小红'
xiaoming.hello; // function: Student.hello()
xiaohong.hello; // function: Student.hello()
xiaoming.hello === xiaohong.hello; // false

xiaoming和xiaohong各自的name不同,这是对的,否则我们无法区分谁是谁了。
xiaoming和xiaohong各自的hello是一个函数,但它们是两个不同的函数,虽然函数名称和代码都是相同的!
如果我们通过new Student()创建了很多对象,这些对象的hello函数实际上只需要共享同一个函数就可以了,这样可以节省很多内存。

要让创建的对象共享一个hello函数,根据对象的属性查找原则,我们只要把hello函数移动到xiaoming、xiaohong这些对象共同的原型上就可以了,也就是Student.prototype:

JavaScript创建对象_动力节点Java学院整理

修改代码如下:

function Student(name) {
 this.name = name;
}

Student.prototype.hello = function () {
 alert('Hello, ' + this.name + '!');
};

用new创建基于原型的JavaScript的对象就是这么简单!

忘记写new怎么办

如果一个函数被定义为用于创建对象的构造函数,但是调用时忘记了写new怎么办?
在strict模式下,this.name = name将报错,因为this绑定为undefined,在非strict模式下,this.name = name不报错,因为this绑定为window,于是无意间创建了全局变量name,并且返回undefined,这个结果更糟糕。
所以,调用构造函数千万不要忘记写new。为了区分普通函数和构造函数,按照约定,构造函数首字母应当大写,而普通函数首字母应当小写,这样,一些语法检查工具如jslint将可以帮你检测到漏写的new。
最后,我们还可以编写一个createStudent()函数,在内部封装所有的new操作。一个常用的编程模式像这样:

function Student(props) {
 this.name = props.name || '匿名'; // 默认值为'匿名'
 this.grade = props.grade || 1; // 默认值为1
}

Student.prototype.hello = function () {
 alert('Hello, ' + this.name + '!');
};

function createStudent(props) {
 return new Student(props || {})
}

这个createStudent()函数有几个巨大的优点:一是不需要new来调用,二是参数非常灵活,可以不传,也可以这么传:

var xiaoming = createStudent({
 name: '小明'
});

xiaoming.grade; // 1

如果创建的对象有很多属性,我们只需要传递需要的某些属性,剩下的属性可以用默认值。由于参数是一个Object,我们无需记忆参数的顺序。如果恰好从JSON拿到了一个对象,就可以直接创建出xiaoming。

练习

请利用构造函数定义Cat,并让所有的Cat对象有一个name属性,并共享一个方法say(),返回字符串'Hello, xxx!':

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jsp网页搜索结果中实现选中一行使其高亮
Feb 17 Javascript
javascript实现网页背景烟花效果的方法
Aug 06 Javascript
js实现带有介绍的Select列表菜单实例
Aug 18 Javascript
全面解析Bootstrap排版使用方法(文字样式)
Nov 30 Javascript
Vue 单文件中的数据传递示例
Mar 21 Javascript
vue2.0与bootstrap3实现列表分页效果
Nov 28 Javascript
JS+CSS实现滚动数字时钟效果
Dec 25 Javascript
php 解压zip压缩包内容到指定目录的实例
Jan 23 Javascript
基于百度地图api清除指定覆盖物(Overlay)的方法
Jan 26 Javascript
AngularJS实现的自定义过滤器简单示例
Feb 02 Javascript
js实现图片3D轮播效果
Sep 21 Javascript
React+Redux实现简单的待办事项列表ToDoList
Sep 29 Javascript
JavaScript字符串_动力节点Java学院整理
Jun 27 #Javascript
JavaScript变量作用域_动力节点Java学院整理
Jun 27 #Javascript
详解微信小程序 登录获取unionid
Jun 27 #Javascript
JavaScript定义函数_动力节点Java学院整理
Jun 27 #Javascript
详解vue项目构建与实战
Jun 27 #Javascript
微信小程序 蓝牙的实现实例代码
Jun 27 #Javascript
微信小程序 开发MAP(地图)实例详解
Jun 27 #Javascript
You might like
一些常用的php简单命令代码集锦
2007/09/24 PHP
深入理解PHP之数组(遍历顺序)  Laruence原创
2012/06/13 PHP
jquery tablesorter.js 支持中文表格排序改进
2009/12/09 Javascript
基于jquery的无缝循环新闻列表插件
2011/03/07 Javascript
jQuery 在光标定位的地方插入文字的插件
2012/05/10 Javascript
javascript jscroll模拟html元素滚动条
2012/12/18 Javascript
IE中图片的onload事件无效问题和解决方法
2014/06/06 Javascript
基于jquery实现可定制的web在线富文本编辑器附源码下载
2015/11/17 Javascript
jquery及js实现动态加载js文件的方法
2016/01/21 Javascript
基于JQuery的$.ajax方法进行异步请求导致页面闪烁的解决办法
2016/05/10 Javascript
jquery遍历table的tr获取td的值实现方法
2016/05/19 Javascript
JavaScript程序中的流程控制语句用法总结
2016/05/23 Javascript
JavaScript简单获取页面图片原始尺寸的方法
2016/06/21 Javascript
JavaScript构建自己的对象示例
2016/11/29 Javascript
jQuery实现三级联动效果
2017/03/02 Javascript
canvas绘制一个常用的emoji表情
2017/03/30 Javascript
js时间戳与日期格式之间相互转换
2017/12/11 Javascript
10行原生JS实现文字无缝滚动(超简单)
2018/01/02 Javascript
vue如何解决循环引用组件报错的问题
2018/09/22 Javascript
Python使用turtule画五角星的方法
2015/07/09 Python
python查看FTP是否能连接成功的方法
2015/07/30 Python
Python 功能和特点(新手必学)
2015/12/30 Python
Python列表list内建函数用法实例分析【insert、remove、index、pop等】
2017/07/24 Python
R语言 vs Python对比:数据分析哪家强?
2017/11/17 Python
对python特殊函数 __call__()的使用详解
2019/07/02 Python
Pytest框架之fixture的详细使用教程
2020/04/07 Python
css3实现3d旋转动画特效
2015/03/10 HTML / CSS
Redbubble法国:由独立艺术家设计的独特产品
2019/01/08 全球购物
如何提高SQL Server的安全性
2016/07/25 面试题
服务中心夜班服务员岗位职责
2013/11/27 职场文书
软件测试专业推荐信
2014/09/18 职场文书
财务人员岗位职责
2015/02/03 职场文书
给老婆的检讨书(搞笑版)
2015/05/06 职场文书
奖学金发言稿(范文)
2019/08/21 职场文书
微软PC Health Check电脑健康状况检查应用下载(Win11配置检测工具)
2021/06/26 数码科技
TypeScript 使用 Tuple Union 声明函数重载
2022/04/07 Javascript