理解Javascript_06_理解对象的创建过程


Posted in Javascript onOctober 15, 2010

简单的代码
我们先来看一段简单的代码:

function HumanCloning(){ 
} 
HumanCloning.prototype ={ 
name:'笨蛋的座右铭' 
} 
var clone01 = new HumanCloning(); 
alert(clone01.name);//'笨蛋的座右铭' 
alert(clone01 instanceof HumanCloning);//true 
HumanCloning.prototype = {}; 
alert(clone01.name);//'笨蛋的座右铭' 
alert(clone01 instanceof HumanCloning);//false 
var clone02 = new HumanCloning(); 
alert(clone02.name);//undefined 
alert(clone02 instanceof HumanCloning);//true

复杂的理论
JS中只有函数对象(函数)具备类的概念,因此创建一个对象,必须使用函数对象。函数对象内部有[[Construct]]方法和[[Call]]方法,[[Construct]]用于构造对象,[[Call]]用于函数调用,只有使用new操作符时才触发[[Construct]]逻辑。注:在本例中HumanCloning这个自定义函数是一个函数对象,那么请问Object,String,Number等本地对象是函数对象吗?答案是肯定的,这是因为本地对象都可以看作是函数的派生类型,在这个意义上,可以将它们跟用户定义的函数等同看待。(与《理解Javascript_04_数据模型》中"内置数据类型"一节相呼应)
var obj=new Object(); 是使用内置的Object这个函数对象创建实例化对象obj。var obj={};和var obj=[];这种代码将由JS引擎触发Object和Array的构造过程。function fn(){}; var myObj=new fn();是使用用户定义的类型创建实例化对象。
注:关于函数对象的具体概念会在后续的文章中讲解,现在可以将"函数对象"简单的理解为"函数"的概念及可.

内部的实现
结合本例,函数对象为HumanCloning,函数对象创建的对象实例为clone01和clone02. 现在我们来看一下var clone01 = new HumanCloning();的实现细节(注:函数对象的[[Construct]]方法处理逻辑来负责实现对象的创建):
1. 创建一个build-in object对象obj并初始化
2. 如果HumanCloning.prototype是Object类型,则将clone01的内部[[Prototype]]设置为HumanCloning.prototype,否则clone01的[[Prototype]]将为其初始化值(即Object.prototype)
3. 将clone01作为this,使用args参数调用HumanCloning的内部[[Call]]方法
3.1 内部[[Call]]方法创建当前执行上下文(注:关于执行上下文,将在后续博文中讲解,在《Javascript提速_01_引用变量优化》一文中已有部分讲解》)
3.2 调用HumanCloning的函数体
3.3 销毁当前的执行上下文
3.4 返回HumanCloning函数体的返回值,如果HumanCloning的函数体没有返回值则返回undefined
4. 如果[[Call]]的返回值是Object类型,则返回这个值,否则返回obj
注意,如下代码为步骤1,步骤2和步骤3的代码解释:

var clone01 = {}; 
//程序外部是无法访问[[prototype]]的,仅用于理解 
//clone01.[[prototype]] = HumanCloning.prototype; 
HumanCloning.call(clone01);

注意步骤2中, prototype指对象显示的prototype属性,而[[Prototype]]则代表对象内部Prototype属性(隐式的)。构成对象Prototype链的是内部隐式的[[Prototype]],而并非对象显示的prototype属性。显示的prototype只有在函数对象上才有意义,从上面的创建过程可以看到,函数的prototype被赋给派生对象隐式[[Prototype]]属性,这样根据Prototype规则,派生对象和函数的prototype对象之间才存在属性、方法的继承/共享关系。(即原型继承实现原理,正是《理解Javascript_05_原型继承原理》的内容)
注意步骤3.4中描述,让我们来看一个来自于怿飞的问题:
理解Javascript_06_理解对象的创建过程

我想,现在回答这个问题,应该是易如反掌吧。

注:原文地址http://www.planabc.net/2008/02/20/javascript_new_function/

内存分析
理解Javascript_06_理解对象的创建过程
一张简易的内存图,并引入的函数对象的概念,同样也解释了上面代码(相对来说图不是很严谨,但易于理解)。在此也引出了一个问题,instanceof的实现原理,想必大家也看出了一些苗头,instanceof的判断依赖于原型链,具体实现细节,请参见后续博文。
本地属性与继承属性
对象通过隐式Prototype链能够实现属性和方法的继承,但prototype也是一个普通对象,就是说它是一个普通的实例化的对象,而不是纯粹抽象的数据结构描述。所以就有了这个本地属性与继承属性的问题。
首先看一下设置对象属性时的处理过程。JS定义了一组attribute,用来描述对象的属性property,以表明属性property是否可以在JavaScript代码中设值、被for in枚举等。
obj.propName=value的赋值语句处理步骤如下:
1. 如果propName的attribute设置为不能设值,则返回
2. 如果obj.propName不存在,则为obj创建一个属性,名称为propName
3. 将obj.propName的值设为value
可以看到,设值过程并不会考虑Prototype链,道理很明显,obj的内部[[Prototype]]是一个实例化的对象,它不仅仅向obj共享属性,还可能向其它对象共享属性,修改它可能影响其它对象。
我们来看一个示例:

function HumanCloning(){ 
} 
HumanCloning.prototype ={ 
name:'笨蛋的座右铭' 
} 
var clone01 = new HumanCloning(); 
clone01.name = 'jxl'; 
alert(clone01.name);//jxl 
var clone02 = new HumanCloning(); 
alert(clone02.name);//笨蛋的座右铭

结果很明确,对象的属性无法修改其原型中的同名属性,而只会自身创建一个同名属性并为其赋值。
参考。
https://3water.com/article/25008.htm
Javascript 相关文章推荐
JavaScript使用prototype定义对象类型
Feb 07 Javascript
JavaScript 获得选中文本内容的方法
Feb 15 Javascript
JQuery实现表格中相同单元格合并示例代码
Jun 26 Javascript
JavaScript lastIndexOf方法入门实例(计算指定字符在字符串中最后一次出现的位置)
Oct 17 Javascript
再谈javascript原型继承
Nov 10 Javascript
jQuery tagsinput在h5邮件客户端中应用详解
Sep 26 Javascript
echarts饼图扇区添加点击事件的实例
Oct 16 Javascript
Angular2之二级路由详解
Aug 31 Javascript
vue填坑之webpack run build 静态资源找不到的解决方法
Sep 03 Javascript
jquery判断滚动条距离顶部的距离方法
Sep 05 jQuery
微信小程序iBeacon测距及稳定程序的实现解析
Jul 31 Javascript
VUE页面中通过双击实现复制表格中内容的示例代码
Jun 11 Javascript
JavaScript聚焦于第一个字段的代码
Oct 15 #Javascript
JavaScript访问样式表代码
Oct 15 #Javascript
IE下js调试工具Companion.JS
Oct 15 #Javascript
jquery $.ajax各个事件执行顺序
Oct 15 #Javascript
jquery判断字符输入个数(数字英文长度记为1,中文记为2,超过长度自动截取)
Oct 15 #Javascript
jquery 元素相对定位代码
Oct 15 #Javascript
JQuery小知识
Oct 15 #Javascript
You might like
php 文件状态缓存带来的问题
2008/12/14 PHP
CI框架学习笔记(一) - 环境安装、基本术语和框架流程
2014/10/26 PHP
php防止sql注入之过滤分页参数实例
2014/11/03 PHP
PHP实现上传文件并存进数据库的方法
2015/07/16 PHP
php提取身份证号码中的生日日期以及验证是否为成年人的函数
2015/09/29 PHP
javascript 操作文件 实现方法小结
2009/07/02 Javascript
jQuery在IE下使用未闭合的xml代码创建元素时的Bug介绍
2012/01/10 Javascript
jquery删除ID为sNews的tr元素的内容
2014/04/10 Javascript
jQuery实现Twitter的自动文字补齐特效
2014/11/28 Javascript
iframe中子父类窗口调用JS的方法及注意事项
2015/08/25 Javascript
JAVASCRIPT代码编写俄罗斯方块网页版
2015/11/26 Javascript
Jquery修改image的src属性,图片不加载问题的解决方法
2016/05/17 Javascript
JS+Canvas绘制时钟效果
2020/08/20 Javascript
Bootstrap面板学习使用
2017/02/09 Javascript
原生JS京东轮播图代码
2017/03/22 Javascript
Vue 表情包输入组件的实现代码
2019/01/21 Javascript
深入理解使用Vue实现Context-Menu的思考与总结
2019/03/09 Javascript
JS检索下拉列表框中被选项目的索引号(selectedIndex)
2019/12/17 Javascript
[03:06]2018年度CS GO最具人气解说-完美盛典
2018/12/16 DOTA
在Python中操作字典之update()方法的使用
2015/05/22 Python
python实现对指定字符串补足固定长度倍数截断输出的方法
2018/11/15 Python
Python 实现打印单词的菱形字符图案
2020/04/12 Python
python判断是空的实例分享
2020/07/06 Python
python 装饰器重要在哪
2021/02/14 Python
全面总结使用CSS实现水平垂直居中效果的方法
2016/03/10 HTML / CSS
canvas绘制太极图的实现示例
2020/04/29 HTML / CSS
数控技术与应用毕业生自荐信
2013/09/24 职场文书
材料成型专业个人求职信范文
2013/09/25 职场文书
2014年教育培训工作总结
2014/12/08 职场文书
2015年酒店前台工作总结
2015/04/20 职场文书
证劵公司反洗钱宣传活动总结
2015/05/08 职场文书
《叶问2》观后感
2015/06/15 职场文书
政审证明范文
2015/06/19 职场文书
关于vue中如何监听数组变化
2021/04/28 Vue.js
新手必备Python开发环境搭建教程
2021/05/28 Python
解决vue-router的beforeRouteUpdate不能触发
2022/04/14 Vue.js