JavaScript基础
- 原型
- 原型继承
- 问题
- 解决
- 原型链
- isPrototypeOf()
- Object.getPrototypeOf()
- 理解对象
- 数据属性
- 访问器属性
原型
原型继承
继承是面向对象编程的另一个特征,通过继承进一步提升代码封装的程度,JavaScript中大多是借助原型对象实现继承的特性。
龙生龙、凤生凤、老鼠的儿子会打洞描述的正是继承的含义。
我们来看个代码:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><title>Title</title>
</head>
<body>
<script>//继续抽取 公共的部分放到原型上const Person= {eyes: 2,head: 1}//女人 构造函数 继承 想要继承 Personfunction Woman(){}//Woman通过原型来继承PersonWoman.prototype=Person//指回原来的构造函数Woman.prototype.constructor=Womanconst red= new Woman()console.log(red)console.log(Woman.prototype)//男人 构造函数 继承 想要继承Personfunction Man(){}Man.prototype=PersonMan.prototype.constructor=Manconst pink=new Man()console.log(pink.head)console.log(pink)
</script>
</body>
</html>
问题
例如:
给女人加一个生孩子的方法
//给女人添加一个方法 生孩子Woman.prototype.baby=function (){console.log("宝贝")}
全部代码:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><title>Title</title>
</head>
<body>
<script>//继续抽取 公共的部分放到原型上const Person= {eyes: 2,head: 1}//女人 构造函数 继承 想要继承 Personfunction Woman(){}//Woman通过原型来继承PersonWoman.prototype=Person//指回原来的构造函数Woman.prototype.constructor=Womanconst red= new Woman()console.log(red)console.log(Woman.prototype)//给女人添加一个方法 生孩子Woman.prototype.baby=function (){console.log("宝贝")}//男人 构造函数 继承 想要继承Personfunction Man(){}Man.prototype=PersonMan.prototype.constructor=Manconst pink=new Man()console.log(pink.head)console.log(pink)
</script>
</body>
</html>
男人和女人都同时使用了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就会都影响。
解决
需求:男人和女人不要使用同一个对象,但是不同对象里面包含相同的属性和方法
答案:构造函数
new 每次都会创建一个新的对象
function Star(){this.age = 18this.say = function () {}
}
const ldh = new Star( )
const zxy = new Star()
console.log(ldh)
console.log(zxy)
console.log(ldh === zxy) // false每个实例对象都不一样
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"><title>Title</title>
</head>
<body>
<script>/*//继续抽取 公共的部分放到原型上const Person= {eyes: 2,head: 1}*///解决 构造函数 new 出来的对象 结构一样 但是对象不一样function Person(){this.eyes=2this.head=1}//女人 构造函数 继承 想要继承 Personfunction Woman(){}//Woman通过原型来继承Person//父构造函数(父类) 子构造函数(子类)//子类的原型 = new 父类Woman.prototype=new Person()//指回原来的构造函数Woman.prototype.constructor=Woman//给女人添加一个方法 生孩子Woman.prototype.baby=function (){console.log("宝贝")}const red= new Woman()console.log(red)console.log(Woman.prototype)red.baby() //男人 构造函数 继承 想要继承Personfunction Man(){}Man.prototype=new Person()Man.prototype.constructor=Manconst pink=new Man()console.log(pink.head)console.log(pink)
</script>
</body>
</html>
原型链
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对象的链状结构关系称为原型链
- 只要是对象就有__proto__,指向原型对象。
- 只要是原型对象就有constructor,指回创造我的构造函数。
当访问一个对象的属性(包括方法)时,首先查找这个对象自身
有没有该属性。
② 如果没有就查找它的原型(也就是__proto__指向的prototype原型对象
)
③如果还没有就查找原型对象的原型(Object的原型对象
)
④ 依此类推一直找到Object 为止(null
)
⑤ __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
可以使用instanceof 运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<script>function Person(){}const ldh=new Person()console.log(ldh.__proto__===Person.prototype);console.log(Person.prototype.__proto__===Object.prototype)console.log(ldh instanceof Person)console.log(ldh instanceof Object)console.log(ldh instanceof Array)console.log([1,3,7] instanceof Array)console.log(Array instanceof Object)
</script>
</body>
</html>
正常的原型链都会终止于 Object 的原型对象,Object 原型的原型是 null
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Person.prototype.__proto__.constructor === Object); // true
console.log(Person.prototype.__proto__.__proto__ === null); // true
function Person(){}console.log(Person.prototype.__proto__);
{constructor: ƒ Object()hasOwnProperty: ƒ hasOwnProperty()isPrototypeOf: ƒ isPrototypeOf()propertyIsEnumerable: ƒ propertyIsEnumerable()toLocaleString: ƒ toLocaleString()toString: ƒ toString()valueOf: ƒ valueOf()
}
isPrototypeOf()
确定两个对象之间的关系
[[prototype]]
isPrototypeOf()会在传入参数的[[Prototype]]指向调用它的对象时返回 true
function Person(){}const person=new Person()console.log(Person.prototype.__proto__);console.log(Person.prototype.isPrototypeOf(person));
相当于:
console.log(person.__proto__===Person.prototype) //true
Object.getPrototypeOf()
返回参数的内部特性 [[Prototype]] 的值
console.log(Object.getPrototypeOf(person)===Person.prototype) //true
理解对象
new Object() ==== {}
const person=new Object()person.name="张三"person.age=18person.say=function(){console.log(this.name)}person.say()
等同于
const person={name:"张三",age:20,say(){console.log(this.name)}}person.say()
数据属性
- configurable:属性是否可以通过delete 删除并重新定义 ⇒true
- Enumerable:属性是否可以通过for in 循环 =》 true
- writable:属性是否可以被修改 =》 true
- value:属性实际的值undefined
Object.defineProperty
访问器属性
- configurable:属性是否可以通过delete 删除并重新定义 → true
- Enumerable:属性是否可以通过for in 循环 =》 true
- Get:获取函数
- Set: 设置函数
getter
setter
let person ={year_:2023,age:18}Object.defineProperty(person,"year",{get(){console.log('get')return this.year_},set(newvalue){console.log('set',newvalue)this.year_=newvaluethis.age +1}})console.log(person.year)person.year =2014console.log(person.age)