对象、类、与面向对象编程

对象、类、与面向对象编程

  1. 属性类型 -这些都是js内部引擎的规范定义不能改变
    分为:数据属性和访问器属性
    [[Configurable]] 是否可以通过delete删除 并重新定义,是否可以修改它的特性,以及是否可以把它改成访问器属性,默认 是true

[[Enumerable]] 表示属性是否可以通过for-in循环返回。直接定义在对象的属性的这个特性都是true

[[Writable]] 表示属性的值是否可以被修改,默认为true

[[Value]] 包含属性实际的值。读取和写入的位置,默认为undefined

/*要修改默认属性的默认特性
必须使用 Object.defineProperty() 这个方法 接收3个参数

要给其添加属性的对象
属性的名称
一个描述符对象(描述符对象上的属性包含) configurable\enumerable\writable\value
跟相关特性的名称一一对应。根据需要修改的特性,可以设置其中一个或多个值
*/
let person = {};
Object.defineProperty((person,"name",{
    writable:false,
    value:"Nicholas"
}));
console.log(person.name);
person.name = 'Greg';
console.log(preson.name)//Nicholas
delete person.name;    //类似规则也适用于创建不可配置的属性
console.log(preson.name)//Nicholas

/*
访问器属性
访问器属性不包含数据值, 他们包含  gtter setter 函数,不够这两个函数不是必需的。
[[Configurable]] 表示属性是否可以通过delete删除并重新定义,是否可以修改它的特性,以及是否可以把它改为数据属性。默认这个属性为true
[[Enumerable]] 是否可以通过 for-in循环返回。 默认true
[[Get]] 获取函数,在读取属性时调用, 默认值为undefined
[[Set]] 设置函数,在写入属性时调用,默认undefined
*/

/*
访问器属性是不能直接定义的,必须使用Object.defineProperty()
*/
//定义一个对象,包含伪私有成员year_那公共成员edition
let book = {
    year_:2017,
    edition:1
};
Object.defineProperty(book,"year",{
    get() {
        return this.year_;
    },
    set(newValue) {
        if(newValue > 2017) {
            this.year_ = newValue;
            this.edition += newValue - 2017;
        }
    }
})
book.year = 2018;
console.log(book.edition);// 2
//

/*
定义多个属性
Object.defineProperties()
这个方法可以通过多个描述符一次性定义多个属性
2个参数,(要为之添加或者修改属性的对象,另一个描述符对象,其属性与要添加和修改的属性一一对应。)
*/
let look = {};
Object.defineProperties(book,{
    year_:{
        value:2017
    },
    edition:{
        value:1
    },
    year:{
        get(){
            return this.year_;
        },
        set(newValue) {
            if(newValue >2017) {
                this.year_ = newValue;
                this.edition += newValue - 2017;
            }
        }
    }
})
/**
Object.getOwnPropertyDescriptor()
 * 读取属性
 * @param  {obj}   对象     属性所在的对象
 * @param  {str}   字符串      要取得其描述符得属性名
 * @param {obj}  返回是对象  根据属性类型不同 返回得 属性也不同
*/
let book = {};
Object.defineProperties(book,{
    year_:{
        value:2017
    },
    edition:{
        value:1
    },
    year: {
        get: function() {
            return this.year_;
        },
        set: function(newValue){
            if(newValue > 2017) {
                this.year_ = newValue;
                this.edition += newValue - 2017;
            }
        }
    }
})

let descriptor = Object.getOwnPropertyDescriptor(book,"year_");
/*

*/
console.log(Object.getOwnPropertyDescriptors(book));

//es2017出的方法    会在每个自有属性上调用Object.getOwnPropertyDescriptor()并在一个新对象中返回它们
/**
 * 合并
 * 
 * assign() 
 * @param {obj}  返回是对象  一个或多个对象
 * 
 * 先把每个原对象   Object.propertyIsEnumerable()返回true
 * 和自有对象的Object.hasOwnProperty()返回true)属性复制到目标对象
 * 使用原对象的get 目标对象的set
 * 
 * 对对象操作是浅复制, 如果多个源对象都有相同的属性,则使用最后一个复制的值
 */

let dest,src,result;

dest = {id:'dest'};
result = Object.assign(dest,{id:'src1',a:'foo'},{id:'src2',b:'bar'});
//会覆盖之前相同的属性
console.log(reslut);//{ id: src2, a: foo, b: bar }


// 可以通过目标对象上的设置函数观察到覆盖的过程:
dest = {
  set id(x) {
    console.log(x);
  }
};

Object.assign(dest, { id: 'first' }, { id: 'second' }, { id: 'third' });
// first
// second
// third

let dest ,src ,result;
/**
 *  错误处理
*/
dest = {};
src = {
    a: 'foo',
    get b () {
        //Object.assign()在调用这个获取函数时会抛出错误
        throw new Error();
    },
    c:'bar'
};

try{
    Object.assign(dest,src)
} catch(e) {

}
// Object.assign()没办法回滚已经完成的修改
// 因此在抛出错误之前,目标对象上已经完成的修改会继续存在:
console.log(dest); // { a: foo }
//对象的标识及相等判定

//这些是 === 符合预期的情况

console.log(true === 1);  // false
console.log({} === {});   // false
console.log("2" === 2);   // false
// 这些情况在不同JavaScript引擎中表现不同,但仍被认为相等
console.log(+0 === -0);   // true
console.log(+0 === 0);    // true
console.log(-0 === 0);    // true

// 要确定NaN的相等性,必须使用极为讨厌的isNaN()
console.log(NaN === NaN); // false
console.log(isNaN(NaN));  // true


//ES6 新增了 Object.is() 和===很像

/**
 * 判断是否相等
 * 
 * is() 
 * @param {obj}  传参2个对象
 * 
 */

console.log(Object.is(true, 1));  // false
console.log(Object.is({}, {}));   // false
console.log(Object.is("2", 2));   // false

// 正确的0、-0、+0相等/不等判定
console.log(Object.is(+0, -0));   // false
console.log(Object.is(+0, 0));    // true
console.log(Object.is(-0, 0));    // false

// 正确的NaN相等判定
console.log(Object.is(NaN, NaN)); // true

//如果要检查多个值,递归地利用相等性传递即可

function recursivelyCheckEqual(x,...rest){
    return Object.is(x,rest[0]) &&
            (rest.lengt < 2 || recursivelyCheckEqual(...rest))
}

es6 属性值简写

let name = 'Matt';
let person = {
    //name:name 
    name
};

es6 可计算属性

//old 之前想动态定义对象key值 需要这么做
const namekEY = 'name';
const ageKey = 'age';

let person = {};
person[nameKey] = 'Matt';
person[ageKey] = 27;

console.log(person) // {name:'Matt',age:27}

//new  es6 现在动态定义可以这么写

let person = {
  [nameKey]: 'Matt',
  [ageKey]: 27
};

es6 简写方法名字

//old es5
let person = {
    sayName: function() {
        console.log('...')
    }
}

person.sayName('Matt');//My name is Matt
//new es6
const methodKey = 'sayName';
let person = {
    sayName(name) {
        console.log('...')
    }
    [methodKey](name) {// 简写方法名与可计算属性健相互兼容
        console.log('1212')
    }
}
//配合计算属性本身可以是复杂的表达式

const nameKey = 'name';
const ageKey = 'age';
const jobKey = 'job';
let uniqueToken = 0;

function getUniqueKey(key) {
  return `${key}_${uniqueToken++}`;
}

let person = {
  [getUniqueKey(nameKey)]: 'Matt',
  [getUniqueKey(ageKey)]: 27,
  [getUniqueKey(jobKey)]: 'Software engineer'
};

console.log(person);  // { name_0: 'Matt', age_1: 27, job_2: 'Software engineer' }

对象解构

1.解构 同名可以省略

2.解构可以结构对象属性和方法,把源数据结构转换为对象,但是null和undefined不能被解构

3.解构 可以同时进行定义默认值

4.解构 不要求变量必须在解构表达式种声明,如果是事先声明,解构表达式必须包含在一对括号中

5.嵌套解构 解构对于嵌套属性或赋值目标没有限制,可以通过复制对象属性(浅拷贝)

6.嵌套解构 可以使用嵌套结构进行解构

7.嵌套解构 外层属性没定义 源对象/目标对象都不能使用

8.对象解构 如果解构中途出错,只会部分解构

9.对象解构 在函数参数列表解构,不会对arguments有影响

let person = {
    name:'Matt',
    age:27
};

let {name, age} = person;
console.log(name); //Matt
console.log(age); //27

//可以在解构 时候进行 同时进行定义默认值
let person = {
    name:'Matt',
    age: 27
};

let {name,job='Software engineer'} = person;
console.log(name); //Matt
console.log(job); //Software engineer

创建对象的几种方法

工厂模式

  1. 大众化 应用于软件工程
function createPerson(name,age,job) {
    let o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function () {
        console.log(this.name);
    }
    return o;
}
let person1 = createPerson('nicholas',29,"Software Engineer");

let person2 = createPerson('Greg',28,"Doctor");

function Person(name,age,job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        console.log(this.name)
    }
}

let person1 = new Person('Nicholas',12,"student")

let person2 = new Person('Jack',11,"police")

new 操作符都做了什么

(1) 在内存中创建一个新对象。

(2) 这个新对象内部的[[Prototype]]特性被赋值为构造函数的prototype属性。

(3) 构造函数内部的this被赋值为这个新对象(即this指向新对象)。

(4) 执行构造函数内部的代码(给新对象添加属性)。

(5) 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。

这是我在开课吧学习记下来的笔记,开课吧非常好,大家在一起直播上课,课上老师幽默风趣,贼逗乐,讲的通俗易懂。很牛逼,爱了爱了,课后微信群里大家交流很积极,助教小姐姐很耐心的教,啊哈哈哈哈

下面是我在开课吧上课的截图
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值