这篇文章我们来了解一下对象属性值读写的具体过程。

1.getter和setter

之前我们了解了对象的属性描述符,这里我们来聊一下与之相对应的访问描述符-getter和setter。

在ES5中可以使用getter和setter部分改写默认操作,但是只能应用在单个属性上,无法应用在整个对象上。

getter是一个隐藏函数,会在获取属性值时调用。setter也是一个隐藏函数,会在设置属性值时调用。

当你给一个属性定义getter、setter或者两者都有时,这个属性会被定义为“访问描述符”(和“属性描述符”相对)。对于访问描述符来说,JavaScript会忽略它们的value和writable特性,取而代之的是关心set和get。

看一段代码:

var obj = {get a() {return 1;}
};
Object.defineProperty(obj, 'b', {get: function(){return 2;}
});
obj.a; //1
obj.b; //2

上面代码展示的就是定义getter的两种方式,不管是对象文字语法中的get a(){..},还是defineProperty(..)中的显式定义,二者都会在对象中创建一个不包含值的属性,对于这个属性的访问会自动调用一个隐藏函数,它的返回值会被当作属性访问的返回值。

通常来说getter和setter是成对出现的,getter一般也不会只返回一个静态的值:

var obj = {get a() {return this._a_;},set a(val) {this._a_ = val * 2;}
};
obj.a = 1;
obj.a; //2

对象中一个属性的getter/settter和writable/value不能同时被定义。

2.对象的读写

【下面的内容需要你对JavaScript的原型链有一定的了解】

1.[[Get]]

JavaScript中对象属性的访问是有一套完整的规则的,思考下面代码:

var obj = {a : 2};
obj.a; //2

obj.a是一次属性的访问,但是这条语句并不仅仅是在obj中查找名字为a的属性。在JavaScript的语言规范中,obj.a实际上是实现了[[Get]]操作。

对象默认的内置[[Get]]操作首先在对象中查找是否有名称相同的属性,如果有,就返回这个属性的值。

如果没有,就会继续访问对象的原型([[Prototype]])链:

var obj1 = {a : 1};
var obj = Object.create(obj1);
obj.hasOwnProperty('a'); //false
obj.a; // 1

Object.create会创建一个对象并把这个对象的[[Prototype]]关联到指定的对象。

可以通过Object.getPrototypeOf获取到对象的原型([[Prototype]]):

Object.getPrototypeOf(obj) === obj1; // true
//在浏览器中,一般可以通过__proto__访问到对象原型
obj.__proto__ === obj1; // true

现在obj的原型关联到了obj1。

在访问obj.a的时候,尽管a不存在于obj中,但是属性访问仍然成功的(在obj1中)找到了a的值为1。

如果obj中也找不到a并且原型链不为空的话,就会继续查找下去。

这个过程会持续到 找到匹配的属性名或者查找完整条原型链。如果是后者的话,[[Get]]操作的返回值是undefined。

所有普通的原型链最终都会指向内置的Object.prototype。

2.[[Put]]

既然有可以获取属性值的[[Get]]操作,就一定有对应的[[Put]]操作。 JavaScript中对象属性的设置是也有一套完整的规则的,思考下面代码:

var obj = {foo: 1};
obj.foo = 2;
obj.foo; //2

在给对象属性赋值的时候,如果已经存在这个属性,[[Put]]算法大致如下。

  1. 属性是否是访问描述符?如果是并且存在setter就调用setter。
  2. 属性的数据描述符中writable是否是false?如果是,在非严格模式下静默失败,在严格模式下抛出TypeError异常。
  3. 如果都不是,将该值设置为属性的值。

如果这个属性不存在,会出现以下3种情况:

1.如果在obj的原型链上层存在名为foo的普通数据访问属性并且没有被标记为只读(writable:false),那就会直接在obj中添加一个名为foo的新属性,它是屏蔽属性

var obj1 = {foo : 1};
var obj = Object.create(obj1);
obj.foo; //1
obj.foo = 2;
obj.foo; //2
obj1.foo; //1

什么是屏蔽属性?

如果一个属性名既出现在当前对象中也出现在当前对象的原型链上层,那么就会发生屏蔽。

当前对象中包含的属性会屏蔽原型链上层的所有同名属性,因为属性访问总是会选择原型链中最底层的属性。

上面代码片段中在给obj.foo重新赋值之后,再通过obj访问属性foo,就只能访问到新设置在当前foo对象上的foo的值了。

2.如果在obj的原型链上层存在foo,但是它被标记为只读(writable:false),那么无法修改已有属性或者在obj上创建屏蔽属性。如果运行在严格模式下,代码会抛出一个错误。

var obj1 = {}
Object.defineProperty(obj1,'foo', {value: 1,writable: false
});
var obj = Object.create(obj1);
obj.foo; //1
obj.foo = 2;//严格模式会抛出错误TypeError
obj.foo; //1
obj1.foo; //1

3.如果在obj的原型链上层存在foo并且它是一个setter,那就一定会调用这个setter。foo不会被添加到obj。

var obj1 = {};
Object.defineProperty(obj1, 'foo', {set: function(val){console.log('setter of obj1:' + val)}
})
var obj = Object.create(obj1);
obj.foo = 1; //输出:setter of obj1:1
obj.hasOwnProperty('foo'); //false

从上面代码片段可以看出,在执行obj.foo的时候,实际上只执行了obj1.foo的setter方法,并没有在obj上创建屏蔽属性。

如果你希望在第二种和第三种情况下也屏蔽foo,那就不能使用=操作符来赋值,而是使用Object.defineProperty来向obj添加foo:

var obj1 = {}
Object.defineProperty(obj1,'foo', {value: 1,writable: false
});
var obj = Object.create(obj1);
Object.defineProperty(obj,'foo', {value: 2
});
obj.foo; //2

javascript onsubmit返回false仍然能提交_JavaScript对象-Get和Put相关推荐

  1. onsubmit=“return check() 给form加onsubmit 验证所有表单后再提交,可以用返回false 来阻止submit提交

    onsubmit="return check() 给form加onsubmit 验证所有表单后再提交,可以用返回false 来阻止submit提交<form class="f ...

  2. 表单提交 onsubmit=return false

    一般,后台程序员与表单打交道的时间是最多的. 最近在看老师考试系统的源码, 看到了有这么一段代码,当时不是很理解, google寻求帮助. 现在来总结一下. <form action=" ...

  3. ajax 阻止默认提交,jQuery验证插件:在对ajax调用servlet时,submitHandler不会阻止默认提交-返回false无效...

    我有一个使用jquery和servlet的简单表单.jQuery对Servlet进行Ajax调用,然后Servlet进行一些服务器端计算,然后通过jQuery在同一页面上显示结果.我不希望表单进行默认 ...

  4. JavaScript 技术篇-chrome浏览器读取剪切板命令document.execCommand(‘paste‘)返回false原因及解决方法

    新版本 chrome 执行 document.execCommand('paste') 返回 false 因为读取剪切板涉及用户隐私安全,必须的用户允许的情况下可以进行访问,但是复制和剪切功能可以使用 ...

  5. IOS下,javascript 自带的 confirm 首次必返回 false

    前言 下面的代码,在IOS 13.3下执行时,首次必返回false. if (confirm("是否继续")) {alert("继续"); } else {al ...

  6. 由表单中onsubmit=return false;想到的

    众所周知,在表单中加上οnsubmit="return false;"可以阻止表单提交. 下面是简单的一小段代码: 代码 <form action="index.j ...

  7. Javascript 中的false、0、null、undefined和空字符串对象

    typeof类型检测 我们下来看看他们的类型分别是什么: alert(typeof(false) === 'boolean');//truealert(typeof(0) === 'number'); ...

  8. 在定时器中返回给视图的值_JavaScript二进制数组(2)TypedArray视图

    ArrayBuffer对象作为内存区域可以存放多种类型的数据.同一段内存,不同数据有不同的解读方式,这种解读方式称为"视图(view)".ArrayBuffer有两种类型的视图,一 ...

  9. java List集合中contains方法总是返回false

    ArrayList的contains方法 java 今天在用ArrayList类的caontains方法是遇到了问题,我写了一个存放User类的ArrayList 但在调用list.contains( ...

最新文章

  1. 第四代测序(纳米孔测序)有望全面代替边合成边测序吗?
  2. 第十六届智能车竞赛 | 单车拉力组浅析
  3. 【Flutter】StatelessWidget 组件 ( Divider 组件 | Card 组件 | AlertDialog 组件 )
  4. linux百万行数据加分页符,百万级数据量报表全量导出
  5. 读书笔记——《迁移到云原生架构》
  6. linux 计划任务格式,linux crontab 定时任务格式和使用方法2019-01-13
  7. 机器学习和AI的区别是什么?| 今日吐槽
  8. cad画多段线时不显示轨迹_CAD画的线段显示不出来的解决方法
  9. VS2015安装教程(带图解+下载地址+超详细)
  10. rtf文件怎么打开_什么是RTF文件(以及如何打开一个文件)?
  11. iOS 上的 WebSocket 框架 Starscream
  12. Leo的假期学习记录python大数据入门篇(3)
  13. eclipse没有web项目
  14. 微信分享,获取分享点击事件,登录后才可以分享
  15. 【C】C语言int型数组转化为char型字符串数组
  16. sql 创建学生表 课程表 成绩表
  17. 虚拟pc服务器 翻译,单机服务器配置文件;ServerSettings.ini【翻译】
  18. mui.fire运用
  19. JFreeChart Hacking-补丁贴
  20. 好玩的神乐七奈桌面宠物+附带音效

热门文章

  1. keil 5 出现 error:  #67: expected a } 错误解决
  2. wifi无线网卡移植到andorid
  3. 创客常用开发板“四剑客”对比,谁最“快”?
  4. 【DIY】自己动手更换热水器镁棒,保养电加热热水器注意事项,电热水器镁棒多久更换一次实际数据参考...
  5. windows 11预览版来了!
  6. 时域和频域的麦克斯韦方程组
  7. 计算机网络·详解TCP流量控制,拥塞控制,运输连接管理
  8. 子组件获取父组件的值,将这个值作为状态值保存
  9. VMware Workstation PRO 15 (已永久性激活)
  10. 在项目中配置Nexus Repository的信息