前言
是的,面向对象和原型(链)也是一度让我陷入难以理解的边缘,不过我没有停留太久,直接跳过,做了项目,加上看了老师们的知乎文章之后,今天终于输出了对面向对象、prototype
和__proto__
的理解,过程中可能啰嗦,whatever,同步和老师做完了题目之后,蜜汁自信又回来了哈哈哈哈😂~
一、JS对象
1、什么是对象
JS 中的对象:是一系列无序 key: value 的集合
先看下面这个代码:
var obj = { a: 1, b: 2} //json对象。字面量创建的对象
var person = {
name: 'hunger',
sayName: function(){
console.log('My name is hunger')
} //sayName对应的值是一个函数
}
2、获取对应属性的值
通过 对象.属性
来获取对应属性的值
console.log(person.name)
person.sayName()
(1)那么,函数是一个对象?
function sum(a, b){
return a + b
}
如图:使用 函数名(对象).属性
进行查看该对象属性是否有值
总结:函数也是一个JS对象
(2)同理,数组是对象?
a = [1,2,3]
如图:
总结:数组也是一个JS对象
二、面向对象编程
1、传统面向编程
wiki的解释
OOP(),是一种编程思路或编程方法,基于一个对象,该对象包含数据(一般即属性),以及一些执行过程的代码(即方法)。对象的方法,可以从外部去访问,并且可以去修改,调用此方法去修改对象的数据
(1)面向过程的写法
拧钥匙()
联通电路()
火花塞点火()
活塞运动()
内燃机启动()
司机挂挡()
变速箱工作()
踩油门()
活塞运动加快()
刹车解除()
连杆传输动力到轮子()
轮子运转()
面向过程的思路:一次性实现所有的流程
(2)面向对象的写法
Car.拧钥匙()
Car.挂挡()
Car.踩油门()
面向对象的思路:把某个功能看成一个整体(对象),通过调用对象(如开车)的某个方法来启动功能。在用的时候不去考虑这个对象内部的实现细节,在去实现这个对象细节的时候不用管谁在调用
2、构造一个对象
比如我们用字面量构造了,暴露了这个对象的具体实现方法的细节:
var obj1 = {
nick: 'Byron',
age: 20,
printName: function(){
console.log(obj1.nick);
}
}
var obj2 = {
nick: 'Casper',
age: 25,
printName: function(){
console.log(obj2.nick);
}
}
问题:这样构造有两个明显问题
- 太麻烦了,每次构建一个对象都是复制一遍代码
- 如果想个性化,只能通过手工赋值,使用者必需了解对象详细使用函数做自动化
function createObj(nick, age){
var obj = {
nick: nick,
age: age,
printName: function(){
console.log(this.nick);
}
};
return obj;
}
var obj3 = createObj('Byron', 30);//创造一个对象去赋值对应参数
obj3.printName();
问题:这种方法解决了构造过程复杂,需要了解细节的问题,但是构造出来的对象类型都是Object,没有识别度
3、New一个对象
一个函数中含有要调用的对象共同属性,然后声明多个对象,就能相对应地调用函数对象中的属性值
function people(name,age){
this.name=name
this.age=age
}
var obj1 = new people(hunger,2)
var obj2 = new people(nick,10)
以上代码的执行过程如下:
(1)执行 new People
- 创建一个空对象 {},假设名字是 tmpObj,这里实际上是new person
- 执行 People 函数,执行过程中对 this 操作就是对 tmpObj 进行操作
- 函数执行完后返回刚刚创建的 tmpObj
(2)把 tmpObj 赋值给 obj1和obj2 ( obj1和obj2也指向同一个对象)
↓↓
当你在写一个new对象的表达式时,其实就是在写一个构造函数,如写函数F时,都会自动添加prototype属性,这是一个对象new一个对象,创建一个空对象,这个对象中的内部属性__proto__
指向这个函数类的prototype,执行函数时,初始化this(初始化this实质上也是给空对象初始化,然后函数return出这个已初始化的对象(实例),然后再把实例整体地赋值给一个变量,如p
↑↑
4、构造函数
- 任何函数使用new表达式就是构造函数
- 每个函数都自动添加一个名称为prototype属性,这是一个对象
- 每个对象都有一个内部属性
__proto__
(规范中没有指定这个名称,但是浏览器都这么实现的) 指向其类型的prototype属性,类的实例也是对象,其(指实例)__proto__
属性指向“类”的prototype
5、prototype
原型,是可以把一些公共属性放在里面。这里的可以考虑放入的公共属性就可以默认参数
image
分析原型图:
- 任何函数只要声明,就有prototype这个属性,也是一个对象,对象中含有constructor和proto
- 如果调用:函数名.prototype.constructor,指的也还是这个函数
- 函数中的prototype是一个对象,说明可以赋值,增加一些属性
- 如果通过函数去创建一个新的空对象,就会在这个新对象中出现:proto,而这个属性则是指向了函数中的prototype这个对象,假如:
p1.proto=函数中的prototype
p2.proto=函数中的prototype
- 说明,实例中的某些属性可以通过prop访问到其类型的prototype属性,这就意味着类的prototype对象可以作为一个公共容器,供所有实例访问。
我们刚才的问题可以通过这个手段解决:
- 所有实例都会通过原型链引用到类型的prototype
- prototype相当于特定类型(函数)所有实例都可以访问到的一个公共容器
- 重复的东西移动到公共容器里放一份就可以了
看一下的代码:
function Person(nick, age){
this.nick = nick;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.nick);
}
var p1 = new Person();
p1.sayName();
这里我们将一个共有属性sayName加入了函数中的prototype,即
Person.prototype.sayName = function(){
console.log(this.nick);
}
实例就可以从这个公共容器中设定的属性找到重复的公共属性值。
网友评论