内容简介:面向对象编程是将事物看成一个个对象,对象有自己的属性有自己的方法。比如人,我们先定义一个对象模板,我们可以定义一些属性 比如,名字年龄和功能,比如走路。我们把这个叫做类。然后帮们将具体数据传入模板,成为一个个具体的人,我们将它叫做实例。
面向对象编程是将事物看成一个个对象,对象有自己的属性有自己的方法。
比如人,我们先定义一个对象模板,我们可以定义一些属性 比如,名字年龄和功能,比如走路。我们把这个叫做类。
然后帮们将具体数据传入模板,成为一个个具体的人,我们将它叫做实例。
JS 中面向对象是使用原型( prototype
)实现的。
function Person(name, age) { this.name = name this.age = age this.walk = function(){} } Person.prototype.walk = function () {} var bob = new Person('bob', 10) console.log(bob.age) 复制代码
其中的 Person
函数叫做构造函数,构造函数一般会将第一个字母大写, 构造函数创建特定类型的对象,构造函数中没有,显式的创建对象,和返回对象,直接将属性赋值给 this
。
我们使用 new
关键字创建对象实例,它会经历 4 个步骤,
constructor
我们也可以将 walk
函数写在构造函数中 this.walk=function(){}
,但是这样写的话,每新建一个实例,实例都会新建一个 walk
函数,这样就浪费内存空间,我们将它放在 prototype
上这样就会让所有实例共享一个 walk
函数,但是如果都写了它会调用自己的 walk
函数而不是共享的。
每一个函数都有一个 prototype
属性,函数的 prototype
对象上的属性方法,所有实例都是共享的。
prototype
对象有个 constructor
属性,它指向它的构造函数。
当创建一个实例时,实例内有会有个 [[Prototype]]
指针指向构造函数的原型对象,在浏览器中查看显示为 __proto__
属性。
当实例访问一个属性或者调用一个方法,比如 bob.walk()
,内部会首先在自身上查找这个方法,如果找到的话就完成,如果没有找到的话,就会沿着 [[prototype]]
向上查找,这就是为什么 prototype
上的方法都是共享,如果沿着 [[prototype]]
找到头,还没找到,那么就会报错 bob.walk
不是一个函数。
继承
继承主要是利用原型链,让子类的prototype等于父类的实例,也就是利用实例寻找属性和方法时,会沿着 [[prototype]]
向上找。
继承就是,一个子类继承父类的代码,而不用重新编写重复的代码。比如我们要写 Cat
, Dog
等类,我们发现每个类都有类似 this.name = name; this.age = age
这些重复的代码,所以我们可以先写一个 Animal
类,让 Cat
, Dog
继承这个类,我们就不用编写重复的属性和方法了。
function Animal(name) { this.name = name; this.age = 10 } Animal.prototype.say = function () { console.log(this.name) } function Cat() { Animal.apply(this, arguments) } Cat.prototype = new Animal() Cat.prototype.constructor = Cat 复制代码
我们用 apply
改变 Cat
的 this
指向,让我们可以借用 Animal
的构造函数,然后再让 Cat
的 prototype
指向一个 Animal
实例,并把 constructor
修改正常。
如果我们初始化一个 Cat
类,然后调用 say
方法,那么在内部的查找流程是:
自身 -> 沿着[[prototype]]找到Cat.prototype(它是一个Animal实例)-> 沿着Animal实例的[[prototype]]查找 -> 找到Animal.prototype(找到run方法并调用)
我们发现 Cat.prototype = new Animal()
这样就会让 Cat
的prototype多出 name
和 age
两个属性。
function Animal(name) { this.name = name; this.age = 10 } Animal.prototype.say = function () { console.log(this.name) } function Cat() { Animal.apply(this, arguments) } function F(){} F.prototype = Animal.prototype Cat.prototype = new F() Cat.prototype.constructor = Cat 复制代码
我们使用了一个中间类函数 F
,让它的 prototype
等于父级的 prototype
,那么我们查找到 F.prototype
时,就自动到了 Animal.prototype
上。
我们如果想直到一个属性是不是自身的可以使用
实例.hasOwnProperty(属性)
查看该属性是否来自本身。
Object.getOwnPropertyNames(obj)
返回所有对象本身属性名数组,无论是否能枚举
属性 in 对象
判断能否通过该对象访问该属性,无论是在本身还是原型上
如果我们想获取一个对象的 prototype
,我们可以使用
Object.getPrototypeOf(obj)
方法,他返回对象的 prototype
Object.setPrototypeOf(object, prototype)
方法,设置对象的 prototype
还可以使用对象的 __proto__
属性获取和修改对象的 prototype
(不推荐)
属性描述符
在 js 中定义了只有内部才能用的特性,描述了属性的各种特性。
对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可能是可写的,也可能不是可写的。存取描述符是由getter-setter函数对描述的属性。描述符必须是这两种形式之一;不能同时是两者。
数据属性
-
configurable
是否能配置此属性,为false
时不能删除,而且再设置时会报错除了Writable -
enumerable
当且仅当该属性的enumerable
为true
时,该属性才能够出现在对象的枚举属性中 -
value
包含了此属性的值。 -
writable
是否能修改属性值
存取描述符
configurable enumerable get set
我们可以使用 Object.defineProperty
方法定义或修改一个对象属性的特性。
var obj = {} Object.defineProperty(obj, "key", { enumerable: false, // 默认为 false configurable: false, // 默认为 false writable: false, // 默认为 false value: "static" // 默认为 undefined }); Object.defineProperty(obj, 'k', { get: function () { // 默认为 undefined return '123' }, set: function (v) { this.kk = v } // 默认为 undefined }) 复制代码
使用 Object.getOwnPropertyDescriptor
可以一次定义多个属性
var obj = {}; Object.defineProperties(obj, { 'property1': { value: true, writable: true }, 'property2': { value: 'Hello', writable: false } }); 复制代码
class
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class
关键字,可以定义类。
这样编写面向对象就更加的简单。
和类表达式一样,类声明体在严格模式下运行。构造函数是可选的。
类声明不可以提升(这与函数声明不同)。
class Person { age = 0 // 属性除了写在构造函数中也可以写在外面。 static a = 0 // 静态属性 constructor (name) { // 构造函数,可选(如果没有显式定义,一个空的constructor方法会被默认添加) this.name = name } // 类的内部所有定义的方法,都是不可枚举的 say () { // 方法 共享函数 return this.name } static walk() { // 静态方法 } } typeof Person // "function" Person === Person.prototype.constructor // true 复制代码
使用的时候,也是直接对类使用 new
命令,跟构造函数的用法完全一致,但是忘记加 new
会报错。
静态属性和静态方法,是属于类的,而不是属于实例的,要使用 Person.walk()
调用。
类的所有方法都定义在类的 prototype
属性上面。
// 上面等同于 Person.prototype = { constructor() {}, say() {} }; Person.a = 0 Person.walk = function () {} 复制代码
ES6 为 new
命令引入了一个 new.target
属性,该属性一般用在构造函数之中,返回 new
命令作用于的那个构造函数。如果构造函数不是通过 new
命令或 Reflect.construct()
调用的, new.target
会返回 undefined
,因此这个属性可以用来确定构造函数是怎么调用的。
function Person(name) { if (new.target === Person) { this.name = name; } else { throw new Error('必须使用 new 命令生成实例'); } } 复制代码
Class 内部调用 new.target
,返回当前 Class
与函数一样,类也可以使用表达式的形式定义。
const AA = class A {} // 这个类的名字是A,但是A只在内部用,指代当前类。在外部,这个类只能用AA引用 const BB = class {} let person = new class { // 立即执行的 Class constructor(name) { this.name = name; } }('张三'); 复制代码
Class 继承
Class 可以通过 extends
关键字实现继承。
class Animal { constructor (name) { this.name = name } } class Cat extends Animal { constructor (...args) { super(...args) // 调用父类的 constructor 方法 // 必须调用且放在 constructor 最前面 } } 复制代码
如果子类没有定义 constructor
方法,这个方法会被默认添加。
class ColorPoint extends Point { } // 等同于 class ColorPoint extends Point { constructor(...args) { super(...args); } } 复制代码
父类函数的静态属性和方法也会继承
super
这个关键字,既可以当作函数使用,也可以当作对象使用。
super
作为函数时,只能用在子类的构造函数之中,用在其他地方就会报错。
super
作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
在子类普通方法中通过 super
调用父类的方法时,方法内部的 this
指向当前的子类实例。
构造函数方法是不能继承原生对象的,
Boolean() Number() String() Array() Date() Function() RegExp() Error() Object() 复制代码
但是 class 可以继承。这样就可以构造自己的 Array
子类。
可以继承了 Object
,但是无法通过 super
方法向父类 Object
传参。这是因为 ES6 改变了 Object
构造函数的行为,一旦发现 Object
方法不是通过 new
Object()
这种形式调用,ES6 规定 Object
构造函数会忽略参数。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 面向Python,面向对象(基础)
- 面向Python,面向对象(基础3)
- <<深入PHP面向对象、模式与实践>>读书笔记:面向对象设计和过程式编程
- 《JavaScript面向对象精要》之六:对象模式
- 《JavaScript面向对象精要》之三:理解对象
- 面向对象的程序设计之理解对象
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
RESTful Web Services Cookbook
Subbu Allamaraju / Yahoo Press / 2010-3-11 / USD 39.99
While the REST design philosophy has captured the imagination of web and enterprise developers alike, using this approach to develop real web services is no picnic. This cookbook includes more than 10......一起来看看 《RESTful Web Services Cookbook》 这本书的介绍吧!