原型链

本文最后更新于:2023年3月1日 中午

理解 new 关键字的作用机制

理解 [[GET]]

对象有隐式原型,而函数有显示原型

隐式原型是指向显示原型的,然后一直递归下去,直到为null 就会返回undefined

new 关键字的作用机制

1.执行前

  • 1.绑定this为空对象
  • 2.让空对象[[Prototype]] –> 函数的 prototype属性
  • 2.1 所有对象都有[[Prototype]] (__proto__)
  • 2.2 所有的函数对象 –>prototype
  • 3.正常执行函数
  • 4.如果函数返回的基本类型,返回this的值,否则返回原函数的返回值

[[GET]]

如果要访问对象的属性,就需要用到一个隐式方法[[GET]],会一直沿着原型链找,直到找到NULL的话,如果找不到这个属性的话会返回一个 undefined,而不会报错

  1. 判断对象里面有没有
  2. 判断它的__proto__指向的对象里面有没有
1
2
3
4
5
6
7
function foo(){
console.log(1);
}

var a = new foo(); //返回值:this指向的对象的引用

console.log(a.b); //undefined

原型链,共享方法和属性,节省内存开销

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//阿里 四面
Object.prototype.a = function(){
console.log("a");
}

Function.prototype.b = function(){
console.log("b");
}

var F = function(){};

var f = new F();

f.a(); //a
f.b(); // 报错,没有b这个方法
F.a(); //a
F.b(); //b

原型链

静态方法和实例方法

1
2
3
4
5
6
7
8
9
10
11
12
function foo(){
console.log(1);
}

//静态方法
foo.a = 1; //这个是写在函数上面的,实例是拿不到的
var bar = new foo();
bar.a; //undefined
//实例方法
foo.prototype.a = a; //这个是写在构造函数的上的,实例是可以拿到的
var bar = new foo();
bar.a; //1

一些很奇怪的问题

1
2
3
4
5
6
7
8
9
10
11
12
//Object 和 Function

//关于{} 和 function(){}
//Object.prototype.__proto__ = null; //不是所有对象都是 Object的实例
//Function.prototype.__prototype = Object.prototype;
//Object.__proto__ = Function.prototype new Function
//Function.__proto__ = Function.prototype new Function


//只要是对象就有 __proto__ ,只要是函数就有 prototype
//对象的隐式原型对象 指向 函数的显示原型对象
//函数的隐式原型对象 指向 函数的显示原型对象

原型链的引用

  1. 面向对象编程 ->提高代码的可复用率 -> 更加合理的数据关系
  2. 原型链的本质:对象的隐式原型和构造函数的显示原型的连接
  3. 连接方式:new 关键字, 使用方式: [[GET]] 和 [[PUT]]

instanceof 的作用机制

1
2
3
4
5
6
7
8
9
var Studen = {
age:12,
name:"spider"
}

var s1 = new Student;

console.log(s1 instanceOf Object;)

作用:判断 s1 是不是 Object的一个实例

  1. s1.__proto__ === Object.prototype
  2. s1.proto.proto === Object.prototype
  3. s1.proto = Student.prototype
  4. s1.proto.proto = Student.prototype.proto = Object.prototype //true

手写一个 instanceOf

1
2
3
4
5
6
7
8
9
10
Object.myInstanceOf = funcrion(obj,fun){
if(obj === null) return false; //找到了终点

if(Object.getPrototypeOf(obj) === fun.prototype){
return true;
}else{
return Object.myInstanceOf(Object.getPrototypeOf(obj),fun);
//Object.getPrototypeOf(obj); //返回obj的隐式原型
}
}

数组和类数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//数组
var a = [1,2,3];

a = {
"0":1,
"1":2,
"2":3,
"length":3,
__proto:Array.prototype
}


//类数组
a = {
"0":1,
"1":2,
"2":3,
"length":3,
__proto: XXX; //这里是主要的区别,所以类数组拿不到数组的一些方法
//不能通过 Array.prototype 拿到一些数组的方法
}

RHS(读) 和 LHS (写)

所有的程序都是一个状态机

状态机也就是数据的集合 -> RHS 读和 LHS 写

LHS RHS

[[PUT]] [[GET]]

修改一个对象的属性

[[PUT]] –> LHS

1.判断对象里面有没有属性

如果找到了

  • 如果是基本类型: 覆盖
  • 如果是引用类型:
    • 是对引用类型的引用 —> 覆盖
    • 对引用类型的访问 —> 修改

2.如果没有

  • 沿着原型链找
  • 如果没有找到,就一直找,直到原型链终点
  • 如果终点都没有的话,就会自己创建一个

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!