关于JavaScript对象我要知道的事

  • 与某些语言把原始类型存储在栈中,把引用类型存储在堆中不一样,JavaScript使用一个变量对象来追踪变量的生存周期:原始值直接保存在这个对象内,引用类型的指针(指向这个引用类型在内存中的地址)被保存在这个对象内。数组

  • 因为上面的缘由,当把一个引用类型赋值给一个变量时,只是把它的指针赋值给了这个变量。框架

  • 解除对一个对象的引用的最好的方法是将对象变量赋值为null,这样垃圾收集机制就能更好的处理无用的垃圾了。例如:函数

    let pointer = {};  // 建立一个引用了对象的变量 pointer, 称为对象变量
    
    // do something with pointer
    
    pointer = null;  // 将对象变量赋值为 null, 它引用的对象会被垃圾收集,那块内存就能空出来
    复制代码

    上面的代码用一个pointer变量引用了一个对象,在将pointer变量设置为 null以后,垃圾收集器就能更好的处理那个已经没有了引用的对象。ui

  • 对于全部的引用类型,使用字面量形式建立的对象并无调用构造函数,可是JavaScript引擎在背后作的工做和调用了构造函数时同样。例如对于一个普通对象:spa

    // 使用对象字面量的方式建立一个对象
    let person = {
        name: '王大锤',
        age: 30
    };
    
    /* 等价于下面使用构造函数建立的对象 */
    
    // 使用构造函数建立一个对象
    let person = new Object();
    person.name = '王大锤';
    person.age = 30;
    复制代码

    又例如对于一个数组:指针

    let arr = [1, 2, 3]; // 使用字面量形式建立一个数组
    
    /* 等价于下面使用构造函数的形式建立数组 */
    
    let arr = new Array(1, 2, 3);
    复制代码
  • 使用Array.isArray方法鉴定一个变量是否是数组,使用instanceof操做符也能够判断一个变量的值是否是数组的实例,可是若是变量在同一个网页的不一样框架之间传递,因为每一个框架都有本身的环境,因此后者可能没法获得准确的结果,可是前者始终能获得正确的结果。code

    let arr = [1, 2, 3]; 
    console.log(Array.isArray(arr), arr instanceof Array);  // true true
    复制代码
  • 对原始类型的值使用instanceof操做符判断其对应的类型,总会返回false,这是由于原始类型虽然有打包操做,可是在使用instanceof进行判断时,打包操做就已经结束了,此时打包出来的临时对象已经被销毁,因此结果为false对象

    let name = 'Jack Ma';
    let age = 40;
    let flag = false;
    
    console.log(name instanceof String);  // false
    console.log(age instanceof Number);   // false
    console.log(flag instanceof Boolean); // false
    复制代码
  • 函数存在一个被称为[[call]]的内部属性,内部属性没法经过代码访问,这里使用双中括号来标注此类属性名。[[call]]属性是函数的独有属性,并且typeof操做符对具备[[call]]属性的对象返回function,这就是使用typeof判断函数类型的原理。排序

  • 函数声明能够被提高是由于引擎提早知道了函数的名字;函数表达式是使用匿名函数定义的,变量名只是引用了这个匿名函数,虽然能够经过变量对函数进行调用,但变量名并非函数的名字,因此没法进行提高。ip

  • sort方法在排序的时候会将对象转换成字符串而后再比较,因此在不指定比较函数的时候不能对纯数字数组进行准确排序。

  • 函数也有length属性,表示函数指望的参数个数,也就是函数声明的形参个数。

  • 函数和方法的区别:其实这两个名称指的都是函数,只是当一个函数是一个对象的属性时,相对于这个对象,函数就被称为了方法。

  • 当属性***第一次***被添加给对象时,JavaScript会调用对象名为[[put]]的内部方法来建立这个属性,并赋值。

  • 当属性被添加给对象以后,再改变属性的值时,不会再调用再调用[[put]]方法了,这时会调用[[set]]这个内部属性。

    let obj = {};  //定义一个对象,这个对象没有任何用户本身建立的属性 
    
    obj.name = 'Jack M';  // 调用了 [[put]] 方法,由于 obj 原本没有 name 属性,这里给它添加了 name 属性
    obj.name = 'Mask';    // 调用了 [[get]] 方法,由于这时已经存在了name属性,这里只是从新给属性赋值
    复制代码
  • 若是想删除对象的某个属性,应使用delete操做符。注意:直接将属性设置为null是没法删除这个属性的,这样只是给属性赋了一个新值为null

    // 建立一个带有 name 属性的对象
    let obj = {
        name: 'Yuri'
    };
    
    // 将 name 属性值设为 null,没法删除这个属性,只是给它赋值为 null, 即 obj.name === null
    obj.name = null;
    console.log(obj.name === null);  // true
    
    // 使用 delete 关键词能够真正删除属性
    delete obj.name;
    console.log(obj.name);  // undefined
    console.log('name' in obj);  // false
    复制代码
  • 想遍历对象的属性时,能够用两种方法:

    1. for ... in ... :迭代对象的可枚举的***属性名***,可枚举属性是指[[Enumerable]]值为 true 的属性
    2. Object.keys(object):这个方法返回对象的全部可枚举属性的属性名组成的数组。
    // 建立一个带有两个自有属性的对象
    let obj = {
        name: 'Yuri',
        age: 40,
        speak: 'You will obey ...'
    };
    
    
    for(let propertyName in obj){  // 每次都会将 对象的属性名赋值给 propertyName
        console.log(propertyName);
    }
    // name
    // age
    // speak
    
    
    let allProperties = Object.keys(obj);  // 得到 obj 对象的全部可枚举属性的属性名
    console.log(allProperties);  // ["name", "age", "speak"]
    复制代码

    注意:这两个方法取得的可枚举属性是有差异的,for in方法会遍历对象的原型链,而Object.keys()方法只会涉及到对象自己的属性,不会访问原型链。

  • 对象的大部分自带的属性的[[Enumerable]]的值都是false,即不可遍历,用实例对象的propertyIsEnumerable方法能够判断一个属性是否是可枚举的:

    console.log(obj.propertyIsEnumerable('name'));  // true
    console.log(obj.propertyIsEnumerable('age'));   // true
    console.log(obj.propertyIsEnumerable('speak')); // true
    复制代码
  • 使用构造函数建立对象时,若是不须要传递参数时,能够不加小括号:

    // 定义一个构造函数
    function Person(name){
        /* xxx */
    }
    
    let p1 = new Person();
    let p2 = new Person;  // 不加小括号
    
    console.log(p1 instanceof Person, p2 instanceof Person);  // true true
    复制代码
相关文章
相关标签/搜索