Object对象
对象的创建
对象字面量
var obj = {}
构造函数
//通过Object()是系统提供的构造函数
var obj = new Object();
//系统提供的构造函数还有Array(),Number()...
//自定义构造函数
function Car(color){
this.color = color;
this.name = "BMW";
this.gas = "300"
this.run = function(){
this.gas--;
}
}
var car = new Car("red");//创建对象,相当于工厂造对象,有基本的属性,创建的对象都是独立的。
构造函数内部原理:
在函数体最前面隐式加上 this = { }
执行this.xxx = xxx;
隐式返回this(如果有自定义的不是引用类型,字符串等会被this代替,真正返回的是this)
function Person(name,height){
//var this = {};隐式添加
this.name = name;
this.height = height;
this.say = function(){
console.log("my name is"+this.name);
}
return 100;
//return this;隐式添加
}
var person = new Person("小明","179");//当new了以后会进行隐式添加两行代码
console.log(person);//依然输出整个对象,而不是100
ES6中的class
上面的代码等价于
class Person{
constructor(name,height){
//new时会执行constructor的代码
this.name = name;
this.height = height;
this.say = function(){
console.log("my name is"+this.name);
}
console.log(123);//当new的时候会打印
}
}
var person = new Person("小明","179");
console.log(person);
包装类
原始值(六个原始值)不能拥有属性和方法,当硬要给原始值添加属性得时候会隐式执行new Number(4).len=3;
然后新建的Number对象就会被删除。
六个原始值:number,boolean,string,null,undefined,symbol
引用类型:Object,Array,Function,Date...
var num = 4;
num.len = 3;
//隐式执行new Number(4).len = 3;然后删除
console.log(num.len);//对象已经删除,但访问时会再一次隐式执行new Number(4).len,这是一个新的Number对象,里面并没有len属性,所以会打印undefine
能进行这样子操作的有Number,Boolean,String。
String、Boolean、Number类型的数据之所有会有可调用的方法,是因为在他的原型链上定义了那些可用的方法
原型
原型是函数上的一个属性,他定义了构造函数制造出来的对象的公有祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法,原型也是对象。
__proto__是对象访问原型的属性,在实例中存在。
Person.prototype.FirstName = "邹";//prototype是function对象的属性,他的对象引用不可以访问
Person.prototype.say = function(){
console.log("I am father!");
}
function Person(){
this.say = function(){
console.log("I am son!");
}
}
var p1 = new Person();
console.log(p1);
console.log(p1.__proto__);//__proto__是隐式属性,对象的引用访问原型。
/*
直接打印p1的时候显示为空对象,因为Person对象没有FirstName属性。但是访问p1.FirstName可以打印出“邹”。原因是Person.prototype作为Person的父类,Person对象继承了父类的属性和方法。Person对象的所有对象都可以继承父类的属性和方法。这一点跟java的继承思想基本一样。
*/
console.log(p1 .say());
/*
this.say = function(){...}相当于java继承中的重写。
*/
图解:
原型的应用
把对象共性的东西提取到原型里面,减少代码的冗余。
Person.prototype.Name = "宝马";
Person.prototype.run = function(){
console.log("run run run!!!");
}
function Car(color){
this.color = color;
}
var car = new Car("red");
//此时car拥有Name属性和run方法。
name属性和run方法是共有的,可以提取共有属性到原型。
原型对象的另一种写法:
Person.prototype={
constructor:Person,
Name:"宝马",
run : function(){
console.log("run run run!!!");
}
/* 这种写法是把整个prototype对象的引用更换了,使用点赋值只是把prototype对象属性赋新值。*/
}
function Car(color){
this.color = color;
}
var car = new Car("red");
/*__proto__是javascript内部隐式定义的属性,当使用构造函数生成对象的时候,隐式执行的var this = {}其实里面有东西:*/
var this = {
__proto__:obj.prototype
}
/*对象查找属性的时候如果自身没有,就会根据__proto__指向的obj.prototype去找*/
原型链
原型链上的属性增删改查:增删改都需要是本身属性的增删改,儿子不能增删改父亲的,父亲可以增删改自己的。
对象都有原型,绝大多数(使用Object.create(null)没有原型)对象最终都会继承Object.prototype。
缺点:过多的继承了父类没用的属性。
关于 prototype 和 _proto_
Javascript中所有的对象都是Object的实例,并继承Object.prototype的属性和方法,也就是说Object.prototype是所有对象的爸爸。(个人感觉搞清楚这一点很重要)。
1、当定义一个函数的时候,这个函数会经过浏览器处理,会得到一个prototype属性。prototype里面有两个属性:constructor和_proto_。
--constructor这个属性就指向了函数本身。
--这个_proto指向的就是构造函数的prototype
--Object.prototype是所有函数的爹,当你声明一个函数的时候也就是相当于对Object的实例化。
2、当构造函数被实例化,他的实例b的_proto_就指向了这个构造函数B的prototype。
所以b._proto_==B.prototype
当b需要访问name时,先从自身的属性开始找,找不到就去_proto找,_proto指向了B的prototype中有name,所以访问成功,实现了继承。
Object上的方法
方法名 | 用处 |
---|---|
Object.create(prototype,[propertiesObject]) | 用指定的原型对象及其属性去创建一个新的对象 |
Object.assign(target,source1,source2...) | 用于对象的合并,把source的可枚举属性合并到target上。 |
Object.defineProperties(obj,props) | 在一个对象上定义或修改属性,并返回该对象。 |
Object.defineProperty(obj,prop,descriptor) | 在一个对象上定义或修改一个对象的属性并返回这个对象。 |
Object.keys(obj) | 返回一个由一个给定对象的自身可枚举属性组成的数组。 var obj ={ a:1, b:2};Object.keys(obj) 打印[a,b] |
Object.values(obj) | 方法返回一个给定对象自己的所有可枚举属性值的数组 |
Object.entries(obj) | 返回一个给定对象自身可枚举属性的键值对数组👇 |
obj.hasOwnProperty(“prop”) | 判断对象自身属性中是否具有指定的属性。 (不包括原型链) |
Object.getOwnPropertyNames(obj) | 返回一个由指定对象的所有自身属性的属性名组成的数组。 |
Obj.isPrototypeOf(obj) | 判断一个对象是否存在于另一个对象的原型链上。 |
Object.setPrototypeOf(obj,prototype) | 设置对象的原型对象 (性能消耗很大。) |
Object.is(value1,value2) | 判断两个值是否相同。相当于value1===value2 |
Object.freeze(obj) | 冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。 |
Object.isFrozen(obj) | 判断一个对象是否被冻结 |
Object.preventExtensions() | 对象不能再添加新的属性。可修改,删除现有属性,不能添加新属性。 |
Object.assign
把源对象(source)的可枚举属性拷贝到目标对象,原来的相同属性会被覆盖掉。
const target = { a: 1, b: 2 };
const source1 = { b: 4, c: 5 };
const source2 = { c: 9, d: 8 };
const returnedTarget = Object.assign(target, source1, source2);
console.log(target);//Object { a: 1, b: 4, c: 9, d: 8 }
console.log(returnedTarget);//Object { a: 1, b: 4, c: 9, d: 8 }
1、他的所有参数都是对象,如果不是对象会转换为对象,如果首参数是null和undefind不能转换成对象,所以会报错。
2、source除了是对象、字符串、数组以外的其他类型,不会产生影响。字符串会以数组形式进行操作。
3、assign是浅拷贝,如果source属性值是引用值,那么拷贝的是这个对象的引用
4、assign常用于:克隆对象、合并多个对象、为属性指定默认值。
Object.create
根据第一个参数(必须)为原型创建一个对象,并且这个对象拥有第二个参数(可选)的可枚举属性。
//var o = Object.create(null); 创建一个没有prototype的对象
var obj = {name:"APPLE"}
var a = Object.create(obj,{
"a":{value :1,congigurable :false,enumerable :true,writable:true},
"b":{value :2,congigurable :false,enumerable :true,writable:true},
"c":{value :3,congigurable :false,enumerable :true,writable:true}
})//创建一个a对象,他的原型是obj,它有a,b,c三个自身属性。
console.log(a);//a.__proto__.name="APPLE"
1、undefined ,null没有原型。
2、创建的对象以第一个对象为原型,创造出来的对象 通过_proto_访问obj。
3、第二个参数是可选参数,表示创建的对象拥有的自身属性。
value:对象的属性值。
congigurable:能否修改或删除这个属性名,默认true
enumerable:此属性是否为可枚举(即能否被for-in遍历),默认true
writable:此属性值是否可以被修改,默认true
Object.defineProperty和Object.defineProperties
通过定义属性描述对象,来定义或修改一个属性,然后返回修改后的对象.
{
value: 123,//属性的值,数据描述符
writable: false,//可写,数据描述符
enumerable: true,//可枚举
configurable: false,//可配置性
get: undefined,//获取值,数据存取符
set: undefined//设置值,数据存取符
}//属性描述对象的一个实例,数据描述符和数据存取符不可一起使用。
var obj = {
a:10
}
Object.defineProperty(obj, "attri", {
value: 123,
writable: false,
enumerable: true,
configurable: false
})//为obj对象设置attri属性的描述对象。
//如果要设置多个属性,使用Object.defineProperties
let value = 123;
Object.defineProperty(obj, "prop", {
get() {
console.log('get');
return value;
},
set(newValue) {
console.log('set');
value= newValue;
},
enumerable: true,
configurable: false
});
obj.prop;// 打印 get
obj.prop = 234; // 打印 set
第一个参数是要添加属性的对象。
第二个是字符串形式的属性名,如果属性已存在则更新此属性。
第三个是属性的描述对象。
数据描述符和数据存取符不可一起使用。
defineProperty和defineProperties都有性能损耗不建议大量使用
Object.keys、Object.values、Object.entries
返回一个由一个给定对象的自身可枚举属性组成的数组。
var obj = {
a:10,
b:20
}
Object.defineProperty(obj, "attri", {
value: 123,
enumerable: false //不可枚举
})
console.log(Object.keys(obj));//["a","b"]
和Object.values(obj)相对应,keys返回的是属性名数组,values返回属性值数组。
Object.entries(obj),返回的是二维数组,数组里面是["属性名",属性值]
Object.getOwnPropertyNames(obj)则可以获取到所有属性(包括不可枚举类型)
obj.hasOwnProperty(“prop”)
判断对象自身属性中是否具有指定的属性。(不包括原型链上的属性)
function F(name,age){
this.name=name;
this.age=age;
}
F.prototype.color = "red"
let f = new F("zou",18)
console.log(f.color);//red
console.log(f.hasOwnProperty("color"));//false
对象枚举
for-in循环 和 hasOwnProperty
for-in用于遍历对象的属性
hasOwnProperty用于判断时候为自己的属性
var obj = {
name:"eee",
age:100,
height:176,
__proto__:{
firstName:"zpi";
}
}
for (var i in obj){
if(obj.hasOwnProperty(i)){
/* obj.hasOwnProperty(i)用于判断i这个属性是否属于obj,返回布尔值。如果没有这个判断,原型继承的属性也会被打印出来 */
console.log(obj[i]);
/*每循环一圈都会把属性名的字符串形式赋值给i,所以不能用.来访问对象属性*/
}
}
关于obj[i]访问属性:访问对象的方法有两种。一是obj.name,二是obj['name'],第一种最终还是会变成第二种的方式去执行。
obj['name'] 中括号里面必须是字符串形式。这样子的话我们有时候可以利用字符串拼接的方式去访问对象。
for-of循环
循环可迭代(普通对象不可迭代)的数据。
var arr = {
a:1,
b:2,
c:3
}
for(var i of arr){
console.log(i);
}
//Uncaught TypeError: arr is not iterable
可迭代的数据:数组,字符串,Map,Set,arguments(类数组),Typed Arrays,Generators。
var arr = [
{ name:'nick', age:18 },
{ name:'freddy', age:24 },
{ name:'mike', age:26 },
{ name:'james', age:34 }
];
for(var i of arr){
console.log(i);//打印的是数组元素
}
for(var i in arr){
console.log(i);//打印的是索引
}
for-in遍历的是索引,for-of遍历的是值。
in操作符
用于判断属性时候存在于这个对象。(与hasOwnProperty不同)
var obj = {
name:"eee",
age:100,
height:176,
__proto__:{
firstName:"zou"
}
}
console.log('firstName' in obj);//true
console.log('lastName' in obj);//false
必须是字符串形式,如果该属性能被obj访问则返回true。
也就是说,再obj和obj的原型链上的属性用in都返回true。
(使用的概率极低)
instanceof 操作符
文档说:a instanceof A 用于判断a是否为A的实例。
更准确的说: a instanceof A 用于判断a的原型链上是否有A。
function A(){}
function B(){}
var a = new A();
var b = new B();
console.log(a instanceof A);//a是A的实例,返回true
console.log(a instanceof B);//a不是B的实例,返回false
console.log(a instanceof Object);//a的原型链上有Object,返回true
console.log([] instanceof Array);//[]的原型链上有Array,返回true
json对象
JSON是一种传输数据的格式。本质上是对象,但是用途有所区别。对象供本地使用,json用于传输数据。
var obj={
age:10,
name:"mary"
}
var a = JSON.stringify(obj); //字符串化,对象-->字符串
var b = JSON.parse(a); //解析,字符串-->对象