We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
作者:Dmitri Pavlutin 译者:前端小智 来源:dmitripavlutin
点赞再看,养成习惯 本文 GitHub https://github.com/qq449245884/xiaozhi 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。
点赞再看,养成习惯
本文 GitHub https://github.com/qq449245884/xiaozhi 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。
GitHub
在 ES6 之前,JS 中的对象字面量(也称为对象初始化器)是非常基础的。可以定义两种类型的属性:
键值对 {name1: value1}
{name1: value1}
获取器 { get name(){..} } 和 设置器 { set name(val){..}} 的计算属性值
{ get name(){..} }
{ set name(val){..}}
var myObject = { myString: 'value 1', get myNumber() { return this._myNumber; }, set myNumber(value) { this._myNumber = Number(value); }, }; myObject.myString; // => 'value 1' myObject.myNumber = '15'; myObject.myNumber; // => 15
JS 是一种基于原型的语言,因此一切都是对象。 在对象创建,配置和访问原型时,必须提供一种易于构造的语言。
定义一个对象并设置它的原型是一个常见的任务。最好的方式是直接在对象字面量使用一条语句来设置原型。
不幸的是,字面量的局限性不允许用一个简单的解决方案来实现这一点。必须结合使用object.create() 和对象字面量来设置原型。
object.create()
var myProto = { propertyExists: function(name) { return name in this; } }; var myNumbers = Object.create(myProto); myNumbers['arrat'] = [1, 6, 7]; myNumbers.propertyExists('array'); // => true myNumbers.propertyExists('collection'); // => false
我认为这种解决方案不够灵活。JS 是基于原型的,为什么要用原型创建对象那么麻烦?
幸运的是,JS 也在慢慢完善。JS 中很多令人沮丧的问题都是逐步解决的。
本文演示了 ES 6 如何解决上述问题,并使用额外的功能改进对象字面量。
如你所知,访问现有对象原型的一种方法是使用 getter 属性 __proto__:
__proto__
var myObject = { name: 'Hello World!', }; myObject.__proto__; // => {} myObject.__proto__.isPrototypeOf(myObject); // => true
myObject.__ proto__ 返回 myObject 的原型对象。
myObject.__ proto__
myObject
请注意,不建议将 object.__ proto__ 用作 getter/setter。替代方法应考虑使用Object.getPrototypeOf() 和 Object.setPrototypeOf()。
object.__ proto__
getter/setter
Object.getPrototypeOf()
Object.setPrototypeOf()
ES6允许使用__proto__作为属性名,并在 {__proto__:protoObject}中设置原型。
{__proto__:protoObject}
接着,咱们使用 __proto__ 属性进行对象初始化,并优化上面的代码:
var myProto = { propertyExists: function(name) { return name in this; }, }; var myNumbers = { __proto__: myProto, array: [1, 6, 7], }; myNumbers.propertyExists('array'); // => true myNumbers.propertyExists('collection'); // => false
myNumbers 对象是使用特殊属性名 proto 与创建原型 myProto,这次咱们使用一条语句就创建,没有像上面还需要 object.create() 这样的附加函数。
myNumbers
proto
myProto
如你所看,使用 __proto__ 进行编码很简单,我一直喜欢简单明了的解决方案。
说点脱离主题。 我觉得奇怪的是,简单灵活的解决方案需要大量的工作和设计。如果解决方案很简单,你可能会认为设计起来很容易。但是反之亦然:
如果某些东西看起来太复杂或难以使用,则可能还需要进一步的完善。
你对简单性有何看法? (请在下面随意写评论)
即使__proto__看起来很简单,您也应该注意一些特殊情况。
在对象字面量中只能使用__proto__一次,否则 JS 会报错:
__proto__一
var object = { __proto__: { toString: function() { return '[object Numbers]' } }, numbers: [1, 5, 89], __proto__: { toString: function() { return '[object ArrayOfNumbers]' } } };
上面示例中的对象字面量中使用两次__proto__属性,这是不允许的。在这种情况下,将在会抛出错误: SyntaxError: Duplicate __proto__ fields are not allowed in object literals 。
SyntaxError: Duplicate __proto__ fields are not allowed in object literals
JS 约束只能用一个对象或 null 作为 __proto__ 属性的值。 任何使用原始类型(字符串,数字,布尔值)或 undefined 类型都将被忽略,并且不会更改对象的原型。
null
undefined
var objUndefined = { __proto__: undefined, }; Object.getPrototypeOf(objUndefined); // => {} var objNumber = { __proto__: 15, }; Object.getPrototypeOf(objNumber); // => {}
对象字面量使用 undefined 和 数字 15 来设置 __proto__ 值。 因为仅允许将对象或 null 用作原型,所以__proto__值将被忽略,但 objUndefined 和 objNumber 仍具有其默认原型:纯 JS 对象 {}, 。
15
objUndefined
objNumber
{}
当然,尝试使用基本类型来设置对象的原型也会很奇怪。
当对象字面具有计算结果为'proto'的字符串时 {['__proto__']:protoObj },也要小心。 以这种方式创建的属性不会更改对象的原型,而只是使用键 '__proto__' 创建一个拥有的属性
{['__proto__']:protoObj }
'__proto__'
可以使用较短的语法在对象常量中声明方法,以省略 function 关键字和 : 冒号的方式。 这被称为简写方法定义。
function
:
接着,咱们使用简写的方法来定义一些方法:
var collection = { items: [], add(item) { this.items.push(item); }, get(index) { return this.items[index]; }, }; collection.add(15); collection.add(3); collection.get(0); // => 15
一个很好的好处是,以这种方式声明的方法被命名为函数,这对于调试目的很有用。 从上面示例中执行 collection.add.name 会返回函数名称 “add”。
collection.add.name
“add”
JS 一个有趣的改进是使用 super 关键字作为从原型链访问继承的属性的能力。 看下面的例子:
super
var calc = { numbers: null, sumElements() { return this.numbers.reduce(function(a, b) { return a + b; }); }, }; var numbers = { __proto__: calc, numbers: [4, 6, 7], sumElements() { if (this.numbers == null || this.numbers.length === 0) { return 0; } return super.sumElements(); }, }; numbers.sumElements(); // => 17
calc 是 numbers 对象的原型。 在 numbers 的 sumElements方法中,可以使用 super关键字从原型访问方法:super.sumElements()
calc
numbers
sumElements
super.sumElements()
最终,super 是从对象原型链访问继承的属性的快捷方式。
在前面的示例中,可以尝试直接执行 calc.sumElements() 来调用原型,会报错。 然而,super.sumElements() 可以正确调用,因为它访问对象的原型链。并确保原型中的 sumElements() 方法使用 this.numbers 正确访问数组。
calc.sumElements()
sumElements()
this.numbers
super 存在清楚地表明继承的属性将被使用。
super 只能在对象字面量的简写方法定义内使用。
如果试图从普通方法声明{ name: function(){} } 访问它,JS 将抛出一个错误:
{ name: function(){} }
var calc = { numbers: null, sumElements() { return this.numbers.reduce(function(a, b) { return a + b; }); }, }; var numbers = { __proto__: calc, numbers: [4, 6, 7], sumElements: function() { if (this.numbers == null || this.numbers.length === 0) { return 0; } return super.sumElements(); }, }; // Throws SyntaxError: 'super' keyword unexpected here numbers.sumElements();
方法 sumElements 被定义为一个属性: sumElements: function(){…}。因为super 只能在简写方法中使用,所以在这种情况下调用它会抛出 SyntaxError: 'super' keyword unexpected here。
sumElements: function(){…}
SyntaxError: 'super' keyword unexpected here
此限制在很大程度上不影响对象字面量的声明方式。 由于语法较短,因此通常最好使用简写方法定义。
在 ES6 之前,对象初始化使用的是字面量的形式,通常是静态字符串。 要创建具有计算名称的属性,就必须使用属性访问器。
function prefix(prefStr, name) { return prefStr + '_' + name; } var object = {}; object[prefix('number', 'pi')] = 3.14; object[prefix('bool', 'false')] = false; object; // => { number_pi: 3.14, bool_false: false }
当然,这种定义属性的方式是令人愉快的。
接着使用简写方式来改完上面的例子:
function prefix(prefStr, name) { return prefStr + '_' + name; } var object = { [prefix('number', 'pi')]: 3.14, [prefix('bool', 'false')]: false, }; object; // => { number_pi: 3.14, bool_false: false }
[prefix('number','pi')]通过计算 prefix('number', 'pi') 表达式(即'number_pi')来设置属性名称。
[prefix('number','pi')]
prefix('number', 'pi')
'number_pi'
相应地,[prefix('bool', 'false')] 将第二个属性名称设置为'bool_false'。
[prefix('bool', 'false')]
'bool_false'
symbol 也可以用作计算的属性名称。 只要确保将它们包括在方括号中即可:{[Symbol('name')]:'Prop value'}
{[Symbol('name')]:'Prop value'}
例如,用特殊属性 Symbol.iterator 并迭代对象自身的属性名称。 如下示例所示:
Symbol.iterator
var object = { number1: 14, number2: 15, string1: 'hello', string2: 'world', [Symbol.iterator]: function *() { var own = Object.getOwnPropertyNames(this), prop; while(prop = own.pop()) { yield prop; } } } [...object]; // => ['number1', 'number2', 'string1', 'string2']
[Symbol.iterator]: function *() { } 定义一个属性,该属性用于迭代对象的自有属性。 展开运算符 [... object] 使用迭代器并返回自有的属性的列表
[Symbol.iterator]: function *() { }
[... object]
剩余属性允许从对象中收集在分配销毁后剩下的属性。
下面的示例在解构对象之后收集剩余的属性:
var object = { propA: 1, propB: 2, propC: 3, }; let { propA, ...restObject } = object; propA; // => 1 restObject; // => { propB: 2, propC: 3 }
展开属性允许将源对象的自有属性复制到对象文字面量中。 在此示例中,对象字面量从源对象收集到对象的其他属性:
var source = { propB: 2, propC: 3, }; var object = { propA: 1, ...source, }; object; // => { propA: 1, propB: 2, propC: 3 }
在 ES6 中,即使是作为对象字面量的相对较小的结构也得到了相当大的改进。
可以使用__proto__ 属性名称直接从初始化器设置对象的原型。 这比使用 Object.create() 更容易。
Object.create()
请注意,__proto__ 是 ES6 标准附件B的一部分,不鼓励使用。 该附件实现对于浏览器是必需的,但对于其他环境是可选的。NodeJS 4、5和6支持此功能。
现在方法声明的形式更短,因此不必输入 function 关键字。 在简化方法中,可以使用 super关 键字,该关键字可以轻松访问对象原型链中的继承属性。
如果属性名称是在运行时计算的,那么现在您可以使用计算的属性名称[expression]来初始化对象。
[expression]
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:https://dmitripavlutin.com/why-object-literals-in-javascript-are-cool/
文章每周持续更新,可以微信搜索「 大迁世界 」第一时间阅读和催更(比博客早一到两篇哟),本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,整理了很多我的文档,欢迎Star和完善,大家面试可以参照考点复习,另外关注公众号,后台回复福利,即可看到福利,你懂的。
·
The text was updated successfully, but these errors were encountered:
No branches or pull requests
在 ES6 之前,JS 中的对象字面量(也称为对象初始化器)是非常基础的。可以定义两种类型的属性:
键值对
{name1: value1}
获取器
{ get name(){..} }
和 设置器{ set name(val){..}}
的计算属性值var myObject = {
myString: 'value 1',
get myNumber() {
return this._myNumber;
},
set myNumber(value) {
this._myNumber = Number(value);
},
};
myObject.myString; // => 'value 1'
myObject.myNumber = '15';
myObject.myNumber; // => 15
JS 是一种基于原型的语言,因此一切都是对象。 在对象创建,配置和访问原型时,必须提供一种易于构造的语言。
定义一个对象并设置它的原型是一个常见的任务。最好的方式是直接在对象字面量使用一条语句来设置原型。
不幸的是,字面量的局限性不允许用一个简单的解决方案来实现这一点。必须结合使用
object.create()
和对象字面量来设置原型。我认为这种解决方案不够灵活。JS 是基于原型的,为什么要用原型创建对象那么麻烦?
幸运的是,JS 也在慢慢完善。JS 中很多令人沮丧的问题都是逐步解决的。
本文演示了 ES 6 如何解决上述问题,并使用额外的功能改进对象字面量。
1. 在对象构造上设置原型
如你所知,访问现有对象原型的一种方法是使用 getter 属性
__proto__
:myObject.__ proto__
返回myObject
的原型对象。请注意,不建议将
object.__ proto__
用作getter/setter
。替代方法应考虑使用Object.getPrototypeOf()
和Object.setPrototypeOf()
。ES6允许使用
__proto__
作为属性名,并在{__proto__:protoObject}
中设置原型。接着,咱们使用
__proto__
属性进行对象初始化,并优化上面的代码:myNumbers
对象是使用特殊属性名proto
与创建原型myProto
,这次咱们使用一条语句就创建,没有像上面还需要object.create()
这样的附加函数。如你所看,使用
__proto__
进行编码很简单,我一直喜欢简单明了的解决方案。说点脱离主题。 我觉得奇怪的是,简单灵活的解决方案需要大量的工作和设计。如果解决方案很简单,你可能会认为设计起来很容易。但是反之亦然:
如果某些东西看起来太复杂或难以使用,则可能还需要进一步的完善。
你对简单性有何看法? (请在下面随意写评论)
2.1 __proto__用法的特殊情况
即使__proto__看起来很简单,您也应该注意一些特殊情况。
在对象字面量中只能使用
__proto__一
次,否则 JS 会报错:上面示例中的对象字面量中使用两次
__proto__
属性,这是不允许的。在这种情况下,将在会抛出错误:SyntaxError: Duplicate __proto__ fields are not allowed in object literals
。JS 约束只能用一个对象或
null
作为__proto__
属性的值。 任何使用原始类型(字符串,数字,布尔值)或undefined
类型都将被忽略,并且不会更改对象的原型。对象字面量使用
undefined
和 数字15
来设置__proto__
值。 因为仅允许将对象或null
用作原型,所以__proto__
值将被忽略,但objUndefined
和objNumber
仍具有其默认原型:纯 JS 对象{}
, 。当然,尝试使用基本类型来设置对象的原型也会很奇怪。
当对象字面具有计算结果为'proto'的字符串时
{['__proto__']:protoObj }
,也要小心。 以这种方式创建的属性不会更改对象的原型,而只是使用键'__proto__'
创建一个拥有的属性简写方法定义
可以使用较短的语法在对象常量中声明方法,以省略
function
关键字和:
冒号的方式。 这被称为简写方法定义。接着,咱们使用简写的方法来定义一些方法:
一个很好的好处是,以这种方式声明的方法被命名为函数,这对于调试目的很有用。 从上面示例中执行
collection.add.name
会返回函数名称“add”
。3. super 的使用
JS 一个有趣的改进是使用
super
关键字作为从原型链访问继承的属性的能力。 看下面的例子:calc
是numbers
对象的原型。 在numbers
的sumElements
方法中,可以使用super
关键字从原型访问方法:super.sumElements()
最终,
super
是从对象原型链访问继承的属性的快捷方式。在前面的示例中,可以尝试直接执行
calc.sumElements()
来调用原型,会报错。 然而,super.sumElements()
可以正确调用,因为它访问对象的原型链。并确保原型中的sumElements()
方法使用this.numbers
正确访问数组。super
存在清楚地表明继承的属性将被使用。3.1 super 使用限制
super
只能在对象字面量的简写方法定义内使用。如果试图从普通方法声明
{ name: function(){} }
访问它,JS 将抛出一个错误:方法
sumElements
被定义为一个属性:sumElements: function(){…}
。因为super
只能在简写方法中使用,所以在这种情况下调用它会抛出SyntaxError: 'super' keyword unexpected here
。此限制在很大程度上不影响对象字面量的声明方式。 由于语法较短,因此通常最好使用简写方法定义。
4.计算属性名
在 ES6 之前,对象初始化使用的是字面量的形式,通常是静态字符串。 要创建具有计算名称的属性,就必须使用属性访问器。
当然,这种定义属性的方式是令人愉快的。
接着使用简写方式来改完上面的例子:
[prefix('number','pi')]
通过计算prefix('number', 'pi')
表达式(即'number_pi'
)来设置属性名称。相应地,
[prefix('bool', 'false')]
将第二个属性名称设置为'bool_false'
。4.1 symbol 作为属性名称
symbol 也可以用作计算的属性名称。 只要确保将它们包括在方括号中即可:
{[Symbol('name')]:'Prop value'}
例如,用特殊属性
Symbol.iterator
并迭代对象自身的属性名称。 如下示例所示:[Symbol.iterator]: function *() { }
定义一个属性,该属性用于迭代对象的自有属性。 展开运算符[... object]
使用迭代器并返回自有的属性的列表剩余和展开属性
剩余属性允许从对象中收集在分配销毁后剩下的属性。
下面的示例在解构对象之后收集剩余的属性:
展开属性允许将源对象的自有属性复制到对象文字面量中。 在此示例中,对象字面量从源对象收集到对象的其他属性:
6.总结
在 ES6 中,即使是作为对象字面量的相对较小的结构也得到了相当大的改进。
可以使用
__proto__
属性名称直接从初始化器设置对象的原型。 这比使用Object.create()
更容易。请注意,
__proto__
是 ES6 标准附件B的一部分,不鼓励使用。 该附件实现对于浏览器是必需的,但对于其他环境是可选的。NodeJS 4、5和6支持此功能。现在方法声明的形式更短,因此不必输入
function
关键字。 在简化方法中,可以使用super
关 键字,该关键字可以轻松访问对象原型链中的继承属性。如果属性名称是在运行时计算的,那么现在您可以使用计算的属性名称
[expression]
来初始化对象。代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:https://dmitripavlutin.com/why-object-literals-in-javascript-are-cool/
交流
文章每周持续更新,可以微信搜索「 大迁世界 」第一时间阅读和催更(比博客早一到两篇哟),本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,整理了很多我的文档,欢迎Star和完善,大家面试可以参照考点复习,另外关注公众号,后台回复福利,即可看到福利,你懂的。
·
The text was updated successfully, but these errors were encountered: