JavaScript基础
原型
原型继承
继承是面向对象编程的另一个特征,通过继承进一步提升代码封装的程度,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
}
//女人 构造函数 继承 想要继承 Person
function Woman(){
}
//Woman通过原型来继承Person
Woman.prototype=Person
//指回原来的构造函数
Woman.prototype.constructor=Woman
const red= new Woman()
console.log(red)
console.log(Woman.prototype)
//男人 构造函数 继承 想要继承Person
function Man(){
}
Man.prototype=Person
Man.prototype.constructor=Man
const 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
}
//女人 构造函数 继承 想要继承 Person
function Woman(){
}
//Woman通过原型来继承Person
Woman.prototype=Person
//指回原来的构造函数
Woman.prototype.constructor=Woman
const red= new Woman()
console.log(red)
console.log(Woman.prototype)
//给女人添加一个方法 生孩子
Woman.prototype.baby=function (){
console.log("宝贝")
}
//男人 构造函数 继承 想要继承Person
function Man(){
}
Man.prototype=Person
Man.prototype.constructor=Man
const pink=new Man()
console.log(pink.head)
console.log(pink)
</script>
</body>
</html>
男人和女人都同时使用了同一个对象,根据引用类型的特点,他们指向同一个对象,修改一个就会都影响。
解决
需求:男人和女人不要使用同一个对象,但是不同对象里面包含相同的属性和方法
答案:构造函数
new 每次都会创建一个新的对象
function Star(){
this.age = 18
this.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=2
this.head=1
}
//女人 构造函数 继承 想要继承 Person
function 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()
//男人 构造函数 继承 想要继承Person
function Man(){
}
Man.prototype=new Person()
Man.prototype.constructor=Man
const 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=18
person.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_=newvalue
this.age +1
}
})
console.log(person.year)
person.year =2014
console.log(person.age)
怎么创建出来一个__proto__指向undefined的对象
const n=Object.create(null)
console.log(n.__proto__)
create做什么的细节
//在new的时候
function myNew(){
const person={}
//create的参数不是null的情况: person.__proto__=Person.prototype
//create的参数为null的时候
person.__proto__=undefined
}
class类是语法糖
// prototype 库
// 语法糖
// babel -> es5
class Person {
}