侧边栏壁纸
博主头像
MicroMatrix博主等级

曲则全,枉则直,洼则盈,敝则新,少则得,多则惑。是以圣人抱一为天下式。不自见,故明;不自是,故彰;不自伐,故有功;不自矜,故长。夫唯不争,故天下莫能与之争。古之所谓“曲则全”者,岂虚言哉!诚全而归之。

  • 累计撰写 80 篇文章
  • 累计创建 21 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

《你不知道的JavaScript》第三章笔记

蜗牛
2024-01-17 / 0 评论 / 0 点赞 / 28 阅读 / 6950 字 / 正在检测是否收录...

语法

JavaScript中对象的定义方式有2种,声明或构造的2种方式。

  1. 对象的文字形式
    let a = {name:"micromatrix"}
    
  2. 对象的构造形式
    let obj = new Object()
    obj.name = "micromatrix"
    

类型

JavaScript中的简单基本类型分别为:

  • string
  • number
  • boolean
  • undefined
  • null
  • object

简单基本类型不是对象,但是平常使用中能用"1234".length这种语法是由于JavaScript中自动把基本类型转化成了内置类型。
内置类型分别为:

  • String
  • Number
  • Boolean
  • Array
  • Function
  • Object
  • Date

上面说的只是一部分,其实随着ES6等后续的JS规范更新,像BigIntSymbol都被加入了。这些内置类型实际上就是一些内置函数,它们可以被当作构造函数使用。

var strPrimitive = "I am a string";
typeof strPrimitive; // "string"
strPrimitive instanceof String; // false
var strObject = new String( "I am a string" );
typeof strObject; // "object"
strObject instanceof String; // true
// 检查 sub-type 对象
Object.prototype.toString.call( strObject ); // [object String]

值得注意的是由于内置类型和基础类型感觉就像首字母大写了一样,但是其中null 和 undefined 没有对应的构造形式,它们只有文字形式。相反,Date 只有构造,没有文字形式。

内容

对象的内容是有一些存储在特定命名位置的值组成,也就是属性。但是注意的是在JS引擎内部中,这些值的存储位置多种多样的,一般不会存在对象容器内部,存储在对象内部的这个属性名称,他们就像指针一样,指向这些值真正的存储位置。
访问对象属性的值有2种方式,使用.或者[]操作符

var myObject = {
  a:2
};
myObject.a; // 2
myObject["a"]; // 2

.a被称为"属性访问",而[a]被称为"键访问",实际上他们访问的使用同一个位置。
在对象中,属性名永远都是字符串。即使使用数字作为属性名,它首先会被转换为一个字符串。

可计算属性名

ES6 增加了可计算属性名,可以在文字形式中使用 [] 包裹一个表达式来当作属性名

var prefix = "foo";
var myObject = {
  [prefix + "bar"]:"hello",
  [prefix + "baz"]: "world"
}
myObject["foobar"]; // hello
myObject["foobaz"]; // world

属性和方法

访问的对象属性是一个函数,有的人的叫法是方法,因为在类中通常被称为方法。
作者认为对象内部引用的函数被称为"方法"这不太合适,因为JS中函数永远不会属于一个对象。这主要是由于有些函数具有this引用,有时候这些this确实是指向调用位置的对象引用。但是this是在运行的时候根据调用位置动态绑定的,所以函数和对象的关系最多是间接关系。

数组

数组是对象,也支持[]。不过由于数组有一套更加结构化的存储机制。[]访问的是下标值,并且下标值是整数。
你也可以给数组添加属性,但是这并不会改变数组的length。
可以把数组当作一个普通的键 / 值对象来使用,并且不添加任何数值索引,但是这并不是一个好主意。数组和普通的对象都根据其对应的行为和用途进行了优化,所以最好只用对象来存储键 / 值对,只用数组来存储数值下标 / 值对。

复制对象

  1. 深拷贝
  2. 浅拷贝

这2种拷贝的最大区别在于,浅拷贝对基础值复制一遍,但是对内置类型的值仅仅是复制了对象属性上的引用。而深拷贝要复制引用对象上的值。
注意的是如果你在深拷贝仅仅考虑复制所有的值的话,可能会遇到循环引用的对象复制,这样的话会使得程序进入死循环。
而巧妙的复制方法:

var newObj=JSON.parse(JSON.stringfy(someObj));

浅拷贝: object.assign(...)第一个参数是目标对象,之后还可以跟多个源对象。

属性描述符

从ES5开始,所有的属性具有了属性描述符。

var myObject = {
  a:2
};
Object.getOwnPropertyDescriptor( myObject, "a" );
// {
  // value: 2,
  // writable: true,
  // enumerable: true,
  // configurable: true
// }

可以使用Object.defineProperty来创建普通属性并且设置属性描述符的值

var myObject = {};
Object.defineProperty( myObject, "a", {
  value: 2,
  writable: true,
  configurable: true,
  enumerable: true
} );
myObject.a; // 2

不变性

如果想让属性或者对象是不可改变的,有多种方法可以实现。注意的是,所有的方法创建的都是浅不变性。也就是只会影响目标对象和它的直接属性,如果目标对象引用了其他对象(数组、函数等),其他对象的内容不受影响。

  1. 对象常量
    使用属性描述符种的writable:falseconfigurable:false创建一个不可以修改,定义和删除的属性。

  2. 禁止拓展
    如果静止一个对象新增属性,并且保留已有属性的话。可以使用Object.preventExtensions(...)

    var myObject = {
      a:2
    }
    Object.preventExtensions( myObject );
    myObject.b = 3;
    muObject.b; // undefined 。非严格模式下静默失败,严格模式下提示Type Error
    
  3. 密封
    Object.seal(..) 会创建一个“密封”的对象,这个方法实际上会在一个现有对象上调用Object.preventExtensions(..) 并把所有现有属性标记configurable:false

  4. 冻结
    Object.freeze(..)会创建一个冻结对象,这个方法实际上会在一个现有对象上调用Object.seal(..) 并把所有“数据访问”属性标记为 writable:false,这样就无法修改它们的值。它是最高级别的不可变性运用,但是这个对象引用的其他对象则不受印象

  5. Getter和Setter
    [[Get]]和[[Put]]可以控制属性值的设置和获取。
    对象内置的[[Get]]操作首先在对象中查找是否有名称相同的属性,如果找到就会返回这个属性的值。

  6. 存在性

    var obj={a:2};
    console.log('a' in obj) ;//true
    console.log(obj.hasOwnProperty('a')//true
    

    这里主要的是in操作符会检查属性是否存在对象及其[[Prototype]]原型链中,而hasOwnProperty则只会检查属性是否在对象中,不会检查[[Prototype]]原型链。Object.propertyIsEnumberable(...)会检查给定的属性是否直接存在于对象中;
    Object.keys(...)会返回一个数组,包含所有可枚举属性;
    Object.getOwnPropertyNames(...)会返回一个数组,包含所有属性,无论它们是否可枚举。

0

评论区