Javascript 面向对象编程
对象
js 中对象是一种复合数据类型,允许存储多个值为一个单独的尸体,这些值称为对象的属性,可以通过属性名访问对象属性,可通过 对象字面量{}
创建对象, 还可以用通过 Object.create()
- 两种创建对象的方式有什么区别?
- 通过
{}
字面量的方式创建的对象,会继承自 原型对象Object.prototype
,这意味着这个新创建的独享可以继承和访问Object.prototype
所有的属性和方法,如.toString
、.hasOwnProperty()
- 通过
{}
字面量创建的对象没有显式的指定原型,但是它默认地继承了Object.prototype
- 通过
Object.create(obj)
, 这个方法接收一个现有对象作为参数(这个参数是可选的如果没有传入参数,就使用 Object.prototype 作为原型) ,通过这个方法创建的对象会使用现有的对象作为创建新对象的__proto__(原型)
- 通过
Object.create([obj])
创建对象可以通过参数指定新对象的原型,这是与字面量方式的主要方式,Object.create(null) 穿件的对象没有原型
- 通过
构造函数
构造函数是一种特殊的函数,用于初始化新创建对象的并为新创建的对象设置属性和方法
- 使用
new
关键字调用构造函数,以穿件新的对象实例 - 箭头函数不能作为构造函数使用
- 构造函数和类的区别
- 类是 ES6+ 引入class语法作为面向对象编程的语法糖
- 类的语法更简洁,提供了 继承、静态方法、实例方法
- 构造函数中的
this
关键字this
关键字引用的是新创建的对象实例- 通过new关键字调用构造函数时,this 指向新创建的对象
- 通过new 关键字调用构造函数时发生了什么?
创建新对象
: 首先,js会创建一个新的空对象,这个新的空对象将成为即将要返回的实例对象设置原型链
: 新创建对象的内部链接([[Prorotype]])会被设置为构造函数的prototype
对象绑定this
: 构造函数中的this被绑定到新创建的对象上,这意味着在构造函数内部,你可以通过执行this关键字来访问和修改新对像的属性和方法执行构造函数
: 构造函数中的代码会被执行,这个过长中,可能会设置一些属性或者执行一些初始化的操作返回新对象
: 如果构造函数没有显式的返回一个非原始值(对象或者函数),则new表达式的结果是新创建的对象,如果构造函数返回了一个非原始值,那么这个返回值会成为new表达式的结果。如果构造函数返回了一个原始值(undefined、null、数字、字符串或者布尔值),者new表达式的结果仍然是新创建的对象,而不是返回原始值完成
: 构造函数一旦执行完毕,新创建的对象已经被初始化并准备好了,可以被赋值个一个变量或者进一步使用
对象属性
- 访问对象属性的方式
- 使用
.
语法或[]
(访问动态属性)
- 使用
- 删除对象属性
- 使用
delete
操作符删除对象属性
- 使用
- 对象属性特征
- 数据属性: 包含一个数据值的属性,一共有四个描述对象属性行为的特性:
[[value]]
: 属性数据值[[Writable]]
: 属性值是否可以被更改[[Enumerable]]
: 属性是否可以被枚举, 可以被枚举的属性可以通过for...in
或者Object.keys()
进行遍历[[Configurable]]
: 属性的类型是否可以被改变
- 访问器属性: 不包含属性数值,而是包含一对
getter
和setter
函数,访问器属性也有四个特性:[[Get]]
: 在读取属性时调用[[Set]]
: 在写入属性时调用[[Enumerable]]
[[Configurable]]
- 数据属性: 包含一个数据值的属性,一共有四个描述对象属性行为的特性:
Object.defineProperty(obj, propertyName, descriptor)
方法- 这个方法可以直接在一个对象上定义一个新的属性,或者修改一个对象的现有属性,并返回这个对象
- 参数:
obj
: 要定义或者修改的对象propertyName
: 属性名称descriptor
: 属性描述符对象
Object.prototype
常用的属性和方法:- 属性
constructor
: 指向创建该实力对像的构造函数__proto__
: 指向该对象的原型对象,在严格模式下禁止使用,建议使用Object.getPrototype()
获取对象的原型对象
- 方法
toString()
: 返回[object Array]
toLocalString()
: 返回一个表示该对象的本地化字符串,常用于日期和时间对象valueOf()
: 返回对象的原始值, 对于大多数的对象而言,这个方法返回的就是对象本身,但对于像日期和时间这样的对象,这个方法返回的一个更基本的数据类型(时间戳)hasOwnProperty(propertyName)
: 返回一个布尔值,表示对象自身(不包括原型链) 是否有指定的属性isPrototypeOf(object)
: 返回一个布尔值,表示该对象是否在另一个对象的原型链上propertyIsEnumerable(propertyName)
: 返回一个布尔值,表示对象属性是否可以通过for...in
进行枚举
- 属性
对象方法
-
对象方法中的
this
指向- 通常情况下
this
指向调用该方法的对象实例 - 如果方法被当作普通的函数调用(不是作为对象方法),this 指向全局对象(window)【严格模式下是 undefined】
- 通常情况下
-
如何改变对象方法中
this
指向- 使用 call、apply、bind 方法
- 以函数的形式调用时,this永远指向window
- 以对象形式调用时,this指向调用的方法的对象
- 以构造函数形式调用时,this指向新创建的对象
- 使用call、apply、bind 调用时,this指向指定的target对象
orginObj.call(targetObj, param1, param2...)
使用call方法改变 orginObj对象的this指向,方法接收一个对象作为第一个参数,并将orginObj的this指向该对象(targetObj),参数作为其余参数传给方法orginObj.apply(targetObj, [param1, param2, param3...])
originObj.bind(targetObj)
: bind 方法会创建一个新的函数,当这个函数被调用的时候,this被设置为提供的值,无论它如何被调用
- 使用 call、apply、bind 方法
-
闭包和对象方法的关系
- 对象方法也可以形成闭包,因为他们可以方位定义它们的对象的属性和其他方法
- 当对象方法被调用时就形成了一个闭包,可以访问和修改定义它的对象状态
-
对象方法的上下文
对象方法的上下文指,对象方法被调用时所处的环境
原型和原型链
原型:每个js对象都有一个原型对象,原型对象定义了该对象继承的属性和方法
原型链:当试图访问一个对象的某个属性的时候,如果对象自身没有该属性或方法,js会沿着原型链向上查找,直到找到该属性或者方法,直到原型链的顶端null
- 如何访问对象的原型?
- 通过
obj.__proto__
属性(非标准)或者Object.getPrototypeOf()
方法访问对象原型
- 通过
- 原型污染
- 原型污染指当不当的修改或者添加属性到原型对象上,这可能会导