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
-
浏览器提供window,很多东西挂在了window上
-
window变量是一个容器,用来存放window对象的地址
-
window对象存在Heap堆。
-
window对象里有很多个属性,比如
- 属性console指向一个对象;
- 属性Object指向一个对象,这个对象就是Object构造函数,着重学习这个对象的
prototype属性,它指向所有object对象的原型 - 属性Array指向一个对象,这个对象就是Array构造函数,着重学习这个对象的
prototype属性,它指向所有数组对象的原型
- 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
-
每个对象出生就有
prototype属性和__proto__隐藏属性。 -
我们只研究构造函数(大写字母开头)的
prototype属性和新生对象(小写字母开头)的_ _proto_ _属性 -
构造函数X因为是个对象,所以有prototype属性。这个prototype属性保存了一个对象的地址,这个对象就称为原型!原型里保存了所有x对象的共有属性
-
被构造函数X构造出来的x对象,他有一个隐藏属性
__proto__因为和X.prototype属性一样保存了相同的地址,所以也指向原型。这样x对象也就可以使用这些共有属性啦。 -
所有x对象的原型
x.__proto__ === X.prototype -
原型让你无需重复声明共有属性,省代码,省内存
-
prototype和__proto__都存着原型的地址,只不过就当做prototype挂在构造函数上,__proto__挂在每个新生成的对象上。 -
原型的地址被保存在新生对象的
__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.prototye是Object构造出来的对象的原型
5、Array构造函数
- 构造函数Array函数的
prototype属性指向所有数组对象的原型 - 由Array函数构造出来的所有数组对象的
__proto__属性也指向这个原型 array1.__proto__ === Array.prototype- 注意:第一层原型是
Array.prototype,第二层原型是Object.prototye! array1.__proto__.__proto__ === Object.prototype
6、prototype属性里还有个constructor属性,表示构造者是哪个构造函数
①新生对象的构造者是他的构造函数
- 比如数组对象array1的构造者是Array构造函数
- 比如Array构造函数的构造者是“爸爸构造函数”window.Function
- 比如“爸爸构造函数”window.Function因为是个函数,所以他也是由“爸爸构造函数”window.Function构造的。
- 自己构造了自己,为什么呢?其实是浏览器构造了“爸爸构造函数”window.Function,只不过浏览器把“爸爸构造函数”window.Function的构造者指定为他自身“爸爸构造函数”window.Function。我笑了。
③window是个对象,他是由Window函数构造的(不要深究了)
7、一些问题
- Object.prototype是所有对象的原型,也是个对象
- 那他是由哪个构造函数构造出来的?不知道!
- 那他的原型是什么?null!空!就是这样指定的!
四、为什么对象要有这么多类
理由一
- 有很多对象拥有一样的属性和行为,需要把它们分为同一类
- 如array1和array2
- 这样创建类似对象的时候就很方便
理由二
- 但是还有很多对象拥有其他的属性和行为,所以就需要不同的分类
- 比如Array / Function是不同的分类
- 而Object创建出来的对象,是最没有特点的对象
五、所以原型就是来给对象分类的!
六、用class来构造对象
class Dog {
constructor(name) {
this.name = name;
}
wangwang() {
console.log('狗在汪汪叫')
}
run() {
console.log('狗在跑')
}
}