对象,垃圾回收

创建对象的方式

1. 使用构造函数

 let user = new Object(); // 使用构造函数

2. 使用字面量:本质上还是调用构造函数

		let user2 = {
            name: '叶叶'
        };

对象属性

1. 普通属性

  		let user3 = {
            name: 'li叶叶', // 键"name",值'li叶叶'
            age: 30, // 键"age",值30
            /* 可以使用多个单词作为属性名,但是必须加上引号 */
            'likes birds': true,
            /* 最后一个属性后面可以添加一个逗号,叫做尾逗号,或者悬挂逗号,方便我们添加,删除,移动属性 */
        };

2. 计算属性 在对象字面量中使用方括号.这样的属性叫做计算属性

		let fruit = prompt("请选择你要购买的水果", 'apple');

        let bag = {
            [fruit]: 5, // 属性名从fruit变量中计算
        };
        alert(bag.apple); // 如果 fruit='apple'

对象操作

1. 读取对象属性

 		console.log(user3.name); // li叶叶
        console.log(user3.age); // 30
        // 这种使用方括号的语法,对任何属性都适用
        // 方括号里如果是变量或表达式,计算变量的值
        console.log(user3['likes birds']);
        console.log(user3.isAdmin); //undefined

2. 添加对象属性

 		user3.isAdmin = true;
        console.log(user3.isAdmin); //true

3. 移除一个属性

		delete user3.isAdmin;
        console.log(user3.isAdmin); // undefined

实际应用:属性值简写

		function makeUser(name, age) {
            return {
                name: name,
                age: age
            };
        }
        // 可以简写为
        function makeUser2(name, age) {
            return {
                name,
                age
            };
        }
        let use = makeUser('花花', 20);
        alert(use.name + use.age);

4. 检查属性是否存在
4.1访问一个不存在的属性会返回undefined

	let user4 = {};
	alert(user4.noSuchProperty === undefined);

4.2 使用in来检查属性是否存在

		alert('blabla' in user4);
        // 注意
        let obj = {
            test: undefined
        };
        alert(obj.test); // undefined,表示属性不存在,这是错误的
        alert("test" in obj); // true属性存在

for…in循环

		for(key in object){
			各个属性的执行区
    	}
        let user5 = {
            name: '叶叶',
            age: 20,
            isAdmin: true
        };
        for (let key in user5) {
            console.log(key);
            console.log(user5[key]);
        }

5. 拷贝对象(而不是拷贝对象的引用)
5.1 遍历原始对象的属性,复制给新的对象

		let user6 = {
            name: 'li叶叶',
            age: 30
        };
        let clone = {};
        for (let key in user6) {
            clone[key] = user6[key];
        }

5.2 通过Object.assign(这是浅拷贝,如果对象的属性不是原始值,而是指向一个对象,则复制后的对象共享这个指向的对象)

  Object.assign(dest[,src1,src2,src3,...])
        dest和src1,...srcN是对象
        复制了src1,src2,...,srcN的所有对象到 dest
        如果有同样属性名的属性,前面的会被覆盖
		let user7 = {
            name: "John"
        };

        let permissions1 = {
            canView: true
        };
        let permissions2 = {
            canEdit: true
        };

        // 把permissions1和permissions2的所有属性都拷贝给user
        Object.assign(user7, permissions1, permissions2);
        console.log(user7); //{name: "John", canView: true, canEdit: true}

垃圾回收

JavaScript主要的内存管理概念是可达性
1. 什么是可达性?
以某种方式可以访问或可用的值,这样的值被称为可达值.必须存储在内存中,不能被释放
如果一个值可以通过引用或引用链,从可达值(也称为根)访问到,则认为这个值时可达的
如:
比方说,如果局部变量中有一个对象,并且该对象具有引用另一个对象的 property,则该对象被认为是可达的。而且它引用的内容也是可达的。
2. 举例
当前函数的局部变量和参数
嵌套调用时,当前调用链上所有函数的变量与参数
全局变量
等等
3.垃圾回收的算法
基本算法被称为 “mark-and-sweep”
3.1 垃圾收集器找到所有的根,并"标记"它们
3.2 并遍历标记来自它们的所有参考
3.3 遍历到标记的对象并标记它们的引用,所有被遍历到的对象都会被记住,以免将来再次遍历到同一个对象
3.4 一直这样,直到有未访问的引用
3.5 没有被标记的所有对象都被删除
4.优化
分代收集 —— 对象被分成两组:『新的』和『旧的』。许多对象出现,完成他们的工作并快速释放,他们可以很快被清理。那些长期存活下来的对象会变得『老旧』,而且检查的次数也会减少。
增量收集 —— 如果有许多对象,并且我们试图一次遍历并标记整个对象集,则可能需要一些时间并在执行过程中带来明显的延迟。所以引擎试图将垃圾收集工作分成几部分来做,然后将这几部分逐一处理。这需要他们之间额外的标记来追踪变化,但是会有许多微小的延迟而不是大的延迟。
闲时收集 —— 垃圾收集器只会在 CPU 空闲时尝试运行,以减少可能对代码执行的影响。

对象的原始值转换

  • 对象—boolean 所有对象都是true
  • 对象—number 发生在对象相减或应用数学函数时
  • 对象—string 输出对象和类似的上下文转换中
    当一个对象被用在需要原始值的上下文中时,例如,在 alert 或数学运算中,它会使用 ToPrimitive 算法转换为原始值(标准)该算法允许我们使用特殊的对象方法自定义转换。
		1.string 当一个操作希望是一个字符串时
            // 1.1 输出时
            alert(obj);
            // 1.2 使用对象作为属性键
            anotherObj[obj] = 123;
        2.number 当一个操作需要一个数字时
            // 2.1 显示转换
            let num = Number(obj);
            // 2.2 数学运算
            let n = +obj;
            let delta =date1-date2;
            let greater = user1>user2;
        3.default 在少数情况下不确定期望的类型时
            // +
            let total = car1 +car2;     //类型时数字和字符串都可以
            // == 
            if(user == 1){}     //对象与一个字符串,数字或符号进行比较时

为了进行转换,JavaScript尝试查找并调用这三个对象方法

  • 调用objSymbol.toPrimitive ,如果存在
  • 否则如果暗示是"string"
    尝试调用obj.toString()和obj.valueOf()
  • 否则如果暗示是"number"或"default"
    尝试调用 obj.valueOf()和obj.toString()
Symbol.toPrimitive

名为 Symbol.toPrimitive 的内置符号用来命名转换方法

		obj[Symbol.toPrimitive] = function(hint){
            // 返回一个原始值
            // hint="string","number",和"default"中的一个
        }
 	<script>
        let user = {
            name:'叶叶',
            money: 1000,
            [Symbol.toPrimitive](hint){
                alert(`hint: ${hint}`);
                return hint == 'string'? `{name: "${this.name}"}` : this.money;
            }
        };

        alert(user);    // object --- >string
        alert(+user);   // object --- >number
        alert(user+500);// object --- > default */
        /* 2.toString/vauleOf */
        let user2 = {
            name:'花花',
            money:2000,

            toString(){
                return `{name:"${this.name}"}`;
            },

            // 对于number或default
            valueOf(){
                return this.money;
            }
        };
        alert(user2);    // object --- >string
        alert(+user2);   // object --- >number
        alert(500+user2);// object --- > default
    </script>

构造函数和new操作符

构造函数(在技术上是常规函数)

  • 他们的首字母用大写字母命名。
  • 它们只能用 “new” 操作符来执行。
  • 通常,构造函数没有return语句,它的任务是将必要的东西写入this,并自动转换
  • 如果有return 语句,return
    对象;返回该对象,否则返回this
    当一个函数作为new User()执行时,它会执行以下步骤
  1. 一个新的空对象被创建并分配给this
  2. 函数体执行,通常会修改this,为其添加新的属性
  3. 返回this的值
    双语法构造函数
    在一个函数内部,我们可以使用new.target属性来检查它被调用时,是否使用了new,常规调用为空,如果通过new 调用,就等于函数
<script>

        function User(){
            alert(new.target);
        }
        new User();
        User();
        function User2(){
            if(!new.target){
                return new User2();
            }
            this.name = name;
        }
    </script>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章