【JS学习笔记】JS面向对象,JS原型与原型链

参考自https://juejin.im/entry/58e75555b123db15eb8b605e

参考自:https://juejin.im/post/5a94c0de5188257a8929d837

以下是小陈的阅读理解结果:

首先:JavaScript 是脚本语言. JavaScript 是一种轻量级的编程语言。 JavaScript 是可插入HTML 页面的编程代码。

JS是如何面向对象的,这个问题是我在阿里简历面时被问到的问题,没有考虑,当时的回答是因为JS中一切都是对象,每个对象都有原型啥啥的……

1,Js如何面向对象

JS中有其中7类型,数字,字符串,布尔,null,undefined,Symbol,对象。除对象以外,其他都属于原始类型

Object是键值对的集合,属于引用类型。

JS中一切皆是对象,是因为很多情况下原始类型会被自动转化为对象,而函数实际也是对象。

原型也是对象typeof Object.prototype  -- Object;

函数是特殊的对象

例如:

function foo(){console.log("in foo");};

     typeof foo === function

    但是console.log(foo),

函数的prototype有两个属性:constructor和_proto_。

foo.prototype.constructor === foo,一个函数的原型的constructor指向它本身,例如内建的Object,String,Number都指向其本身;

Object.prototype包含:

对象的_proto_会指向其构造函数的prototype。

例如,var fooObj = new foo();

fooObj._proto_ == foo.prototype

new 的作用实际上是,新创建一个对象,在这个对象上调用new关键字后面的函数(this指向此对象,虽然这里没有用到),并将对象的__proto__指向了函数的原型,返回这个对象!

如果把prototype对象看成是一个普通对象的话,那么依据上面得到的规律:

console.log(foo.prototype.__proto__ === Object.prototype);//true

 JS的内在的原型链机制,当访问一个对象的属性或方法时,JS会沿着__proto__指向的这条链路从下往上寻找,找不到就是undefined,这些原型链即图中彩色的线条。

面向对象的语法:

面向对象有三大特性:封装、继承、多态

封装即隐藏对象的一些私有的属性和方法,JS中通过设置对象的getter,setter方法来拦截你不想被访问到的属性或方法。

继承是一个面向对象的语言看起来很有吸引力的特性,之前看一些文章所谓的JS实现继承的多种方式。

从原型链的机制出发来谈继承,加入Student要继承Person,

Sudent.prototype.__proto__指向Person.prototype。

多态意味着同名方法的实现依据类型有所改变,在JS中只需要在“子类”Student的prototype定义同名方法即可,因为原型链是单向的,不会影响上层的原型。

instanceof从字面意上来说就是判断当前对象是否是后面的实例, 实际上其作用是判断一个函数的原型是否在对象的原型链上:

s1 instanceof Student;//true
s1 instanceof Person;//true
s1 instanceof Object;//true

ES6新增的语法使用了 class 和extends来使得你的代码更加的“面向对象”:

super这个关键字用来引用“父类”的constructor函数

Object.create的作用是以某一对象为原型来创建新的对象,可以简单理解为向下扩展原型链的功能,即生成了一个__proto__指向源对象的新对象。

 

2,为什么JS会有原型与原型链?

与大部分面向对象语言不同,JavaScript中并没有引入类(class)的概念,但JavaScript仍然大量地使用了对象,为了保证对象之间的联系,JavaScript引入了原型与原型链的概念。

在Java中,声明一个实例的写法是这样的:

ClassName obj = new ClassName()

为了保证JavaScript“看起来像Java”,JavaScript中也加入了new操作符:

var obj = new FunctionName()

可以看到,与Java不同的是,JavaScript中的new操作符后面跟的并非类名而是函数名,JavaScript并非通过类而是直接通过构造函数来创建实例。

function Dog(name, color) {
    this.name = name
    this.color = color
    this.bark = () => {
        console.log('wangwang~')
    }
}

const dog1 = new Dog('dog1', 'black')
const dog2 = new Dog('dog2', 'white')

上述代码就是声明一个构造函数并通过构造函数创建实例的过程,这样看起来似乎有点面向对象的样子了,但实际上这种方法还存在一个很大的问题。

  • 每一个构造函数都拥有一个prototype属性,这个属性指向一个对象,也就是原型对象。当使用这个构造函数创建实例的时候,prototype属性指向的原型对象就成为实例的原型对象。
  • 原型对象默认拥有一个constructor属性,指向指向它的那个构造函数(也就是说构造函数和原型对象是互相指向的关系)。
  • 每个对象都拥有一个隐藏的属性[[prototype]],指向它的原型对象,这个属性可以通过Object.getPrototypeOf(obj) 或 obj.__proto__ 来访问。
  • 实际上,构造函数的prototype属性与它创建的实例对象的[[prototype]]属性指向的是同一个对象,即 对象.__proto__ === 函数.prototype 。
  • 如上文所述,原型对象就是用来存放实例中共有的那部分属性。
  • 在JavaScript中,所有的对象都是由它的原型对象继承而来,反之,所有的对象都可以作为原型对象存在。
  • 访问对象的属性时,JavaScript会首先在对象自身的属性内查找,若没有找到,则会跳转到该对象的原型对象中查找。

JavaScript中所有的对象都是由它的原型对象继承而来。而原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,这就是原型链(prototype chain)

所有原型链的终点都是Object函数的prototype属性,因为在JavaScript中的对象都默认由Object()构造。Objec.prototype指向的原型对象同样拥有原型,不过它的原型是null,而null则没有原型。

通过原型链就可以在JavaScript中实现继承,JavaScript中的继承相当灵活,有多种继承的实现方法,这里只介绍一种最常用的继承方法也就是组合继承

function Dog(name, color) { 
this.name = name 
this.color = color 
} 

Dog.prototype.bark = () => { 
console.log('wangwang~') 
} 

function Husky(name, color, weight) 
{ 
Dog.call(this, name, color) 
this.weight = weight 
} 
Husky.prototype = new Dog()

猜你喜欢

转载自blog.csdn.net/weixin_41835977/article/details/88869325