js面向对象知识点
1. 对象的定义
对象 : 是无序属性的集合
2. js的对象分类
-
内置对象
- 本地对象
- Object、Array、String、Number、Boolean、Date、Error.....
- 单体内置对象
- 只有 Global 和 Math
- 两者的区别:
- 单体对象不需要加new
- 本地对象
-
宿主对象
- js寄宿环境定义的对象,
- eg:window、document、history
- js寄宿环境定义的对象,
-
自定义对象
3. typeof 与 instanceof 的应用
3.1 typeof
typeof
: 输出数据所属的类型
格式:
typeof 数据
3.2 instanceof
格式
: 要判断的数据 instanceof 类型
功能
: 查看数据是否是指定的类型
3.3 示例

4. 属性的操作
4.1 访问某个属性
- 方式一:对象名.属性
-
obj.name
-
- 方式二:对象名[属性]。
-
obj["name"];
-
注意:如果属性名被保存在某一个变量,只能使用第二种方式。
4.2 给对象添加属性
-
两种方式
-
对象名.属性名 = 属性值;
-
obj.mame = "zhangsan"
-
-
对象名[“属性名”] = 属性值;
-
obg["name"] = "zhangsan"
-
-
-
属性有四个特征
configurable:是否可以删除。默认为true。writable:是否可以修改属性的值。默认为true。enumerable:是否可以修改属性的值。默认为true。value:值。默认为undefined
-
精细设置对象的属性
格式
Object.defineProperty(对象名,“属性名”,{
Configurable:
Writable:
Enumerable:
Value:
})
示例:
- 案例:设置一个只读属性,模拟常量
4.3 获取全部可以枚举的实例属性
Object.keys();
5. 利用属性的特性,完成例子
5.1 数组去重
let arr = [1,1,2,2,3,3];
let newArr = [];
let obj = {};
for(i=0;i<arr.length;i++){
let t = arr[i];
if(obj[t]){
}else{
obj[t] = true;
newArr.push(t);
}
}
console.log('newArr :', newArr);
输出结果:
5.2 统计数组中个元素出现次数
let arr = [1,1,2,2,3,3];
let obj = {};
for(i=0;i<arr.length;i++){
let t = arr[i];
if(obj.hasOwnProperty(t)){
obj[t] += 1;
}else{
obj[t] = 1;
}
}
console.log('obj :', obj);
输出结果:
6. 原型与原型链
6.1 原型
prototype : 就是原型
- 每一个函数都有一个
prototype属性 - 函数的原型是一个对象,原型里面与很多方法,但是一定有
constructor方法 constructor指向这个函数本身
proto : 隐式原型,它对外是隐藏的,我们在程序开发过程,不会直接使用它。
- 每一个对象都有一个__proto__属性
- 对于函数而言,每一个函数都会有一个
prototype和一个__proto__属性。
结论:
对象的__proto__属性 指向 创建这个对象的函数的prototype
6.2 原型链
原型链
: 访问一个对象的属性时,先在这个对象自己的属性中去找,如果找不到,则沿着__proto__这个属性向中找,如果__proto__这个对象中还是没有找到,就在__proto__对象的__proto__属性中去找,依次下去,这就是原型链。
注意:
- 由于对象的__proto__[隐式原型]与创建这个对象的函数(构造器)的prototype
是一致的。- 所以理论上,你对__proto__修改会
直接影响prototype。- 建议只使用
prototype[原型]
7. this 的应用
7.1 如何确定this的值
答:谁调用了this就是谁。
看方法前的那个对象是谁,this就指向谁。
-
(1)有明确的对象
- 例如:Obj.say();say 的当前对象是obj,所以say中的this 就指向obj。
-
(2)没有明确的对象
- 如果这个函数没有明确说是哪个对象的,则它肯定是属于window对象的,所以this就会指向window.
-
(3)如果是call和apply的方式,这时,this指向第一个参数
- 例如:f.call(obj1),f中的this指向obj1。
7.2 this 的总结
- this出现在全局中,
this是window - this出现在一个
普通的函数中(不是方法),this是window - this出现在一个对象的方法,this可以是这个对象,也可以是window
- call和apply可以
改变this指向,指向()第一个参数 - 一个函数没有明确指出谁调了,this是window
7.3 call,apply与bind可以改变this的指向
请参考
8. 创建对象的N种方式
8.1 字面量方式
例子:矩形对象
- 优点:直接了当,yimuliao
- 缺点:不能批量生产对象,只能一个一个写
8.2 工厂模式
例子:
// 利用工厂模式创建对象 工厂利用一个函数来模拟
function factory(w,h){
// 批量地产生矩形对象
let obj = {}
obj.width = w;
obj.height = h;
obj.getC = function(){
return (this.width+this.height)*2
}
obj.getS = function(){
return this.width*this.height
}
return obj;
}
let r1 = factory(1,2)
let r2 = factory(2,3)
console.log(r1.getC()) // 6
console.log(r1.getS()) // 2
console.log(r2.getC()) // 10
console.log(r2.getS()) // 6
-
优点:主要解决了字面量方式的不能批量生产对象的问题。
-
缺点:他产生的对象没有“商标”(不知道是谁生产的)
8.3 构造器模式(使用new)
示例:
new做了如下四件事:
-
创建一个对象 var o = {};
-
F.call(o); // 先执行F()函数,同时把this用o来代替。把F()构造器设置的各种属性值,直接赋给o. 理解如下代码:
-
o.proto = F.prototype //让o具备F.prototype上定义的方法。
-
return o;
-
构造器模式优点:
- 解决了对象的来源不明的问题。我们可以通过对象的constructor属性,找到它的构造器。
- new 构造器() 这种格式会受面向对象的程序员(java,C#,C++…)所接受。
- 具备工厂模式的批量生产(还可以是定制的,例如传参不同) 。
-
构造器模式缺点:不能像数组一组,共用方法。内存浪费。
8.4 构造器 + 原型 模式
function Rect(w, h) {
this.width = w;
this.height = h;
}
Rect.prototype.getC = function(){
return (this.width+this.height)*2
}
Rect.prototype.getS = function(){
return this.width*this.height
}
// r1 r2 r3都有getC和getS 造成内存空间的浪费
let r1 = new Rect(1, 2);
let r2 = new Rect(2, 3);
console.log(r1.getC()) // 6
console.log(r1.getS()) // 2
console.log(r2.getC()) // 10
console.log(r2.getS()) // 6
9. 继承
9.1 原型继承
function Parent(yourname) {
this.name = yourname;
}
Parent.prototype.say = function () {
console.log(this.name)
}
// 让Son去继承name属性和say方法
function Son(yourname) {
// 继承属性
Parent.call(this,yourname)
}
// 继承方法
Son.prototype = Parent.prototype;
Son.prototype.constructor = Son;
//调用
let s = new Son("hrllo");
s.say();
9.2 继承的浅拷贝
浅拷贝 : 将父类的原型对象直接复制给子类的原型对象
Son.prototype = Parent.prototype;
Son.prototype.constructor = Son;
若有多个对象,多个对象指向同一个原型对象,parent,肯能存在干扰
9.3 继承的深拷贝
深拷贝 : 把原型对象copy一份 让Son继承copy过来的
for(let i in Parent.prototype){
Son.prototype[i] = Parent.prototype[i]
}
每个对象各自独立,不存在干扰的现象
10 class的应用
10.1 使用css创建对象
格式:
class 类名{
constructor(参数){
this.属性= 参数;
}
method(){//对象中简写方法,省略了function。不要与箭头函数搞混了。
}
}
注意:
- class是关键字,后面紧跟类名,类名首字母大写,采取的是大驼峰命名法则。类名之后是{}。
- 在{}中,不能直接写语句,只能写方法,方法不需要使用关键字
- 方法和方法之间没有逗号。不是键值对。
例子:
调用方式:
10.2 使用extends实现继承
格式:
class 子类 extends 父类{
constructor(参数){
super(参数)
this.属性 = 值
}
}
注意:
- 使用extends关键字来实现继承
- 在子类中的构造器constructor中,必须要显式调用父类的super方法,如果不调用,则this不可用
示例:
class NBAPlayer {
constructor(name, age, height) {
this.name = name
this.age = age
this.height = height
}
say() {
console.log(`我是${this.name},今年${this.age},我的身高是${this.height}`)
}
jump() {
console.log("jump...")
}
}
class MVP extends NBAPlayer {
constructor(name, age, height, year) {
super(name, age, height)
this.year = year;
}
showMVP() {
console.log(`我是${this.name},我是${this.year}年的MVP`)
}
}
var m1 = new MVP("xiaoqiang","33","191",2010)
m1.say()
m1.showMVP()