4、JavaScript的Object类型

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去找*/

原型链

原型链结构图.png

原型链上的属性增删改查:增删改都需要是本身属性的增删改,儿子不能增删改父亲的,父亲可以增删改自己的。

对象都有原型,绝大多数(使用Object.create(null)没有原型)对象最终都会继承Object.prototype。

缺点:过多的继承了父类没用的属性。

关于 prototype 和 _proto_

Javascript中所有的对象都是Object的实例,并继承Object.prototype的属性和方法,也就是说Object.prototype是所有对象的爸爸。(个人感觉搞清楚这一点很重要)。

1、当定义一个函数的时候,这个函数会经过浏览器处理,会得到一个prototype属性。prototype里面有两个属性:constructor和_proto_。

--constructor这个属性就指向了函数本身。

--这个_proto指向的就是构造函数的prototype

--Object.prototype是所有函数的爹,当你声明一个函数的时候也就是相当于对Object的实例化。

prototype

2、当构造函数被实例化,他的实例b的_proto_就指向了这个构造函数B的prototype。

所以b._proto_==B.prototype

当b需要访问name时,先从自身的属性开始找,找不到就去_proto找,_proto指向了B的prototype中有name,所以访问成功,实现了继承。

__proto__和prototype

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.definePropertyObject.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);          //解析,字符串-->对象
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342