JS中每一个对象都有一个特殊的内置属性,这个特殊的对象可以指向其他的对象
prototype
使用方式有两种:
_proto_
属性可以获取到(浏览器自己添加的,存在一定的兼容性问题)prototype属性是函数特有的属性 我们的对象只能通过
Object.getPrototypeOf
来查看原型。
var obj = {
}
function foo() {
}
console.log(foo.prototype);
当我们这个对象有对多个共同值的时候,可以把相同的东西当如原型里,这样每次创建这个对象的时候,就可以直接调用而不是重新创建。
function Student(name, age) {
this.name = name
this.age = age
// 如果我们每个对象都创建那么这两个方法会出现很多的冗余
// this.running = function () {
// console.log(this.name + "running");
// }
// this.eating = function () {
// console.log(this.name + "eating");
// }
}
Student.prototype.running = function () {
console.log(this.name + "running");
}
Student.prototype.eating = function () {
console.log(this.name + "eating");
}
var stu1 = Student("jjj", 12)
var stu2 = Student("hhh", 18)
原型对象上面是有一个属性的:constructor,默认情况下原型都会有一个叫constructor
指向当前的对象
function Person() { }
var PersonProtype = Person.prototype
console.log(PersonProtype);
console.log(PersonProtype.constructor);
console.log(PersonProtype.constructor == Person);
原型对象是可以重写的,当我们需要给原型添加更多的属性的时候一般我们会选择重写原型对象
我们也可以改变原型对象中constructor的指向的使用
//改变指向对象
Person.prototype={
constructor:Person
}
//修改枚举类型
Object.defineProperty(Person.prototype,"constructor",{
enumerable:false
})
这里要注意的是原生的constructor是不可枚举的,但是修改constructor的时候会让constructor的特性被设置为true这个时候需要修改一下对象默认属性设置
创建对象的内存表现:
如果我们向对象加入属性在之后的变化:
继承
面向对象有三大特性:封装、继承、多态
这里主要将JS中的继承,在了解继承之前我们需要了解JS中的原型链机制,这个是之后理解的关键
在js中我们不断的获取原型对象,原型链最顶层的原型对象就是Object的原型对象
[Object: null prototype] {}
这种提示一般有两个情况:
ps:Object是所有类的父类
我们也可以对原型链做一些自定义操作,比如这样:
var obj = {
}
obj.__proto__ = {
}
obj.__proto__.__proto__ = {
}
obj.__proto__.__proto__.__proto__ = {
name: "小冷"
}
原型链实现继承
function Person(){
this.name = "l"
}
var p = new Person()
stu.prototype = p
//name == l
stu.prototype.studying = function(){
console.log(this.name+"studying")
}
我们可以通过赋值原型的形式来实现继承,但是有一些弊端
为了解决原型链继承中存在的问题,constructor stealing
应运而生 ,借用继承的做法非常简单:在子类型构造函数的内部调用父类型构造函数
function Person(name, age, height, address) {
this.name = name
this.age = age
this.height = height
this.address = address
}
function Student(name, age, height, address, sno, score) {
Person.call(this,name, age, height, address)
this.sno = sno
this.score = score
}
可以使用父类的构造函数来实现创造,解决之前原型链的问题 在ES6之前一直是保持的这个方式,但是这个继承方式依然不是很完美
在继续的发展中, JSON的创立者道格拉斯, 提到了新的继承方法,这也是目前es5 阶段最合适的继承方案 寄生组合继承
function Person(name, age, height, address) {
this.name = name
this.age = age
this.height = height
this.address = address
}
Person.prototype.running = function () {
console.log(this.name + " running");
}
function Student(name, age, height, address, sno, score) {
Person.call(this, name, age, height, address)
this.sno = sno
this.score = score
}
// 原型继承
var obj = Object.create(Person.prototype)
console.log(obj.__proto__ === Person.prototype);
Student.prototype = obj
// 上到真是环境 会封装用 为了兼容性可以多一个创造类的方法
function object(o){
function F(){}
F.prototype = o
return new F()
}
function inherit(Subtype, Supertype) {
Subtype.prototype = object(Supertype.prototype)
// 需要构造方法
Object.defineProperty(Subtype, "constructor", {
enumerable: false,
configurable: this,
writable: true,
value: Subtype
})
}
inherit(Student, Person)
Student.prototype.eating = function () {
console.log(this.name + "eating");
}
var stu = new Student("小明");
stu.eating()
hasOwnProperty : 对象是否有某一个属于自己的属性
in/for in 操作符: 判断某个属性是否在对象或者对象的原型上
instanceof : 用于检测构造函数的原型,是否出现在某个实例对象的圆形脸上
isPrototypeOf:用于检测某个对象,是否出现在某个实例对象的原型链上