介绍JavaScript
中的Objects
对象的语法及相关特性。
Symbol 类型
“Symbol”值是一种表示唯一的标识符,用于创建对象的“隐藏”属性,防止他人编写代码引用自己的脚本时产生无意的冲突,导致访问或者重写这些属性。
let id = Symbol(); // id是Symbol的一个实例化对象
let id1 = Symbol("id"); // Symobol()内可以添加对对象的描述
let id2 = Symbol("id"); // 与id1一样,描述都为”id“
alert(id1 == id2); // false
如果想要打印描述,不能直接使用变量名,而需要显式调用toString()
方法。
想要在object字面量中使用Symbol,需要使用方括号。
let id = Symbol("ID");
let user = {
name: "John",
[id]: 123
};
Symbol 在 for…in 中会被跳过,在 Object.assgin 中会被复制。
Symbol 不是完全隐藏的,有内置方法可以获取。
全局 Symbol
JavaScript ES6 提出的 Symbol 存在一个全局 symbol 注册表。使用 Symbol.for(key)
可以在注册表中创建或读取 Symbol。
该调用会检查全局注册表,如果有一个描述为 key
的 Symbol,则返回该 Symbol,否则将创建一个新 Symbol(Symbol(key)
),并通过给定的 key
将其存储在注册表中。
let id = Symbol.for("id"); // 如该 Symbol 不存在,则创建它
let idAgain = Symbol.for("id"); // 再次读取
alert( id === idAgain ); // 两者相同
反向调用
Symbol.for(key)
使用名称返回一个symbol变量。
Symbol.keyFor(sym)
使用symbol变量返回一个名称。
系统 Symbol
JavaScript 内部还留有一些系统Symbol,我们可以使用它们来微调对象的各个方面。
// 暂略
对象方法
创建对象方法的几种方式:
// 1. 直接赋值
user.sayHi = function() {
alert("Hello!");
};
// 2. 先声明后赋值
function sayHi() {
alert("Hello!");
};
user.sayHi = sayHi;
// 3. 对象内赋值
let user = {
sayHi: function() {
alert("Hello");
}
};
// 4. 方法简写
let user = {
sayHi() {
alert("Hello");
}
};
一般来说3与4较为正常,而4在绝大部分情况下都与3没有区别。故推荐使用第4种方法。
“this”
JavaScript中的“this
”关键字与其他大多数编程语言不太相同。
this可以用于任何函数而不会报语法错误。
function sayHi() {
alert( this.name );
}
因为this
在运行时才求值,其值由调用该函数的“.”点之前的对象决定。
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
user.f = sayHi;
admin.f = sayHi;
// 函数在两个对象之间共用
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)
admin['f'](); // Admin(使用方括号亦可)
在没有任何对象的情况下,严格模式的this
等于undefined
,这时候如果访问属性则会出错;非严格模式的this
将会是全局对象,即浏览器窗口。
我们不应该在没有对象的情况下调用this,这一般是错误的。
其他:
- 箭头函数没有
this
,在其内部访问会取得来自外部的this
值,所以不适合使用箭头函数定义对象方法。 - 更多细节在遇到问题时请善用搜索引擎解决。
- …
原始值转换
本小节以下内容从原文摘抄。(因为我不知道用不用的上)
对象到原始值的转换,是由许多内置函数和操作符自动调用的,这些函数使用一个原始值作为返回值的。
它有三种类型(暗示):
- “
string
”(对于 alert 和其他字符串转换)- “
number
”(对于 maths)- “
default
”(少数操作)规范明确描述了哪个操作符使用哪个暗示。极少数操作者“不知道期望什么”并使用 “
default
” 暗示。通常对于内置对象,"default
" 暗示的处理方式与 “number
” 相同,因此在实践中最后两个通常合并在一起。
转换算法:
- 调用
obj[Symbol.toPrimitive](hint)
如果这个方法存在的话,- 否则如果暗示是 “
string
”
- 尝试
obj.toString()
和obj.valueOf()
,无论哪个存在。- 否则,如果暗示 “number” 或者 “default”
尝试obj.valueOf()
和obj.toString()
,无论哪个存在。在实践中,为了记录或调试目的,仅实现
obj.toString()
作为“全捕获”方法通常就够了,这样所有转换都能返回一种“人类可读”的对象表达形式。
构造函数
JavaScript
早期时候虽然没有“类”的概念,但我们可以借助构造函数来达到我们相似的效果,实现对象结构的复用。
在现代JavaScript中已经有class语法了,其本质仍然是一种函数。
构造函数在技术上与一般的函数没有区别,但我们约定:
- 大写字母开头
- 只能使用
new
操作符执行
例子:
function User(name) {
// this = {};(隐式创建)
this.name = name;
this.isAdmin = false;
this.sayHi = new function() {
alert("Hello");
}; // <-- 不要漏了这个分号
// return this;(隐式返回)
}
let Haze = new User("Haze");
// 结构等价于
let user = {
name: "Haze",
isAdmin: false,
sayHi: new function() {
alert("hello");
}
};
new 操作符
上面的例子中,隐式创建空对象与隐式返回this
都是new
的作用。
在函数内部,我们可以使用new.target
属性来检查该函数被调用时是否使用了new
操作符:
- 带
new
,返回该函数(即function Func { ... }
) - 不带
new
,则返回undefined
由此可以延伸出一个小trick(但不推荐使用,因为不利于阅读):
function User(name) {
if (!new.target) { // 如果没有运行 new
return new User(name); // 自动补上 new
}
this.name = name;
}
let john = User("John");
let john = new User("John"); // 相同
对于以下对象,我们建议使用其他方法代替使用 new
创建对象:
符号 | 替代 |
---|---|
{} | new Object() |
“” | new String() |
0 | new Number() |
false | new Boolean() |
[] | new Array() |
/()/ | new RegExp() |
function (){} | new Function() |
构造函数 return 规则
一般来说都让它隐式返回this
,如果显式return
,则有以下规则:
- 如果返回一个对象,则返回该对象,不返回this
- 如果返回其他东西,则忽略,仍然返回this
其他
-
JavaScript 为我们内置了许多常用的对象的构造函数,如日期
Date
、集合Set
以及数组Array
。 -
当构造函数没有参数时,语法上是支持省略括号的:
let user = new User; // 等价于 new User();
但从代码风格角度上并不推荐这么做。
更多内容
点击返回个人笔记导航?
访问我的github笔记⭐