「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」
原型链
function Person(){
this.name = 'tom'
}
Person.prototype.age = 18
let person = new Person()
console.log(person.name)
console.log(person.age)
如以上的代码中,Person就是构造函数,Person.prototype就是Person的原型,person则是由Person构建出来的一个实例,它能够获取到Person里的变量,也能获取到Person原型上的变量。
prototype
每一个函数都有prototype属性,也只是函数拥有这个属性。函数的prototype属性指向了一个对象,这个对象就是因调用构造函数而创建的实例的原型。他们的关系如下图:
那实例与原型是通过什么来联系的呢?
__ proto __
每一个js对象都有(除了null和undefined)都有一个__ proto __属性指向原型,该属性并非标准属性,但是大部分浏览器都有内置该属性指向了构造函数的原型,但是还可以使用Object.getprototypeOf(obj)来获取
function Person(){}
let person = new Person()
person.__proto__ = Person.prototype // true
那么有没有属性是原型对象指向构造函数的呢?
constructor
constructor是原型对象上的一个属性,其指向构造函数,实例对象上是没有这个属性的,但是由于其找不到该属性,会再其原型上查找,因此实例对象也能够访问该属性。
实例与原型
当实例对象读取属性时,若是读取不到,便会去对象的原型上查找,原型其实也是一个对象,在其身上查找不到,其会继续向它的原型查找,知道原型链的尽头为止。
function Person(){}
Person.prototype.name = 'Tom'
let person = new Person()
person.name // Tom
person.name = 'Jack'
person.name // Jack
delete person.name
person.name // Tom
new
new 运算符可以创建一个对象实例,该实例可以访问构造函数内的属性和方法,也可以访问构造函数原型上的属性和方法
下面我们来实现一个new方法:
function myNew(){
let obj = new Object()
let Constructor = [].shift.call(arguments)
obj.__proto__ = Constructor.prototype
Constructor.apply(obj,arguments)
return obj
}
function Person(name){
this.name = name || 'person'
}
Person.age = 18
let person = myNew(Person,'tom')
console.log(person.name) // tom
person.__proto__ === Person.prototype // true
来看看new运算符到底做了什么
- 创建一个空对象并将他的原型指向了构造函数的原型对象
- 调用构造函数
- 返回obj对象
但是这样还是不够的,如果构造函数有返回值呢?让我们来看个例子:
function Person (name, age) {
this.strength = 60;
this.age = age;
return {
name: name,
habit: 'Games'
}
}
var person = new Person('Kevin', '18');
console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // undefined
console.log(person.age) // undefined
function Person(name, age) {
this.strength = 60;
this.age = age;
return 'handsome boy';
}
var person = new Person('Kevin', '18');
console.log(person.name) // undefined
console.log(person.habit) // undefined
console.log(person.strength) // 60
console.log(person.age) // 18
可以看到上述结果中,若是构造函数返回一个对象,则我们是不能访问构造函数内部的属性的,而返回其他类型即可
因此,对于刚才的new方法还要再进行一次改写:
function myNew(){
let obj = new Object()
let Constructor = [].shift.call(arguments)
obj.__proto__ = Constructor.prototype
let res = Constructor.apply(obj,arguments)
return typeof res === 'object' ? res : obj
}