【JS】JS数据类型--object(二)

212 阅读7分钟

JS的数据分七个类型:四基两空一对象,而对象又分为很多类

一、对象有很多类

(一) 第一类:函数(对象)

1. 函数的定义方式

(1)正规写法:let f1 = new Function('x','y','return x+y')(name:anonymous)

函数是个对象,对象都是由构造函数构造出来的。所以从上式可以发现任何一个函数都是由“爸爸构造函数”Function函数构造出来的。构造函数这个对象的构造函数是“爸爸构造函数”Function函数

(2)具名函数:function add(x,y) {return x+y}(name:add)

(3)匿名函数:let f1 = function(x,y){return x+y}(name:f1)

把具名函数的函数名去掉就是匿名函数,也叫函数表达式,是等号右边这一部分。因为没有名字,所以必须给这个函数表达式挂在一个名字f1上。

(4)简便写法:let f1 = (x,y) => x+y(name:f1)

2. “爸爸构造函数”Function()函数构造出来的函数共分为两种:构造函数和普通函数

(1) 构造函数

①是指可以创建出一个对象的函数。

②比如Function()函数就是一个构造函数,他用于构造任何函数(函数也是对象呀)。我把它称为“爸爸构造函数”

③“爸爸构造函数”Function()函数又构造出了其他构造函数

④ 比如let Array = new Function(........)

  • 这是用于构造数组对象的Array()函数

⑤比如let Object = new Function(........)

  • 用于构造普通对象的Object()函数

⑥比如let Square = new Function('width','return this.width=width')或者function Square(width){this.width=width}

  • 我们在例子中写的用于构造方块对象的Square()函数

⑦构造函数构造出来的对象,首字母要小写。比如一个数组对象array1 = new Array(1,2,3),比如一个普通对象obj1 = new Object(),比如一个方块对象square1 = new Square()

(2) 普通函数

  • “爸爸构造函数”Function()函数也构造出普通函数
  • 比如let add = new Function('x','y','return x+y')就是构造出了一个普通函数对象

3、属性

(1)自身属性

  • 'name'
  • 'length'

(2)共有属性

  • 'call'
  • 'apply'
  • 'bind'

(二) 第二类:普通对象

1. 定义方式

  • 正规写法:let 对象名 = new 0bject({'name': 'frank'})
  • 简便写法:let 对象名 = { 'name': 'frank', 'age':18 }
  • 匿名写法:console.log({ 'name': 'frank', 'age':18 })

(三) 第三类:数组对象

1. 定义方式

  • 正规写法:let 数组名 = new Array(1,2,3)//元素为1,2,3
  • 正规写法:let 数组名 = new Array(3)//长度为3
  • 简便写法:let arr = [1,2,3]

2. 属性

(1)自身属性

  • '0'
  • '1'
  • '2'
  • 'length'

(2)共有属性(MDN自己去查用法)

  • 'push'
  • 'pop'
  • 'shift'
  • 'unshift'
  • 'join'

二、window

  1. 浏览器提供window,很多东西挂在了window上

  2. window变量是一个容器,用来存放window对象的地址

  3. window对象存在Heap堆。

  4. window对象里有很多个属性,比如

  • 属性console指向一个对象;
  • 属性Object指向一个对象,这个对象就是Object构造函数,着重学习这个对象的prototype属性,它指向所有object对象的原型
  • 属性Array指向一个对象,这个对象就是Array构造函数,着重学习这个对象的prototype属性,它指向所有数组对象的原型
  1. window是个对象,他是由Window函数构造的

三、用构造函数+原型来构造对象

1、创建一个构造函数的全过程(记得还有notability笔记:构造函数new)

let Dog = new Function('width','return this.name=name')
 //我们要用“爸爸构造函数”window.Function写一个构造函数Dog(),我们需要写入一个参数name,之后会把这个name赋值给this的name属性(this用来指代我们将要创建的新对象。),写在这里面的属性都算是自身属性。
Dog.prototype.wangwang = function(){console.log('狗在汪汪叫')}//因为Dog是个函数所以是个对象,所以有prototype属性。现在往prototype属性里面新加一个属性wangwang,这个wangwang属性的值是一个可以打印出“狗在汪汪叫”的函数。写在这里的属性都将是以后创建对象的共有属性。
Dog.prototype.run = function(){console.log('狗在跑')}//同上
let dog1 = new Dog('小兵')

当我们使用new Dog('小兵')是,其实干了四件事

①自动创建一个空对象

②自动将该空对象的原型指向 X.prototype(即将 X.prototype 保存的地址复制到空对象.__proto__里)这时空对象就有了共有属性

③自动将空对象作为this关键字运行构造函数。这时空对象就有了自身属性

④自动return this,返回我们创建好了的对象。命名为dog1。

2、同理

Object函数、Array函数全都如同上面。只不过他们在js创建时已经写好啦。

3、原型的理解新生对象.__proto__ === 构造函数.prototype

  1. 每个对象出生就有prototype属性和__proto__隐藏属性。

  2. 我们只研究构造函数(大写字母开头)的prototype属性和新生对象(小写字母开头)的_ _proto_ _属性

  3. 构造函数X因为是个对象,所以有prototype属性。这个prototype属性保存了一个对象的地址,这个对象就称为原型!原型里保存了所有x对象的共有属性

  4. 被构造函数X构造出来的x对象,他有一个隐藏属性__proto__因为和X.prototype属性一样保存了相同的地址,所以也指向原型。这样x对象也就可以使用这些共有属性啦。

  5. 所有x对象的原型x.__proto__ === X.prototype

  6. 原型让你无需重复声明共有属性,省代码,省内存

  7. prototype__proto__都存着原型的地址,只不过就当做prototype挂在构造函数上, __proto__挂在每个新生成的对象上。

  8. 原型的地址被保存在新生对象的__proto__属性,也被保存在相应构造函数的prototype属性

4、Object构造函数

  • 构造函数Object函数的prototype属性指向所有object对象的原型

  • Object函数构造出来的所有对象的__proto__属性也指向这个原型

  • 所有object对象的原型:obj.__proto__ === Object.prototype

  • Object.prototype 是所有对象的原型!!(除了它自己),但 Object.prototype 有可能不是第一层原型,而是第二层原型,比如 arr 的第一层原型是 Array.prototype,第二层原型才是 Object.prototye.比如构造函数Array的一层原型是Fuction.prototype,第二层原型是Object.prototye这就是原型链!!,看下图

  • Object 的原型是指 Object.__proto__===Function.prototype,不是 Object.prototype,因为 Object.prototyeObject 构造出来的对象的原型

5、Array构造函数

  • 构造函数Array函数的prototype属性指向所有数组对象的原型
  • 由Array函数构造出来的所有数组对象的__proto__属性也指向这个原型
  • array1.__proto__ === Array.prototype
  • 注意:第一层原型是 Array.prototype,第二层原型是 Object.prototye
  • array1.__proto__.__proto__ === Object.prototype

6、prototype属性里还有个constructor属性,表示构造者是哪个构造函数

①新生对象的构造者是他的构造函数

  • 比如数组对象array1的构造者是Array构造函数

②所有函数的构造者都是“爸爸构造函数”window.Function

  • 比如Array构造函数的构造者是“爸爸构造函数”window.Function

  • 比如“爸爸构造函数”window.Function因为是个函数,所以他也是由“爸爸构造函数”window.Function构造的。
  • 自己构造了自己,为什么呢?其实是浏览器构造了“爸爸构造函数”window.Function,只不过浏览器把“爸爸构造函数”window.Function的构造者指定为他自身“爸爸构造函数”window.Function。我笑了。

③window是个对象,他是由Window函数构造的(不要深究了

7、一些问题

  1. Object.prototype是所有对象的原型,也是个对象
  2. 那他是由哪个构造函数构造出来的?不知道!
  3. 那他的原型是什么?null!空!就是这样指定的!

四、为什么对象要有这么多类

理由一

  • 有很多对象拥有一样的属性和行为,需要把它们分为同一类
  • 如array1和array2
  • 这样创建类似对象的时候就很方便

理由二

  • 但是还有很多对象拥有其他的属性和行为,所以就需要不同的分类
  • 比如Array / Function是不同的分类
  • 而Object创建出来的对象,是最没有特点的对象

五、所以原型就是来给对象分类的!

六、用class来构造对象

class Dog {
  constructor(name) {
    this.name = name;
  }
  wangwang() {
  console.log('狗在汪汪叫')
  }
  run() {
  console.log('狗在跑')
  }
}