「前端基础」JS对象部分

    科技2022-08-01  93

    文章目录

    1 定义2 键名ES6 1.4 表达式还是语句?2 属性的操作2.1 属性的读取2.2 属性的赋值2.3 属性的查看2.4 属性的删除:delete 命令 3 with4 后面5 null

    1 定义

    对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。

    键名又称为属性或属性名(property)键值又称为属性值(value) //常用写法 let obj = {'name': 'zxc', 'age': 23} //规范写法 let obj2 = new Object({'name': 'zxc', 'age': 23})

    2 键名

    对象的所有键名都是字符串(ES6 又引入了 Symbol 值也可以作为键名),不是标识符, 可以包含任意字符。引号可省略,省略之后就只能写标识符和纯数字,就算引号省略了, 键名还是字符串。

    如果键名是数值,会被自动转为字符串。如果键名不符合标识符的条件(比如第一个字符为数字,或者含有空格或运算符),且也不是数字,则必须加上引号,否则会报错。如果一个属性值为函数,通常把这个属性称为“方法”。如果属性值还是一个对象,就形成了链式引用。

    对象的属性之间用逗号分隔,最后一个属性后面可以加逗号(trailing comma),也可以不加。

    属性可以动态创建,不必在对象声明时就指定。

    ES6

    对象定义时,需要变量作为属性名,属性值需要用[]来包裹住。

    let name = 'age' let info = { [name] = 18 } info // {age: 18}

    由来:

    let name = 'age' let info = {} info[name] = '18' info // {age: 18}

    ES6之前,对象定义完后,变量可以作为属性名,来动态定义属性。因此借鉴这部分用[]方式。

    1.4 表达式还是语句?

    对象采用大括号表示,这导致了一个问题:如果行首是一个大括号,它到底是表达式还是语句?

    { foo: 123 }

    JavaScript 引擎读到上面这行代码,会发现可能有两种含义。

    第一种可能是,这是一个表达式,表示一个包含foo属性的对象;

    第二种可能是,这是一个语句,表示一个代码块,里面有一个标签foo,指向表达式123。

    疑问: chrome直接输出{ foo: 123 }, 是一个对象. 答: 因为 chrome 欺骗了我们, 用 firefox 可以验证下面这句话,JS是只花了10天就设计出来的语言。

    为了避免这种歧义,JavaScript 引擎的做法是,如果遇到这种情况,无法确定是对象还是代码块,一律解释为代码块。

    { console.log(123) } // 123

    上面的语句是一个代码块,而且只有解释为代码块,才能执行。

    如果要解释为对象,最好在大括号前加上圆括号。

    因为圆括号的里面,只能是表达式,所以确保大括号只能解释为对象。

    ({ foo: 123 }) // 正确 ({ console.log(123) }) // 报错

    这种差异在eval语句(作用是对字符串求值)中反映得最明显。

    eval('{foo: 123}') // 123 eval('({foo: 123})') // {foo: 123}

    2 属性的操作

    2.1 属性的读取

    读取对象的属性,有两种方法:

    点运算符:obj['key']方括号运算符:obj.key

    请注意,如果使用方括号运算符,键名必须放在引号里面,否则会被当作变量处理(数字键可以不加引号,因为会自动转成字符串)。

    方括号运算符内部还可以使用表达式。

    注意,数值键名不能使用点运算符(因为会被当成小数点),只能使用方括号运算符。eg: obj.123

    2.2 属性的赋值

    点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。

    批量赋值: let obj = {} Object.assign(obj, {age: 23, gender: 'men'}) 无法通过自身修改或增加共用属性: let obj = {}, obj = {}//共用toString属性 obj.toString = 'xxx'//只会在改obj自身属性 obj2.toString //还是原型上的 偏要修改或增加原型的属性:一般来说不要修改, 会引起很多问题, 这也是JS的脆弱之处。 obj.__proto__toString = 'xxx' //推荐使用下面这种 Object.prototype.toString = 'xxx'//推荐使用这种 修改原型链(隐藏属性): //不推荐使用__proto__这种 let person = {name: 'Jonathan Ben'} let person2 = {name: 'Jonathan Lee'} let common = {country: 'China'} person.__proto__ = common person2.__proto__ = common //推荐使用这种(ES6),规范的写法:要改就一开始就要改, 别后面再改,不然非常影响性能。 //Object.create尽量初始化空对象, 然后再进行追加, 这样方便. let person = Object.create(common) person.name = 'Jonathan Ben' let person2 = Object.create(common) person2.name = 'Jonathan Lee'

    2.3 属性的查看

    查看一个对象本身的所有属性,可以使用Object.keys方法。

    查看自身所有属性名:Object.keys(obj)

    查看自身所有属性值:Object.values(obj)

    查看自身以及原型(共用属性):console.dir(obj)推荐这种, obj.__proto__推荐前面这种

    判断一个属性是自身的还是原型的: obj.hasOwnProperty('toString')

    原型:

    原型里面存着对象的共用属性比如obj的原型就是一个对象obj.__proto__存着这个对象的地址

    原型也是对象:

    原型也是有原型的原型是对象的跟虽然原型有原型, 但是为null let obj = {} obj.__proto__ // {constructor: ƒ, __defineGetter__: ƒ, ... } obj.__proto__.__proto__ // null '__proto__' in obj.__proto__ // true

    2.4 属性的删除:delete 命令

    delete命令用于删除对象的属性,删除成功后返回true。

    var obj = { p: 1 }; Object.keys(obj) // ["p"] delete obj.p // true obj.p // undefined Object.keys(obj) // []

    注意,删除一个不存在的属性,delete不报错,而且返回true。因此,不能根据delete命令的结果,认定某个属性是存在的。

    var obj = {}; delete obj.p // true

    只有一种情况,delete命令会返回false,那就是该属性存在,且不能删除。

    var obj = Object.defineProperty({}, 'p', { value: 123, configurable: false }); obj.p // 123 delete obj.p // false

    上面代码之中,对象obj的p属性是不能删除的,所以delete命令返回false(关于Object.defineProperty方法的介绍,请看《标准库》的 Object 对象一章)。

    另外,需要注意的是,delete命令只能删除对象本身的属性,无法删除继承的属性(关于继承参见《面向对象编程》章节)。

    var obj = {}; delete obj.toString // true obj.toString // function toString() { [native code] }

    可以通过in来判断对象有哪些属性。

    let obj = { 'name': 'ben' } 'name' in obj // true 'age' in obj // false

    不能用obj.xxx === undefined 来判断xxx是否为obj的属性,这只能判断属性的值为undefined。

    3 with

    它的作用是操作同一个对象的多个属性时,提供一些书写的方便。

    // 例一 var obj = { p1: 1, p2: 2, }; with (obj) { p1 = 4; p2 = 5; } // 等同于 obj.p1 = 4; obj.p2 = 5; // 例二 with (document.links[0]){ console.log(href); console.log(title); console.log(style); } // 等同于 console.log(document.links[0].href); console.log(document.links[0].title); console.log(document.links[0].style);

    注意,如果with区块内部有变量的赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量。

    var obj = {}; with (obj) { p1 = 4; } obj.p1 // undefined p1 // 4

    这是因为with区块没有改变作用域,它的内部依然是当前作用域。这造成了with语句的一个很大的弊病,就是绑定对象不明确。

    with (obj) { console.log(x); }

    单纯从上面的代码块,根本无法判断x到底是全局变量,还是对象obj的一个属性。这非常不利于代码的除错和模块化,编译器也无法对这段代码进行优化,只能留到运行时判断,这就拖慢了运行速度。

    建议不要使用with语句,可以考虑用一个临时变量代替with。

    with(obj1.obj2.obj3) { console.log(p1 + p2); } // 可以写成 var temp = obj1.obj2.obj3; console.log(temp.p1 + temp.p2);

    4 后面

    //可以直接console.log一个无名对象, 注意:不要和lable混淆了. console.log({'name': 'zxc', 'age': 23}) {name: "zxc", age: 23}

    对象的隐藏属性:每一个对象都有隐藏属性,隐藏属性中存储这共用属性组成的对象的地址,共用属性组成的对象叫做原型,也就是说, 隐藏属性存储着原型的地址。

    5 null

    简单基本类型:string、number、boolean、null和undefined

    复杂基本类型:函数、数组、内置函数(String、Number、Boolean、Object、Function、Array、Date、RegExp 和 Error) 疑问:symbol呢?

    null 有时会被当做一种对象类型,但是这其实只是 JavaScript 语言本身的一个 bug,即对 null执行typeof(null)时会返回字符串"object"。实际上,'null本身是简单基础类型。原因是这样的,不同的对象在底层都表示为二进制,在 JavaScript 中二进制前三位都为 0 的话会被判 断为 object 类型,null 的二进制表示是全 0,自然前三位也是 0,所以执行 typeof 时会返回"object"。

    Processed: 0.010, SQL: 8