阅读 85

原型?一次弄懂

原型是什么

  • 所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象

const arr = [] console.log(typeof arr.__proto__); // object 复制代码

  • 所有引用类型__proto__属性指向构造函数的prototype

console.log(arr.__proto__ === Array.prototype); // true 复制代码

  • 当一个对象在查找一个属性的时候,自身没有就会根据__proto__向它的原型进行查找,终点是Object.prototype.__proto__null,查找的过程形成了原型链

console.log(arr.toString); // [Function: toString] 复制代码

探索原型链

小伙伴们可以移步到JavaScript 世界万物诞生记,一篇帮助理解原型链的好文????

下面请出万恶之源

0.jfif

  • 为什么需要原型和原型链

function Person(name) {   this.name = name;   this.sayname = function() {     console.log(name);   } } let p1 = new Person('xguo'); let p2 = new Person('xguo'); console.log(p1.sayname === p2.sayname); // false 复制代码

用构造函数调用生成实例对象,有一个缺点,无法共享属性和方法。每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费,考虑到这些,原型和原型链诞生了

function Person(name) {   this.name = name; } Person.prototype.sayname = function() {   console.log('----'); } let p1 = new Person('xguo'); let p2 = new Person('xguo'); console.log(p1.sayname === p2.sayname); // true 复制代码

  • 如何理解原型链

我们知道Object.prototype.__proto__ === null,为什么呢?因为JS从设计之初就想用null表示空对象,最直接的证据:typeof null === 'object';因此ES5中用Object.create(null)来生成没有原型的空对象

console.log(Object.prototype.__proto__ == Object.create(null).__proto__); // true 复制代码

也就是说,Object.prototype 是使用这种方式生成的,然后才绑在 Objectprototype 属性上,因为对象可以先生成再赋予新属性

console.log(Function.__proto__=== Function.prototype); // true 复制代码

Function 是一个函数,只要是函数,它的__proto__就指向 Funtion.prototype这是继承的设定。Function 生成时,是没有__proto__属性的,它是一个BOM对象,Function __proto__prototype属性都是后面才指向同一个 BOM 对象的

console.log(Object instanceof Function) // true console.log(Object.__proto__=== Function.prototype); // true 复制代码

Object是构造器函数, 因此它的__proto__属性会指向Funtion.prototype

function Person() {} console.log(typeof Person.prototype); console.log(typeof Function.prototype); 复制代码

Function.prototype是一个函数,也是对象,只有Functionprototype是函数其他都是普通对象。它是一个桥梁,我们一直说函数也是对象,只有这个满足了, 函数才能是对象

“构造函数” new

function Cat(name, color) {     // 像其他语言的封装性 降低其他语言开发者的门槛     this.name = name     this.color = color } var cat1 = new Cat('狗蛋', '白色') console.log(cat1.constructor === Cat); // true 复制代码

我们使用new关键字,看起来是执行了类的构造函数方法,Cat的首字母也大写了,并且cat1.constructor === Cat,一切都好像在提示它是一个类

  • 构造函数还是调用

实际上Cat和程序中的其他函数没有任何区别,幕后黑手是new,它会劫持所有普通函数并用构造对象的形式调用它。换句话说,在JavaScript中对于“构造函数”最准确的解释是,所有带new的函数调用

  • .constructor属性

console.log(cat1.constructor === Cat.prototype.constructor); // true 复制代码

实际上,Cat.prototype.constructor默认指向Cat,这和“构造”毫无关系。

function Cat() {} Cat.prototype = {} var cat1 = new Cat() console.log(cat1.constructor === Cat); // false console.log(cat1.constructor === Object); // true 复制代码

.constructor属性只是Cat函数在声明时的默认属性,如果创建一个新对象并替换函数默认的.prototype引用,那么新对象并不会自动获得.constructor属性

  • 手动实现简版new

function Person(name, age, sex="女") {     // console.log(arguments)     this.name = name;     this.age = age;     this.sex = sex; } // 实例除了属性各有各的(私有的 constructor)通过prototype  // 对象间共享的方法(prototype ) // construtor 完成对象构造,再使用prototype连接共享方法 Person.prototype.sayHi = function() {     console.log('你好啊'); } // 手动实现new const objectFactory = function() {     var obj = new Object();     // [].shift [] 对象 shift 上的方法      // this -> [] call  -> arguments      // console.log(Array.from(arguments).shift());     var varConstructor = [].shift.call(arguments);          varConstructor.call(obj, ...arguments);     obj.__proto__ = varConstructor.prototype;     return obj; } const obj = objectFactory(Person, 'xguo', 19, '男'); console.log(obj); // Person {name: 'xguo', age: 19, sex: '男'} obj.sayHi(); // 你好啊


作者:onepiece1205
链接:https://juejin.cn/post/7015506102364307492

文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐