构造函数
构造函数首字母需要大写,并且会默认返回this
function Person(name){
this.name = name;
return this; //默认返回,省略
}
prototype 原型
一个对象被其他对象实例继承时,其在原型上定义的属性,通过“继承”,来拥有该对象原型上定义的属性,继承的行为时通过 new 操作符内部实现的
并且每一个构造器函数内部都有一个名为prototype的属性,通过这个属性就可以访问到原型
proto 隐式原型
在引用类型中,隐式原型 __proto__的属性指向她的构造器函数的显示原型prototype的属性值
let obj = {};
let arr = [];
let fnnc = function() {}
obj.__proto__ == Object.prototype // true
arr.__proto__ === Array.prototype // true
fnnc.__proto__ == Function.prototype // true
instanceof
检查是否该对象为该构造器的实例
手写简易的instanceof
- 排除基本类型
- 取sup的显示原型和sub的隐式原型对比,严格相同则返回
- 循环寻找sub的隐式原型,直到最顶层,为null则退出
function myInstanceof(sub, sup) {
const baseType = ['string', 'number', 'boolean', 'undefined', 'symbol'];
if (baseType.includes(typeof (sub))) return false;
let supPro = sup.prototype;
sub = sub.__proto__;
while (true) {
if (sub === null) return false;
if (sub === supPro) return true;
sub = sub.__proto__;
}
}
function Person(name) {
this.name = name
}
var person = new Person('mike');
console.log(myInstanceof(person, Person)); //true
console.log(myInstanceof(person, Object)); //true
手写new
function mynew(Func, ...args) {
// 1.创建一个新对象
const obj = {}
// 2.新对象原型指向构造函数原型对象
obj.__proto__ = Func.prototype
// 3.将构建函数的this指向新对象
let result = Func.apply(obj, args)
// 4.根据返回值判断
return result instanceof Object ? result : obj
}
constructor
这里constructor是原型的一个属性。用于获取原型的构造器函数
function Person(name) {
this.name = name
}
var person = new Person('mike');
console.log(Person.prototype.constructor===Person); //true
原型链
实例、构造函数、原型之间的关系
每个构造函数都有一个原型对象prototype,原型有一个属性constructor指回构造函数,而实例有一个内部指针__proto__指向原型。
Class
- Class只是一个语法糖,让对象原型写法更加清晰
- Class内部定义的方法不需要function关键字;方法间不需要分号;须使用new来调用
- Class类内所有的方法都定义在Class 类的prototype上
- this 关键字指向类的实例对象,this 上显示定义的属性即定义在实例对象上
// 1. 传统写法
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return "(" + this.x + ", " + this.y + ")";
};
let p = new Point(1, 2); // {x:1,y:2}
// 2. class 改写 =>
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
console.log("this->", this); // Point {x:1,y:2}
}
toString() {
return "(" + this.x + ", " + this.y + ")";
}
}
let p = new Point(1, 2); // {x:1,y:2}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
};
typeof Point; // 'function'
Point === Point.prototype.constructor; // true
setter/getter
使用 get/set 关键字对某个属性设置 取值/存值函数,对该属性的操作进行拦截
class MyClass {
constructor() {}
get age() {
return "get age";
}
set age(value) {
console.log("setter: " + value);
}
}
let inst = new MyClass();
inst.age= 123; // setter: 123
inst.age; // 'get age'
Class 的继承
子类的this 必须先完成构造父类的构造函数,则子类在构造器中必须先调用super方法,若子类不声明构造器,则会默认被加上
class Person{
constructor(name, age) {
this.name= name;
this.age= age;
}
}
class teacher extends Person{
constructor(...args) {
super(...args);
}
}
class Person{
constructor(name, age) {
this.name= name;
this.age= age;
}
}
class Teacher extends Person{
constructor(name, age, height) {
this.height= height; // ReferenceError
super(name, age);
this.height= height; // 正确
}
}
类的 prototype 和__proto__
Class 是构造函数的语法糖,同时有prototype属性和__proto__属性,同时存在两条继承链。
- 子类的__proto__属性,表示构造函数的继承,总是指向父类。
- 子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
实例的 proto
const p = new Person()
const tec = new Teacher()
tec.__proto__.__proto__ == p.__proto__ //true