Object对象

一、Object对象

1.1、什么是对象

对象是由一对或者多对属性(包含属性名和属性值)组成的集合,属性名也叫键名,属性值也叫键值,所以对象的属性也可以称为键值对,对象就是属性的无序集合

1.2、对象的属性

对象有属性,所谓的属性就是这个对象的特点、特性

在特殊情况下,属性是必须加引号的

属性为特殊字符

属性为数字

属性中有空格

关键字、保留字

特殊形式的属性,必须要加上引号,检索属性的时候,必须要用方括号[‘name’],如果属性名符合标识符规范,可以加引号,也可以不加引号,如果不符合标识符规范,则属性必须加引号

对象的属性访问:

点语法:只能访问符合标识符规范的属性

中括号:要加引号,不加引号就是变量

1.3、对象的方法

对象只有属性,但是如果这个属性的值是一个函数,那么这个函数我们就称为对象的”方法“,比如下面的案例,sayHello就是一个属性,只不过它的值是一个函数,所有我们说obj这个对象,有sayHello方法

  var obj={
            name:'小明',  
            age:19,
            sayHello:function(){
                console.log('大家好,我叫'+this.name);
            }
        }
        console.log(obj.name);
        console.log(obj.age);
        console.log(obj.sayHello());

1.4对象的遍历

  var obj={
            name:'小明',  
            age:19,
            sayHello:function(){
                console.log('大家好,我叫'+this.name);
            }
        }
        for(var k in obj){
            console.log(k);
            console.log(obj.k);
        }

二:对象的创建

2.1、字面量方式

var obj={
            name:'小明',
            age:19
        }
        console.log(obj);

2.2、通过new关键字创建对象

var obj=new Object(); //创建的是一个空对象,要往里面添加属性和值
        obj.name='小红';
        obj.age=20;
        console.log(obj);

2.3、对象的常用操作

var obj={
            name:'小明',  
            age:19,
            sayHello:function(){
                console.log('大家好,我叫'+this.name);
            }
        }
        obj.name='小红'; //改
        obj.sex='女';   //增
        delete obj.age;  //删
        console.log(obj.name); //查
        console.log(obj);

2.4、保护对象

Object.preventExtensions()

阻止扩展,可以修改,但是不可以删除

Object.seal()

密封,不能增删

Object.freeze()

冻结,不能增删改

ES6新增的对象

(1)Object.is()

用来比较两个值是否相等

Object.is(NaN,NaN)
//true
NaN==NaN
//false
Object.is(+0,-0)
//false
+0==-0
//true
Object.is({},{})
//false
{}=={}
//false

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iLA3KF7e-1635345187181)(C:\Users\web\AppData\Roaming\Typora\typora-user-images\image-20210930141847982.png)]

(2)Object.assign()

用来合并对象的

用法:let 新对象=Object.assign(目标对象,需要合并的对象);

         let x={a:1};
         let y={b:2};
         let z={c:3};

         let obj=Object.assign({},x,y,z);
         console.log(obj);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TN8eVQZo-1635345187184)(C:\Users\web\AppData\Roaming\Typora\typora-user-images\image-20210930143450665.png)]

如果合并的对象的属性名有重复就是后面的会覆盖前面的

         let x={a:1};
         let y={b:2,a:4};
         let z={c:3};

         let obj=Object.assign({},x,y,z);
         console.log(obj);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NdmHmsiy-1635345187190)(C:\Users\web\AppData\Roaming\Typora\typora-user-images\image-20210930143800622.png)]

如果只有一个参数,Object.assign会直接返回该参数。

         let x={a:1};

         let obj=Object.assign(x);
         console.log(obj);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UDHxlMdk-1635345187192)(C:\Users\web\AppData\Roaming\Typora\typora-user-images\image-20210930144123070.png)]

由于undefinednull无法转成对象,所以如果它们作为参数,就会报错。

Object.assign(undefined) // 报错
Object.assign(null) // 报错

可以利用这个方法来拷贝数组

        //数组中的arr.push()方法会改变原数组
				let x=[1,2,3];

         let arr=Object.assign([],x);
         console.log(arr);
         arr.push(4);
         console.log(arr);
         console.log(x);

(3)Object.keys()、 Object.entries() 、Object.values()

         let obj={
            name: 'zhangsan',
            age: 18,
            sex: '男'
         }
         console.log(obj);

         //遍历属性
         for(let key of Object.keys(obj)){
            console.log(key);
         }

         //遍历属性值
         for(let val of Object.values(obj)){
            console.log(val);
         }

         //解构遍历的键值对
         for(let [val,key] of Object.entries(obj)){
            console.log(val,key);
         }

         //遍历键值对
         for(let item of Object.entries(obj)){
            console.log(item);
         }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lPXYfk5u-1635345187193)(C:\Users\web\AppData\Roaming\Typora\typora-user-images\image-20210930150230824.png)]

(4)对象的解构赋值与…运算符

         let {x,y,...z}={x:1,y:2,z:3,t:4};
         console.log(x,y,z);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cH7axFFZ-1635345187194)(C:\Users\web\AppData\Roaming\Typora\typora-user-images\image-20210930152418557.png)]

由于解构赋值要求等号右边是一个对象,所以如果等号右边是undefind或者null,就会报错,因为它们无法转为对象

解构赋值必须是最后一个参数,否则会报错

解构赋值的拷贝是浅拷贝,即如果是一个键的值是复合类型的值(数组,对象,函数),那么解构赋值拷贝的是这个值的引用,而不是这个值的副本

扩展运算符(…)用于取出参数对象的所有遍历属性,拷贝到当前对象中,这等同于使用Object.assign方法

三、构造函数

3.1、什么是构造函数

用new关键字来调用的函数,称为构造函数,构造函数首字母一般大写,一个构造函数创造的对象被称为该构造函数的实例

常见的内置构造函数

Object()

Array();

RegExp();

Function();

Date();

3.2、构造函数的原理

一个函数可以用new关键字来调用,那么会按顺序发生四件事

1.隐秘的创建一个新的空对象

2.将这个函数里面的this绑定到刚才创建的隐秘新对象上

3.执行函数体内的语句

4.返回这个新的对象

function Fn(name,age){
            /*
            1.隐秘的创建一个this
            2.将这个函数里面的this绑定到刚才创建的隐秘新对象上
            this:{
                name:undefind '小明'
                age:undefind  19
            }
            */
            this.name=name;  //执行代码
            this.age=age;
            //4.return这个this,赋给xiaoming
        }
        //new关键字来调用函数,那么函数就叫做构造函数,将返回一个对象
        //new关键字造出来的xiaoming,我们称为Fn类的实例,可以理解为实体
        var xiaoming=new Fn('小明',19); //Fn函数就是构造函数  xiaoming这个对象是Fn类的实例
        console.log(xiaoming);

3.3、构造函数类和实例

当一个函数被new关键字来调用,这个函数称为构造函数

函数里面的语句会被执行,类是具有相同属性和方法的集合

 function People(name,age){
        /*
        AO{
            this:{
                name:小明
                age:18
                sayHello:f(){}
            }
            name:undefind 小明
            age:undefind 18
            sayHello:f(){}
        }
        */
        this.name=name; //第一个name是this里面的,第二个name是函数作用域里面的,先找函数作用域有没有name值,有就赋值给this里面的name
        this.age=age;
        this.sayHello=function(){
            console.log('大家好,我叫'+this.name);
        }
    }
    /*
    xiaoming{
        name:小明
        age:18
        sayHello:f(){}
    }
    */
    var xiaoming=new People('小明',18);  //People是构造函数,也叫做People类,xiaoming是对象,xiaoming这个对象是People类的实例
    var xiaohong=new People('小红',17);
    console.log(xiaoming); //People {name: "小明", age: 18, sayHello: ƒ}
    xiaoming.sayHello();   //大家好,我叫小明
    console.log(xiaohong);  //People {name: "小红", age: 17, sayHello: ƒ}
    xiaohong.sayHello();   //大家好,我叫小红
function People(){
        this.name='张三';
        this.age=19;
        this.sayHello=function(){
            console.log(this.name);
        }
    }
// 使用new关键字来调用函数,那么函数就叫做构造函数,将返回一个对象
    var zhangsan=new People();
    console.log(zhangsan); //People {name: "张三", age: 19, sayHello: ƒ}

3.4、构造函数的注意事项

1、如果函数里面没有this,那么将创建一个空对象
 /*构造函数里面如果没有this,那么就废了,就不能给隐秘新创建的对象添加属性,但是里面的语句还是能执行,所以new出来的是一个空对象*/
        function People(){
            for(var i=1,sum=0;i<=100;i++){
                sum+=i;
            }
            console.log(sum); //5050
        }
        var xiaoming=new People();
        console.log(xiaoming);  //People{}
2.构造函数中,不允许出现return语句

构造函数总不能出现return,严格来说不能return引用类型数据,如果出现return语句将返回引用类型值,那么构造函数将不能返回新创建的那个对象,而是返回return语句后面的内容

function People(name,age){
        this.name=name;
        this.age=age;
        // return undefined; //Peopel{name:'小明',age:19}
        // return null; //Peopel{name:'小明',age:19}
        // return []; //[]
        // return {a:1,b:2}; // {a:1,b:2}
        return 1; //Peopel{name:'小明',age:19}
    }
    var xiaoming=new People('小明',19);
    console.log(xiaoming);
    console.log(xiaoming.name);

3.5、总结

  1. 当一个**函数()**调用的时候,this就是window
  2. 当一个函数用**对象.方法()**调用的时候,this就是这个对象
  3. 当一个函数绑定给一个HTML元素事件的时候,this就是这个HTML元素
  4. 当一个函数用定时器调用的时候,this就是window
  5. 当一个函数用apply、call调用的时候,this就是你指定的第一个参数
  6. 当一个函数用new调用的时候,this就是隐秘创建的空对象,函数里面的语句将被执行,并且返回新对象

四、原型prototype

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LTSuGBpQ-1635345187194)(C:\Users\web\AppData\Roaming\Typora\typora-user-images\image-20210903102405933.png)]

4.1、原型prototype

原型是构造函数创建对象的原始模型

原型的特点

原型也是对象,是函数对象的一个属性

原型自带constructor属性,constructor指定构造函数

构造函数创建出来的对象会继承原型的属性和方法

4.2、原型对象与实例

当一个对象被new出来的时候,不仅仅执行了构造函数里面的语句,而且在构造函数的原型中,所有的属性也给加了这个对象

prototype一定是函数的属性,但这个函数是一个构造函数的时候,那么它new出来的对象,它的原型对象为new出来的实例的原型对象

  // function People(name,age){
    //     this.name=name;
    //     this.age=age;
    // }
    // People.prototype={
    //     sex:'男',
    //     waihao:'小白'
    // }
    // var xiaoming=new People('小明',12);
    // var xiaohong=new People('小红',13);
    // console.log(xiaoming);
    // console.log(xiaoming.name);
    // console.log(xiaoming.sex);
    // console.log(xiaohong.waihao);

4.3、实例对象的__proto__属性

当一个对象被new出来的时候,不仅执行了构造函数里面的语句,也会把这个函数的__protp__执指向构造函数的prototype

  //构造函数里面没有任何的语句,也就是说,这个函数在执行的时候,不会给创建出来的对象添加任何属性
    function People(){}
    //构造函数的原型,我们更改了构造函数的原型,为一个新的对象
    People.prototype={
        name:'小明',
        age:12,
        sex:'男'
    }
    //当一个对象被new出来的时候,不仅仅执行了构造函数里面的语句,也会把这个函数的__proto__指向构造函数的prototype 
    console.log(xiaoming.__proto__);  //{name: "小明", age: 12, sex: "男"} 属性在原型对象上
	//xiaoming这个对象的原型对象===构造函数的原型
    console.log(xiaoming.__proto__==People.prototype);  //true
    var xiaoming=new People();
    console.log(xiaoming); //People{}  空对象
    //当我们访问name属性的时候,自己身上没有,就会去找原型,原型身上有,就当做自己的属性返回了
    console.log(xiaoming.name);  //小明  自己没有,找原型对象

当访问一个对象身上属性的时候,如果这个对象身上有这个属性,则返回它的值,如果它的身上没有这个属性,那么将访问它的原型对象,检测它的原型身上是否有这个值,如果有返回它原型对象身上的这个值

任何一个函数都有原型,原型是一个对象。用prototype来访问,当这个函数为构造函数的时候,new出来的对象。它的原型对象就是这个构造函数的原型

prototype称为‘原型’,只有函数才有

__proto__称为‘原型对象’,任何对象都有原型对象

4.4、原型的应用

在原型上储存构造函数创建出对象的共有属性和方法,可以避免代码冗余

//在构造函数里面,负责定义一些属性,随着构造函数的执行,这个属性将绑定到new出来的对象身上
    function People(name,age){
        this.name=name;
        this.age=age;
    }
    //把所有的方法,定义在原型对象上
    // People.prototype={
    //     sayHello:function(){
    //         console.log('大家好,我叫'+this.name);
    //     }
    // }
    People.prototype.sayHello=function(){
        console.log('大家好,我叫'+this.name);
    }
    var xiaoming=new People('小明',12);
    var xiaohong=new People('小红',12);
    console.log(xiaoming);
    xiaoming.sayHello();

五、创建对象的常见模式

5.1、工厂模式

  function People(name,age){
        var o=new Object();  //创建空对象
        o.name=name;
        o.age=age;
        o.sayHello=function(){
            console.log(this.name);
        }
        return o;
    }
    var xiaoming=new People('小明',12);
    console.log(xiaoming); //People {name: "小明", age: 12, sayHello: ƒ}




            function People(name,age){
                var obj={};
                obj.name='张三';
                obj.age=19;
                return obj;
            }
            var zhangsan=new People();
            console.log(zhangsan);

5.2、构造函数模式

  function People(name,age){
        this.name=name;
        this.age=age;
        this.sayHello=function(){
            console.log(this.name);
        }
    }
    var xiaoming=new People('小明',12);
    console.log(xiaoming);  //People {name: "小明", age: 12, sayHello: ƒ}

5.3、原型模式

借助函数的原型,将一些实例对象共享的属性和方法放在原型对象中,这样子就不必在构造函数中定义重复的方法

好处:所有的对象实例共享它的属性和方法(即所谓的共有属性)

坏处:省略了构造函数传递初始值参数,导致所有的实例对象都是相同的属性和方法

 function People(){}
    People.prototype={
        name:'小明',
        age:19,
        sayHello:function(){
            console.log(this.name);
        }
    }
    console.log(People.prototype);  //{name: "小明", age: 19, sayHello: ƒ}  构造函数的原型(prototype)==对象的原型对象(__proto__)

    var xiaoming=new People();  //创建了一个实例xiaoming
    console.log(xiaoming.name); //小明

    var xiaohong=new People(); //创建了一个实例xiaohong
    console.log(xiaohong.__proto__); //{name: "小明", age: 19, sayHello: ƒ}  xiaohong.__proto__==People.prototype
    xiaohong.name='小红'; //给构造函数添加属性
    console.log(xiaohong);  //People {name: "小红"} 
    console.log(xiaohong.name);

5.4、混合模式(构造函数模式+原型模式)

构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。

混合模式共享着对相同方法的引用,又保证了每个实例有自己的私有属性,最大限度的节省了内存

function People(name,age){
        this.name=name;
        this.age=age;
    }
    People.prototype={
        //每个函数都有prototype属性,指向该函数的原型对象,原型对象都有constructor属性,这个是一个指向prototype属性所在函数的指针
        constructor:People,
        sayHello:function(){
            console.log(this.name);
        }
    }
    var xiaoming=new People('小明',12);
    var xiaohong=new People('小红',13);

    console.log(xiaoming); //People {name: "小明", age: 12}
    xiaoming.sayHello();

    console.log(xiaohong); //People {name: "小红", age: 13}
    xiaohong.sayHello();

六、原型链

6.1、原型链机制

只要是对象,一定有原型对象,只要这个东西是对象,那么一定有__proto__属性

 function People(){}
    var xiaoming=new People();
    console.log(xiaoming); //People {}
    console.log(xiaoming.__proto__); //{constructor: ƒ}
    console.log(xiaoming.__proto__.constructor); //People(){}
    console.log(xiaoming.__proto__.__proto__); //{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
    console.log(xiaoming.__proto__.__proto__.constructor); //ƒ Object() { [native code] }

js的世界只有一个对象没有原型对象,这个对象就是Object.prototype

Object是一个函数,是系统内置的构造函数,用于创造对象的,Object.prototype是所有对象的原型链终点

当我们在一个对象上打点调用某个方法的时候,系统会沿着原型链去寻找它的定义,一直找到Object.prototype

//Object.prototype是所有对象的原型链的终点,所以我们直接给Object.prototype增加一个方法,那么世界上所有的对象都能调用这个方法
Object.prototype.sayHello=function(){
        console.log('你好');
    }
   var arr=[1,2,3];
   arr.sayHello();
   '没没没'.sayHello();

七、对象与属性

7.1、对象直接打点验证某个属性是否存在

对象打点调用属性,可以看出来属性是否在自己身上或者原型链上,如果在,就返回值,如果不存在就返回undefind

 var obj={
        a:1,
        b:2,
        c:undefined
    }
    //只要是对象,就一定有原型对象__proto__
    obj.__proto__={
        d:3
    }
    console.log(obj); //{a: 1, b: 2, c: undefined}
    console.log(obj.a);  //1
    console.log(obj.d);  //3 在自己身上没有d,就找原型链上有没有d
    console.log(obj.c);  //undefind 有个误会,比如obj.c的值为undefined,那么obj.c还是返回undefined,不知道c属性是否存在

7.2、in运算符

返回一个布尔值,表示这个属性是不是对象的属性

in不仅仅检测是对象自己有没有这个属性,也会检测原型链上有没有,如果有就返回true,没有就false,in操作符会进行原型链查找

var obj={
        a:1,
        b:2,
        c:false
    }
    obj.__proto__={
        d:20
    }
    console.log('a' in obj);  //true
    console.log('d' in obj); //true


//for循环会把原型链上所有的可枚举的属性列出来,不仅把自己身上的属性还有原型链上的所有属性都列出来,但是系统默认的属性(比如constructor)都是不可枚举的
 for(var k in obj){
        console.log(k);
    }

7.3、hasOwnProperty方法

这个方法定义在了Object.prototypr对象上面,所以任何一个Object都能拥有这个方法

这个方法返回true、false。表示自己是否拥有这个属性,不考虑原型链,就看自己身上有没有这个属性,不进行原型链查找

var obj={
        a:1,
        b:2
    }
    obj.__proto__={
        c:3
    }
    console.log(obj.hasOwnProperty('a')); //true
    console.log(obj.hasOwnProperty('c')); //flase

    for(var k in obj){
        //短路算法,如果obj.hasOwnProperty(k)为真,则输出后面
        obj.hasOwnProperty(k)&&console.log(k); //a,b
    }

7.4、定义属性:Object.defineProperty()

js引擎允许对属性操作的控制,需要使用方法Object.defineProperty()来实现,这个方法接三个参数:属性所在的对象、属性的名字、描述符对象

7.5、读取属性的描述对象Object.getOwnPropertyDescriptor()

7.6、instanceof运算符

A instanceof B

验证A对象是不是B类的实例,但是不能证明A是new B()出来,因为可能是继承

function Dog(){}
    //实例化一个dog对象
    var dog=new Dog();
    console.log(dog instanceof Dog); //true
function Dog(){}
    function Cat(){}
    Cat.prototype=new Dog();  //Cat是父亲,Dog是儿子,儿子继承了父亲
    var mao=new Cat(); //通过cat实例一个
    console.log(mao);
    console.log(mao.constructor); //ƒ Dog(){}

7.7、Object.setPrototypeOf

Object.setPrototypeOf(对象);

创建并指定原型

setPrototypeOf():可以为已存在的

八、继承

  function Dog(){}
    function Cat(){}
    Cat.prototype=new Dog(); //Cat是new Dog创建出来的,Cat是mao的母亲,Dog是mao的父亲
    var mao=new Cat();
    console.log(mao); //__proto__: Dog  __proto__指向的是父亲,Dog是父亲
    console.log(mao.constructor); //ƒ Dog(){}

8.1、利用原型对象实现继承

原型对象是JavaScript实现继承的传统方式,如果一个对象中本来没有某个属性或方法,但是可以从另一个对象中获得,就实现了继承

 function Person(name){
            this.name=name;
        }
        Person.prototype.sayHello=function(){
            console.log(`大家好,我叫${this.name}`);
        }
        var p1=new Person('jack');
        var p2=new Person('lili');
        console.log(p1,p2);
        p1.sayHello();
        p2.sayHello();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mAgSgUdr-1635345187195)(C:\Users\web\AppData\Roaming\Typora\typora-user-images\image-20210909171857851.png)]

对象 p1、p2 原本没有 sayHello() 成员,但是在构造函数 Person 的原型对象添加了 sayHello() 成员后,p1、p2 也就拥有了 sayHello() 成员,因此,上述代码可以理解为 p1、p2 对象继承了原型对象中的成员

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值