JavaScript原型与原型链

2021-03-05  本文已影响0人  Lnevan

prototype

function Person() {}
let p = new Person()

console.log(Date.prototype,'---',Person.prototype) 
//{constructor: ƒ Date()
//getDate: ƒ getDate()
//getDay: ƒ getDay()
//getFullYear: ƒ getFullYear()
//getHours: ƒ getHours()……} --- {constructor: ƒ}

var arr1 = [2,4,6,4,3]
var arr2 = [3,5,3,6,4,8,3]

arr1.sort(function(num1,num2) {
    return num1 - num2
})
arr2.sort(function(num1,num2) {
    return num1 - num2
})
console.log(arr1) //[2, 3, 4, 4, 6]
console.log(arr2) //[3, 3, 3, 4, 5, 6, 8]
console.log(arr1 === arr2) //false
console.log(arr1.sort === arr2.sort) //true

上述代码定义了两个数组并调用了sort方法来讲数组重新排序,在第三个输出中很明显两个数组是不相等的,但是它们调用的sort方法却是相等的,这是为什么呢?我们再看一个例子:

var arr1 = [2,4,6,4,3]
var arr2 = [3,5,3,6,4,8,3]

arr1.getSum = function() {
    var sum = 0
    for(var i = 0;i < this.length;i++) {
        sum += this[i]
    }
    return sum
}

console.log(arr1.getSum()) //19
console.log(arr2.getSum()) //报错Uncaught TypeError: arr2.getSum is not a function

这个例子可以看出getSum函数只存在于arr1中,那为什么sort方法却能被两个数组同时使用呢?结合上面的例子可以猜测出一定有什么东西存放着所有数组都能共享的方法sort,那么就引出了原型(prototype)这个概念。通过原型的方法,我们能够做到让getSum函数也能被所有数组共享。

var arr1 = [2,4,6,4,3]
var arr2 = [3,5,3,6,4,8,3]

Array.prototype.getSum = function() {
    var sum = 0
    for(var i = 0;i < this.length;i++) {
        sum += this[i]
    }
    return sum
}

console.log(arr1.getSum()) //19
console.log(arr2.getSum()) //32
console.log(arr1.getSum === arr2.getSum) //true

这个例子更能佐证了arr1和arr2是调用Array.prototype中的sort方法(当然Array.prototype中也还有很多其它的方法),如果不放心,大可打印出来看看:

console.log(arr1.sort === Array.prototype.sort) //true
function Person(name,age) {
    this.name = name
    this.age = age
}

Person.prototype.profession = 'programmer'
var p1 = new Person('Joe',20)
var p2 = new Person('Bob',21)
var p3 = new Person('Mike',22)

console.log(p1.name,p1.age,p1.profession) //Joe 20 programmer
console.log(p2.name,p2.age,p2.profession) //Bob 21 programmer
console.log(p3.name,p3.age,p3.profession) //Mike 22 programmer
function Person() {
    this.name = 'Joe'
    this.say = function() {
        console.log('hello')
    }
}

Person.prototype.name = 'Bob'
Person.prototype.say = function() {
    console.log('Hi!')
}
var p1 = new Person()

console.log(p1.name) //Joe
p1.say() //hello
function Person() {
    this.name = name
}
console.log(Person.prototype.constructor === Person) //true

可以用图片这样子表示:


QQ图片20210305193109.png
function Person(name) {
    this.name = name;
}
var p1 = new Person()
console.log(p1.prototype) //undefined

原型链

function Person(name) { //内部语句:this.prototype = {} 
    this.name = name
}
var p1 = new Person() //内部语句:this.__proto__ = Person.prototype
console.log(p1.__proto__ === Person.prototype) //true

实例对象与其构造函数的关系可表示为:


QQ图片1.png
function Person(name) {
    this.name = name;
}
function Workder () {
    this.sayHello = function() {
        console.log('worker')
    }
}
Person.prototype = new Workder()
var son = new Person()
console.log(son.__proto__) //Workder
var p1 = new Object()
p1.name = 'Joe'
console.log(p1.name) // Joe

这个例子中,p1实例对象是由Object构造函数创建出来的,那么也符合p1.__proto__ === Object.prototype,因为原型对象也是对象,我们假设p1本来就是某个对象的原型对象,那么Object.prototype也就是该原型对象__proto__指向的原型对象,而所有对象都可以通过new Object()来创建,所以原型链最终都会指向Object.prototype

function Person(name) {
    this.name = name
}

var p1 = new Person()
console.log(p1.__proto__.__proto__ === Object.prototype) //true

该例再次说明了原型的原型确实会指向Object.prototype,而原型链这条“链”便是一个个__proto__连起来的。
那么链的终点是什么呢?

console.log(Object.prototype.__proto__) //null

可见,原型链的终点是null

var parent = {
    say() {
        console.log('Hello')
    }
} 
function Person(name) {
    this.name = name
}
Person.prototype = parent
var p1 = new Person()

p1.say() //Hello
//p1.sayName() //报错Uncaught TypeError: p1.sayName is not a function
console.log(p1.age) //undefined

var p2 = new Person()
p2.say = function() {
    console.log('Hi')
}

p2.say() //Hi

总结

//构造函数
function Foo() {}

//实例对象
let f1 = new Foo()

let o1 = new Object()

console.log(f1.__proto__ === Foo.prototype) //true
console.log(Foo.prototype.constructor === Foo) //true
console.log(Foo.prototype.__proto__ === Object.prototype) //true 沿着原型链往上找都会找到Object.prototype

console.log(o1.__proto__ === Object.prototype) //true
console.log(Object.prototype.__proto__) //null 原型链的终点指向null
console.log(Foo.prototype.constructor === Foo) //true

console.log(Function.prototype.constructor === Function) //true

console.log(Object.__proto__ === Function.prototype) //true 内置的引用类型(包括Object)其实也是一个函数对象,都是由Function创建的,所以原型会指向Function.prototype
console.log(Foo.__proto__ === Function.prototype) //true
console.log(Function.prototype.prototype === undefined) //true Function.prototype是个特例,它是函数对象,但是没有prototype属性。其他所有函数都有prototype属性。 
QQ图片.png

*由上图可知:

console.log(Fn.prototype instanceof Object) //true
console.log(Object.prototype instanceof Object) //false
console.log(Function.prototype instanceof Object) //true
console.log(Function.__proto__ === Function.prototype) //true

注:插入的图片来自于网络。

上一篇下一篇

猜你喜欢

热点阅读