一、原始值和对象引用
基本类型: undefined ,null , 布尔值(Boolean) , 字符串(String) , 数值(Number)
赋值时:给的是实实在在的数据值 ,赋值后二者只是值一样,不会相互影响;
注意:字符串对象的类型是对象,不是字符串。
如下图演示//例子1.0.0 字符串赋值 var a = 100;var b = a; b = 200; console.log(a) // 100 console.log(b) // 200 赋值后修改互不干预 ---------------------------------------------- //例子1.0.1 字符串对象比较 var a = 'foo';var b = 'foo'; a == b; // true a === b; // true var c = new String('foo'); var d = new String('foo'); var e = String('foo'); var f = String('foo'); c == d // false c === d //false 因为a和b是类型对象,引用不同的对象 c == 'foo' // true 因为在比较前 a.toString()转换成了 字符串 此时就是字符串和字符串比较 e === a //true e === f //true c == f //false c === f //false # 不使用new时返回的是一个基本类型字符串,效果与使用'hello'字面量创建是一样的 # 使用new 用构造函数返回字符串本身的类型是对象,此时同样需要: 当且仅当它们引用同一个基对象时,它们才相等
引用类型: 统称为Object类型,细分的话,有:Object类型,Array类型,Function类型等。
- 赋值时:当且仅当它们引用同一个基对象时,它们才相等。 也就是仅仅赋值了引用值,所以新旧数据会互相影响,因为本质上还是同一个数据对象;
想得到一个副本,遍历赋值对象的每个属性或元素
//例子1.0.2 引用类型赋值 var a = {"age":20};var b = a; b.age = 21; console.log(a.age) //21 console.log(b.age) //21 var c = ["1","3","5"];var d = c; d.push("6"); console.log(c) // ["1", "3", "5", "6"] console.log(d) // ["1", "3", "5", "6”]
二、对象常见的用法:创建 设置 查找 删除 检测 枚举
1. 创建对象的方法:
(1)对象字面量的方式
var newObj1 = {x:1,y:2};
(2)使用new关键字,如:new Object()
var newObj2 = new Object();
newObj2.x = 1;
newObj2.printKey = function(){
return this.x;
};
(3)构造函数
function Person(num){
this.x = num;
this.printKey = function(){
return this.x;
}
}
var newObj3 = new Person(1);
(4)工厂方式创建
function Factory(num){
var obj = new Object();
obj.x = num;
obj.printKey = function(){
return obj.x;
}
return obj;
}
var newObj4 = new Factory(1);
(5)原型方式创建
function Person(){}
Person.prototype.name = "lisi";
Person.prototype.say = function(){
alert(this.name);
};
var newObj5 = new Person();
(6)Object.create()函数来创建
创建一个对象并指定对象原型
语法:Object.create(proto[, propertiesObject]);
参数一:指定对象的原型对象。
参数二:对象的属性描述符;没有默认undefined 添加到新创建对象的不可枚举
value: 属性的默认值, 默认为undefined
congigurable: 能否使用delete、能否修改属性特性、或能否修改访问器属性、false为不可重新定义,默认值为true
enumberable: 可枚举性,对象属性能否通过for-in 循环,默认为true
writable: 对象属性是否可修改,默认为true,可修改,设置false可理解为常量不可修改
var o1=Object.create({x:1,y:2});
//创建了一个原型对象为{x: 1, y: 2}的对象o1; 打印o1.__proto__ 》》{x: 1, y: 2}
var o2=Object.create(null);
//创建一个原型为null的空对象;o2不继承任何属性和方法;
var o3 = Object.create(Object.prototype);
//o3和{}和new Object()一样;
var o4 = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: {
writable:true,
configurable:true,
value: "hello"
},
// bar会成为所创建对象的访问器属性
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) {
console.log("Setting `o.bar` to", value);
}
}
});
----------------------------------------------
// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
var o = Object.create({}, { p: { value: 42 } })
o.p = 24; //设置p的值
o.p; //42 依然是42 。因为:省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的
## 基于属性描述符的补充
# Object.getOwnpropertyDescriptor()
//获得对象自身属性的属性描述符
# Object.getPrototypeOf()
//查询原型
# Object.defineProperty()
//修改或创建单个属性的描述符
# Object.defineProperties()
//修改或创建多个个属性的描述符
Object.getOwnPropertyDescriptor(o4,"foo");//{value: "hello", writable: true, enumerable: false, configurable: true}
Object.getOwnPropertyDescriptor(o4,"toString");//undefined; 继承属性非自身属性;
----------------------------------------------
var o5={a:9};
Object.defineProperty(o5,"x",{value:1,writable: true, enumerable: false, configurable: true});//添加一个不可枚举的数据属性x,并赋值为1;
o5.x;//1;
Object.keys(o5);//可枚举数组为["a"] ;x不可枚举
Object.defineProperty(o5,"x",{writable:false});//x变成只读;
o5.x = 2;//试图修改x的值
o5.x;//1 依然是1;
Object.defineProperty(o5,"x",{value:2});//能修改
Object.defineProperty(o5,"b",{get:function(){
return this.a;
}})//新增b为存取属性
o5.b //9;
2. 设置查找:
data.aaa 可写成 data[aaa] 前面认定是字符串,后者可以是表达式 ; 可读取可设值。
var data = {key1:"peo",key2:"12"};
console.log(data.key1); //peo
console.log(data['key'+1]); //peo
data.key1 = 'jerry'; //{key1: "jerry", key2: "12"}
data['key'+2] = 'student'; //{key1: "jerry", key2: "student"}
3. 删除delete:
只能删除自有属性 不能删除继承属性(要删除继承属性必须从定义这个属性的原型对象上删除它,而且这会影响多有继承自这个原型的对象)
var data = {key1:"peo",key2:"12"};
delete data.key2; //返回true 且 data》{key1:"peo"}
delete data.name; //返回true 要删除的本身就不存在
4. 检测属性:
in运算符、hasOwnPreperty()、propertyEnumerable()
//in运算符 >> 检测自身或继承中是否有该属性
var data = {x:1};
"x" in data; //true;
"y" in data; //false;
"toString" in data; //true: data继承toString属性
//hasOwnProperty() >> 检测自身属性中是否有该属性
data.hasOwnProperty("x"); //true
data.hasOwnProperty("y"); //false
data.hasOwnProperty("toString"); //false :只检测自身属性,toString是继承来的属性
//propertyIsEnumerable() >> 检测自身属性中是否有该属性且该属性是可枚举的
5.枚举(enumerate):
for/in循环 遍历对象中所有可枚举的属性(包含自身属性和继承的属性)
propertyIsEnumerable() 检测属性可否枚举
var o = {x:1,y:2,z:3}; //可枚举的自有属性
o.propertyEnumerable("toString");//false,不可枚举
for(p in o){
console.log(p);//输出x,y,z;不输出toString
}
6. 属性的getter和setter
对象由一组名字、值组成。值可以是普通数据属性,也可以是个方法;又getter和setter定义的属性称作“存取器属性”;
如果同时具有getter和setter方法,那么它是个读/写属性;
如果只有getter方法,它是个只读属性;
如果只有setter方法,它是个只写属性,读取只写属性总返回undefined
var p = {
x:1.0,
y:1.2, //x、y是普通可读写的数据属性
//r是可读写的存取器属性,它有getter和setter ;
//另外注意:这个函数定义没有使用function关键字,而是使用了get或set。
get r(){return Math.sqrt(this.x*this.x+this.y*this.y);},
set r(newValue){
var oldValue = Math.sqrt(this.x*this.x+this.y*this.y);
var ratio = newValue/oldValue;
this.x *= ratio;
this.y *= ratio;
},
//theta是只读的存取器属性,只有getter方法
get theta(){return Math.atan2(this.y,this.x);}
}
三、对象的三个属性:原型、类、可拓展性
每个对象都有原型prototype、类class、可拓展性extensible attrbute
原型属性:对象的原型属性是用来继承的;
Object.getPrototypeOf();可以查询它的原型;
检测一个对象是否是另一个对象的原型(isPrototypeOf 和instanceof非常类似)
A.isPrototypeOf(B) //A对象是否在B的原型链上
A instanceof B // A是不是B的实例;B构造函数的prototype对象是否在A的原型链上
var p = {x:1};
var o = Object.create(p);//创建一个原型指向p的对象o;
p.isPrototypeOf(o); //true:p对象在o的原型链上
Object.prototype.isPrototypeOf(o); //true:p继承自Object.prototype;
-----------------------
var d = new Date();//通过Date()构造函数创建一个对象
d instanceof Date; //true;d是由Date()创建的
d instanceof Object;//true;所有的对象都是Object的实例
var a = [1,2,3];
a instanceof Array;//true;
a instanceof Object;//true;
function Foo(name, age){this.name = name;}
var f = new Foo('jerry');
f instanceof Foo //true f属于Foo这个构造函数的实例化
f instanceof Object//true 所有的对象都是Object的实例
类属性:对象的类属性是一个字符串,用以表示对象的类型信息;可调用对象的toString()方法查询
function classof(o){
if(o === null) return "Null";
if(o === undefined) return "Undefined";
return Object.prototype.toString.call(o).slice(8,-1)
}
classof([])//"Array"
classof({})//"Object"
classof(function(){}) //"Function"
function f(){}; classof(new f())//"Object"
classof(/\d/)//"Regexp"
classof(window)//"Window"这个客户端宿主对象
可扩展性:是否可以给对象添加新属性
- Object.isExtensible() //判断该对象是否可扩展。
- Object.preventExtensions() //阻止向对象添加新的属性;将对象转为不可扩展的,一旦转为不可扩展 无法转回可扩展
- Object.seal() //阻止向指定对象添加新属性或者删除现有属性;已有的可写属性依然可以设置。
- Object.freeze() //将指定对象设置为不可改变;更严格的锁定,
- Object.isSealed() //检查当前对象是否为封闭;
- Object.isFrozen() //检查当前对象是否为冻结;
序列化对象:
- JSON.stringify() //把对象转字符串
- JSON.parse() //json字符串转json
四、Object 原生方法
分成两类: 原型方法和 静态函数
- Object 原型方法定义在 Object.prototype 对象上,所有 Object 实例对象都会继承这些方法。
- Object 静态函数就是定义在 Object 对象上的方法,通过 Object 直接调用,不需要实例继承。
原型方法:
方法 | 描述 |
---|---|
hasOwnProperty() | 检测自身属性中是否有该属性 |
isPrototypeOf() | 检测当前对象是不是指定对象的原型 |
propertyIsEnumerable() | 检测自身属性中是否有该属性且该属性是可枚举的 |
toString() | 返回该对象的字符串表示 |
toLocaleString() | 返回该对象的一个本地化的字符串表示 |
valueOf() | 返回该对象的原始值 |
Object.prototype.toString.call(x).slice(8,-1);
//调用这个方法 截取字符串的第8位到倒数第2位 是读取它的属性
----------------------
const num = 2333333;
num.toLocaleString(); // 2,333,333
num.toLocaleString('zh', { style: 'currency', currency: 'CNY' }); //¥2,333,333.00
num.toLocaleString('zh', { style: 'currency', currency: 'cny', currencyDisplay: 'code' }); //CNY2,333,333.00
num.toLocaleString('zh', { style: 'currency', currency: 'cny', currencyDisplay: 'name' }); //2,333,333.00人民币
静态方法:
方法 | 说明 |
---|---|
对象原型 | |
Object.create() | 使用指定原型及属性创建一个新的对象 |
Object.getPrototypeOf() | 查询原型获取对象的 Prototype 对象 |
遍历对象 | |
Object.keys() | 以数组形式返回参数对象包含的可枚举的私有属性的key名; |
Object.values() | 以数组形式返回参数对象包含的可枚举的私有属性的value |
Object.getOwnPropertyNames | 以数组形式返回参数对象包含的私有属性名; |
对象属性 | |
Object.defineProperty() | 创建或配置指定对象的某个属性 |
Object.defineProperties() | 创建或配置指定对象的一个或多个属性 |
Object.getOwnpropertyDescriptor() | 获得对象自身属性的属性描述符 |
对象状态控制 | |
Object.preventExtensions() | 阻止向对象添加新的属性;将对象转为不可扩展的,一旦转为不可扩展 无法转回可扩展 |
Object.isExtensible() | 判断该对象是否可扩展。 |
Object.seal() | 阻止向指定对象添加新属性或者删除现有属性;已有的可写属性依然可以设置。 |
Object.freeze() | 将指定对象设置为不可改变;冻结一个对象。更严格的锁定。 |
Object.isSealed() | 检查当前对象是否为封闭; |
Object.isFrozen() | 检查当前对象是否为冻结; |
五、Es6-对象的扩展
1.简洁表示法
function f(x, y) {
return {
// 等同于hello: function ()...
hello() { console.log('我的名字是', this.name); },
//等同于 x: x, y: y
x, y
};
}
2.属性名表达式
Es5在{}里面key值只能是字面量,
Es6可以在{}里面用[]写表达式。
let propKey = 'foo';
var obj = {
//Es5只支持字面量
foo: true,
//用[]写表达式
[propKey]: true,
['a' + 'bc']: 123,
['h' + 'ello']() {
return 'hi';
}
};
3.方法的 name 属性
- 普通函数,name属性返回:函数名
- getter|setter函数,name属性返回:get|set 加 函数名
- bind方法创造的函数,name属性返回:bound 加 原函数名
- Function构造函数创造的函数,name属性返回:anonymous
- 对象的方法是Symbol值,name属性返回:Symbol值的描述
4.属性的可枚举性和遍历
可枚举性
目前,有四个操作会忽略enumerable为false的属性。
for...in循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。
属性的遍历
ES6 一共有 5 种方法可以遍历对象的属性。
(1) for...in
遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
(2) Object.keys(obj)
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
(3) Object.getOwnPropertyNames(obj)
返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
(4) Object.getOwnPropertySymbols(obj)
返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5) Reflect.ownKeys(obj)
返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
首先遍历所有数值键,按照数值升序排列。
其次遍历所有字符串键,按照加入时间升序排列。
最后遍历所有 Symbol 键,按照加入时间升序排列。
5.super 关键字
作用: 用于访问父对象上的函数。
详解:super可以用在类的继承中,或者对象字面量中,super指代了整个prototype或者__proto__指向的对象。
语法:
super([arguments]); // 访问父对象上的构造函数
super.functionOnParent([arguments]); // 访问对象上的方法
6.对象的扩展运算符: ...
7.链判断运算符: ?.
//Es5
const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';
//Es6
const firstName = message?.body?.user?.firstName || 'default';
const fooValue = myForm.querySelector('input[name=foo]')?.value
8.Null 判断运算符: ??
只有运算符左侧的值为null
或undefined
时,才会返回右侧的值
const animationDuration = response.settings.animationDuration ?? 300;
六、Es6-对象的新增方法
1.Object.is()
严格等于,不会做隐式类型转换, 其行为与===基本一致,不过有两处不同:
- +0不等于-0**
- NaN等于自身
2.Object.assign()
基础:用于对象的合并,将源对象source的所有可枚举属性,复制到目标对象target
注意:
(1) 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。
(2) 属于浅拷贝
常用于:
## 合并 替换值
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
-----------------
## 如果只有一个参数,`Object.assign`会直接返回该参数
typeof Object.assign(2) // "object"
## 由于`undefined`和`null`无法转成对象,所以如果它们作为参数,就会报错。
Object.assign(undefined) // 报错
Object.assign(null) // 报错
3.Object.getOwnPropertyDescriptors()
主要是为了解决Object.assign()
无法正确拷贝get
属性和set
属性的问题。
ES5 的Object.getOwnPropertyDescriptor()
方法会返回某个对象属性的描述对象;
ES2017 引入了Object.getOwnPropertyDescriptors()
方法,返回指定对象所有自身属性(非继承属性)的描述对象
该方法的实现:
function getOwnPropertyDescriptors(obj) {
const result = {};
for (let key of Reflect.ownKeys(obj)) {
result[key] = Object.getOwnPropertyDescriptor(obj, key);
}
return result;
}
4.Object.setPrototypeOf(),Object.getPrototypeOf()
__proto__本质上是一个内部属性,所以从语义的角度,还是从兼容性的角度,都不要使用这个属性,而是使用下面操作代替:Object.setPrototypeOf()
(写操作)、Object.getPrototypeOf()
(读操作)、Object.create()
(生成操作)
Object.setPrototypeOf(object, prototype) 写入
// 用法
const o = Object.setPrototypeOf({}, null);
//等同于
function setPrototypeOf(obj, proto) {
obj.__proto__ = proto;
return obj;
}
Object.getPrototypeOf(obj) 读取
如果参数不是对象,会被自动转为对象
5.Object.keys(),Object.values(),Object.entries()
ES2017引入了跟Object.keys
配套的Object.values
和Object.entries
,作为遍历一个对象的补充手段,供for...of
循环使用
var obj = {name:"tom",age:12,sex:"man"};
Object.keys(obj);//["name", "age", "sex"] 获取对象的key组合数组
for (let key of keys(obj)) {
console.log(key); // "name", "age", "sex"
}
Object.values(obj)//["tom", 12, "man"] 获取对象的value组合数组
for (let value of values(obj)) {
console.log(value); // "tom", 12, "man"
}
Object.entries(obj)//
[["name", "tom"],["age", 12], ["sex", "man"]]
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ["name", "tom"],["age", 12], ["sex", "man"]
}
6. Object.fromEntries()
Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。
主要目的: 是将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象。
// 例一
const entries = new Map([
['foo', 'bar'],
['baz', 42]
]);
Object.fromEntries(entries)
// { foo: "bar", baz: 42 }
// 例二
const map = new Map().set('foo', true).set('bar', false);
Object.fromEntries(map)
// { foo: true, bar: false }
mark一下 仅供参考 欢迎更正补充 end
参考资料:
- 《javascript权威指南》
- 阮一峰:https://es6.ruanyifeng.com/#d...
- Object.create:https://developer.mozilla.org...
- 浅谈JS对象添加getter与setter的5种方法:https://www.jb51.net/article/...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。