> 文章列表 > JavaScript【五】JavaScript中的对象

JavaScript【五】JavaScript中的对象

JavaScript【五】JavaScript中的对象

文章目录

  • 🌟前言
  • 🌟对象
  • 🌟声明对象:
    • 🌟隐式创建对象:
    • 🌟实例化Object:
    • 🌟实例化自定义构造函数:(会重复占用内存)
    • 🌟new运算符具体做了什么:
    • 🌟instanceof关键字(一元运算符)
  • 🌟增
  • 🌟删(删除对象或者对象上的属性方法)
  • 🌟改(修改属性和方法)
  • 🌟查对象(访问)
  • 🌟对象的遍历
  • 🌟对象的拷贝
  • 🌟对象的特性
    • 🌟封装
    • 🌟封装方法
  • 🌟原型:
  • 🌟原型链:`本身->构造函数->构造函数的原型->原型的构造函数的原型->->`
  • 🌟对象的继承
    • 🌟继承方式
    • 🌟继承的顺序
  • 🌟this
    • 🌟this的指向
    • 🌟改变this的指向
  • 🌟ES6对象扩展
    • 🌟属性方法的简洁表示法
    • 🌟对象的解构赋值
    • 🌟对象的Rest属性
  • 🌟写在最后


在这里插入图片描述

🌟前言

哈喽小伙伴们,本文将收录在JavaScript【前端童子功】这个专栏里;这个专栏里边会收录一些JavaScript的基础知识和项目实战;希望大家可以多多支持,你们的支持就是我创作的动力;让我们一起来看看吧🤘

🌟对象:

一切皆对象,对象是属性和方法的无序结合。

  • 属性:用数据值来描述它的状态。
  • 方法:用来改变对象的行为叫做方法,一个方法是一个值为某个函数的大户型。

🌟声明对象:

🌟隐式创建对象:

var cup={size:"450ml",color:"red",material:"glass",warm:function (){return "warm";    }}console.log(cup.size);console.log(cup.color);console.log(cup.material);console.log(cup.warm());

🌟实例化Object:

var cup=new Object();cup.size="500ml";cup.color="blue"cup.material="glass"cup.warm=function(){return "warm"}console.log(cup.size);console.log(cup.color);console.log(cup.material);console.log(cup.warm());

🌟实例化自定义构造函数:(会重复占用内存)

构造函数类;实例化对象单个对象

function Cup(size,color,material){this.size=size;this.color=color;this.material=material;this.warm=function(){console.log("warm");;}this.storeUp=function(water){return "store up"+water;}}var cup1=new Cup("500ml","red","玻璃")console.log(cup1);var cup2=new Cup("450ml","yellow","不锈钢")console.log(cup2);var cup3=new Cup("300ml","blue","紫砂")console.log(cup3);

🌟new运算符具体做了什么:

function Base(){this.name = "zhangsan";this.age = 20;
}
var obj = new Base();// new操作符等价于
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
  1. 创建了一个空对象obj
  2. 将这个空对象的__proto__成员指向了Base函数对象prototype成员对象。相当于obj拥有了Base原型上的属性方法
  3. 将Base函数对象的this指针替换成obj,然后再调用Base函数,于是就给obj对象赋值了一个name和age成员变量。相当于obj拥有了Base构造函数上的属性方法
var this = Object.create(Peson.prototype);

🌟instanceof关键字(一元运算符)

如果obj对象是构造函数Fun的一个实例,则 obj instanceof Fun 返回 true。

判断一个对象是否是一个构造函数的实例:

obj instanceof Object   // true
obj instanceof Object    // false

🌟增

对象.属性名=属性值;
对象。方法名=方法‘

🌟删(删除对象或者对象上的属性方法)

  • 销毁对象

    javascript中的垃圾回收机制在对象没有引用的时候会进行销毁,释放内存

    对象=null;
    
  • 删除对象上的属性和方法,使用delete运算符

    • 删除属性:delete 对象.属性名
    • 删除方法:delete 对象.方法名
    var obj={
    a:'a',
    b:function(){console.log('这是一个方法')}
    }
    delete obj.a;   //删除obj对象上的a属性    
    delete obj.b;   //删除obj对象上的b方法
    

🌟改(修改属性和方法)

​ 直接为属性或方法赋新值即可

  对象.属性名=新的属性值;对象.方法名=新的方法;

🌟查对象(访问)

  • 访问属性

    对象.属性名;
    对象["属性名"]; //字符串
    
  • 访问方法

    对象.方法名();
    对象["方法名"](); //字符串
    

    注:当属性名或方法名保存到变量中时,访问该属性或方法需要使用[]

    for(let i in obj){
    obj[i]     // i是存储属性名的变量,所以访问该属性时必须通过[]
    }
    

🌟对象的遍历

  1. for in 循环

    循环遍历对象自身的和继承的可枚举属性(不含Symbol属性).

var obj={
name:'小米',
age:18,
say:function(){
console.log('你好');
}}
for (var i in obj) {
console.log(obj[i]);
}

🌟对象的拷贝

由于对象是引用类型,变量中存储的是数据的地址,所以对象直接通过=赋值只能将地址赋值而不是数据。

对象的拷贝分为浅拷贝、深拷贝:

var obj = {type: "animal",cat:{name:"Tom",weight: 16,food:["fish","meat"]},
}
  • 浅拷贝: 直接拷贝对象的内存地址,如果原地址中对象被改变了,那么浅拷贝出来的对象也会相应改变

    • 1:直接复制
  var newobj=obj;
  • 2:Object.assign(obj)
  var newobj=Object.aaign(obj)
  • 深拷贝: 新开辟一块内存,将对象中所有属性全部复制,如果原地址中对象被改变了,那么深拷贝出来的对象不变

深拷贝实现方法:

  1. 递归遍历,逐层拷贝。 因为基础类型可以直接拷贝,所以通过递归遍历对象的每一层,全部得到基础类型后再拷贝。
function deepCopy(0){var newobj={};for(var i in o){if(typeof o[i]=="bject"){newobj[i]=deepCopy(0[i]);}else{newobj[i]=o[i];}}return newobj;
}
var newobj=deepCopy{obj};
  1. 通过JSON.stringify()先将对象转化为字符串,字符串赋值后再通过JSON.parse()转化回对象。(方法无法转换)
  • JSON 是轻量级数据交互的格式
  1. Object.assign({},obj)`
var newobj=Object.assign({},obj)

🌟对象的特性

  1. 封装
  2. 继承

🌟封装

封装: 将对象的所有组成部分组合起来,尽可能的隐藏对象的部分细节,使其受到保护,只提供有限的接口与外部发生联系。

例如同时生成多个相同的对象,可以将生成对象的过程打包直接调用,这个过程就是封装

优点:

  1. 安全,使用时无法看到具体实现细节,只需要直接调用
  2. 便于修改操作

🌟封装方法

  • 工厂函数(不推荐使用)

    将创建对象并赋值的过程封装成一个函数

    function person(name,sex){var person = {};person.name = name;person.sex = sex;person.say = function(){alert("说话");}return person;
    }
    var zhangsan = person("张三","man");
    alert(zhangsan.name);
    
  • 构造函数(每创建一个对象,会把相同的代码存储到内存中,会造成对内存的浪费)

    function person(name,sex){this.name = name;this.sex = sex;this.say = function(){alert("说话");}
    }
    var lisi = new person("李四","boy");
    alert(lisi.sex);
    

每次使用工厂函数或构造函数,内部的属性和方法都会在内存中重新开辟一个控件存储生成的对象,导致某些相同的方法或属性被重复保存,占用内存。

  • prototype方法(会把共享的方法或属性放到代码段中来存储,它不能共享对象)

    构造函数+原型

    实例一:

    person.prototype.eat=function(){alert("吃饭");
    }
    var lisi=new person("李四","boy");
    lisi.eat();
    

    实例二:

    person.prototype.aaa = {name:"王五"};
    var lisi = new person("李四","boy");
    var zhaoliu = new person("赵六","boy");
    alert(lisi.aaa.name = "xiaosi"); //xiaosi
    alert(zhaoliu.aaa.name);  //xiaosi 将原型上的属性值一起改了
    
  • 混合函数 最佳的一种方法,构造函数与prototype的结合,根据实际情况考虑

    私有属性方法放到构造函数中,共有方法放到原型中

    function person(user, sex){this.user = user;this.sex = sex;
    }
    person.prototype = {eat: funciton(){return "eat";}play: funciton(){return "play";}
    }
    

🌟原型:

通过工厂函数与构造函数的方式实例化对象,每实例化一个对象就会重新开辟一片内存空间,造成空间浪费,把公共的属性和方法放在构造函数的原型上,并不会重新开辟空间,节省内存。

原型是构造函数的属性。构造函数.prototype={}

放到原型上的方法与属性,在对象的_ proto _中找到。

🌟原型链:本身->构造函数->构造函数的原型->原型的构造函数的原型->->

访问对象的属性或方法时遵循的链式规则,该属性或方法会在对象本身调用,对象本身没有则去对象本身的构造函数调用,本身构造函数没有则去父类的构造函数调用、父类的原型…以此类推,直到寻找至Object、以及Object的原型、null。最后属性不存在时会得到undefined,方法不存在则会报错。

ject.prototype.say=function(){alert("Object的方法");}function person(){this.say=function(){alert("person的方法");}}person.prototype.say=function(){alert("person原型的方法");}function student(){this.say=function(){alert("student的方法");}}student.prototype=new person();var xiaoming=new student();xiaoming.say=function(){alert("xiaoMing的方法");}xiaoming.say();

🌟对象的继承

继承:一个对象拥有另一个对象的属性与方法

  • 父类(基类):被继承的对象,
  • 子类:继承的对象。

优点:
提高代码的重用性,提高代码的逻辑性与可维护性。

🌟继承方式

  1. 原型继承(将父类的实例作为子类的原型)

    原理:对象访问属性方法会遵循 "构造函数 -> 原型"的顺序,所以将父类的实例放到子类原型时, 子类实例化出的对象就可以访问到原型上父类的内容,从而实现了继承。

    function Animal(){this.age=age;this.eat=function(food){alert(food)}
    }
    function Cat(){ }
    Cat.prototype = new Animal();    // 将父类(Animal)的实例作为子类(Cat)的原型
    var tom = new Cat();cat.eat('fish')     // 弹出 'fish'console.log(tom instanceof Animal);     //true
    console.log(tom instanceof Cat);        //true
    
  2. call FN.call(obj,参数1,参数2....)
    格式:fun.call(obj2,参数1, 参数2…)
    本质上来说,call方法实际上就是要改变fun函数内的this指向。

    function Animal () {this.eat = function(food){alert(food)}
    }
    function Cat () {this.name = "tom";
    }
    var animal = new Animal ();
    var cat = new Cat ();
    animal.eat.call(cat, "鱼")   // 继承单个方法(改变单个方法的this指向)// 继承整个构造函数 (改变整个构造函数的this指向)
    Animal.call(cat);//(方法立即执行)
    cat.say("鱼")
    
  3. apply
    用法基本与call相同,函数的参数通过数组传递
    格式:fun.apply(obj2,[参数1, 参数2…])

    function Animal () {this.eat = function(food){alert(food)}
    }
    function Cat () {this.name = "tom";
    }
    var animal = new Animal ();
    var cat = new Cat ();
    animal.eat.apply(cat, ["鱼"])Animal.apply(cat)
    cat.eat("鱼")
    
  4. bind继承

    • bing用法与 call类似,也是可以改变函数体内 this 的指向

    • call与apply是使用时立即执行函数,

      bind
      

      是返回对应函数,便于稍后调用

      function Animal () {
      this.eat = function(food){alert(food)
      }
      }
      function Cat () {this.name = "tom";
      }
      var animal = new Animal ();
      var cat = new Cat ();
      animal.eat.bind(cat, "鱼")()   // bind只是改变了this指向,想要调用该函数还需()
      
  5. ES6类继承

    通过extends关键字实现类与类之间的继承,然后实例化子类,来实现继承。详见下一节

🌟继承的顺序

优先级:对象本身–>构造函数–>原型链

原型链:
当访问对象的属性或方法时,该属性或方法会在对象本身调用,对象本身没有则去对象本身的构造函数调用,本身构造函数没有则去父类的构造函数调用、父类的原型…以此类推,直到寻找至Object、以及Object的原型、null。最后属性不存在时会得到undefined,方法不存在则会报错。

  Object.prototype.say=function(){alert("Object的方法");}function person(){this.say=function(){alert("person的方法");}}person.prototype.say=function(){alert("person原型的方法");}function student(){this.say=function(){alert("student的方法");}}student.prototype=new person();var xiaoming=new student();xiaoming.say=function(){alert("xiaoMing的方法");}xiaoming.say();

🌟this

this是一个很特别的关键字,被自动定义在所有函数的作用域中。
this总是会指向一个对象。或者说,this就是属性或方法‘当前’所在的对象。

🌟this的指向

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

  1. 在全局环境和全局函数中this指window全局对象。
  2. 作为对象方法调用,this 指代调用该方法对象。
  3. 在构造函数中this指向构造函数的实例
  4. 在事件中,this指向事件源。
  5. 在call和apply中,this指的是方法中传入的对象,如果apply中没有传对象,this指向window
function Fun(){run(){console.log(this)       // this指向实例化出的对象,因为是实例化出的对象调用了run方法setInterval(_=>{conosle.log(this)     // this指向 window,因为是window调用了setInterval方法})}
}

🌟改变this的指向

  • call() ;

    • 第一个参数是this的指向,第二个参数为一个参数列表,会立即执行
  • apply() ;

    • 第一个参数是this的指向,第二个参数为一个参数数组,会立即执行
  • bind()

    • 第一个参数是this的指向,第二个参数为一个参数列表,不会立即执行

🌟ES6对象扩展

🌟属性方法的简洁表示法

当属性名为变量名, 属性值为变量的值时,可直接将变量作为对象的属性:

let username = "张三"let obj = {username,      // 属性名为变量名, 属性值为变量的值age: 20
}
  • 对象方法的简写:

    let obj = {
    run:function(){alert(1)
    }
    }
    // 简写为:
    let obj = {
    run(){alert(1)
    }
    }
    

这种写法用于函数的返回值,将会非常方便。

function getPoint() {const x = 1;const y = 10;return {x, y};
}getPoint()

🌟对象的解构赋值

解构不仅可以用于数组,还可以用于对象。

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"let { first: f, last: l } = { first: 'hello', last: 'world' };
f // 'hello'
l // 'world'

上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo

如果变量名与属性名一致,可以写成下面这样:

let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

  • 用途1:接收函数的参数

    // 接收被除数x与除数y
    function calc({dividend: x, dividend: y}){
    return x/y
    }
    let divide = calc({dividend:9,dividend:3})
    
  • 用途2:接收函数的返回值

    function calc(a,b){
    return {add: a+b,subtract: a-b,multiply: a*b,divide: a/b
    }
    }
    // 相对于返回数组来讲,不需要知道返回值参数的顺序
    let {add, subtract, multiply, divide} = calc(1,2)
    

🌟对象的Rest属性

ES6中数组的rest和扩展运算符,用于数组于普通参数之间的转化

Math.max(...[1,2,3,4])function fun(a,b,...c){ }

现在在ES9中,当对象结构复制时也可以使用rest运算符:

let obj = {a: 1, b: 2, c: 3};
let {a,...x}
//  a == 1
//  x == {b: 2, c: 3}

或在函数参数中也可以使用:

restParam({a: 1,b: 2,c: 3
});function restParam({ a, ...x }) {// a = 1// x = { b: 2, c: 3 }
}

🌟写在最后

更多JavaScrip知识以及API请大家持续关注,尽请期待。各位小伙伴让我们 let’s be prepared at all times!

✨原创不易,还希望各位大佬支持一下!
👍 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!