• 0

  • 476

原型和原型链

6天前

原型

一、前奏:面向对象

创建对象的方式:

  1. 简写方式,直接通过语法糖简写 var a = {}
  2. 通过new Object创建 let a = new Object()

关于Object:

可以看出Object是一个函数,之所以可以用new Object创建对象是因为,Object的本质是一个构造函数,构造函数和普通的函数没有本质区别,只是可以用来构造一些东西。

二、对象和构造函数

写一个构造函数:

  1. 内部用this指代需要生成的实例化对象
  2. 使用new实例化对象
  3. 函数的名称需要首字母大写
function Foo(a) { 
    this.a = a;
    this.b = a;
    this.say = function () {
        console.log("哈哈哈")
    }
}
var obj = new Foo(3);
obj;//Foo {a: 3, b: 3, say: ƒ}
obj.say();//哈哈哈
复制代码

构造函数和实例化对象的关系是什么?

——构造函数是妈,构造函数实例化的对象是儿子。

因为JavaScript是没有类的。只有基于原型。在构造函数中通过new关键字可以生成对象,和基于类的语言非常类似,所以我们称构造函数也是一个类。

instanceof用于判断一个变量是否是某个对象的实例

obj instanceof Foo;// true
复制代码

Object是对象,同时也是构造函数。

Object instanceof Object;//true
Object instanceof Function;//true
复制代码

任何对象都可以看作是Object的实例。

只有构造函数拥有原型 prototype,可以直接访问修改,相当于函数的基因,可以让实例化对象使用的公用的方法。

构造函数的基因:

let proto = {
    say: function () { 
        console.log('say')
    },
    walk: function () { 
        console.log('walk',this === obj2)
    }
}
Foo.prototype = proto;
var obj2 = new Foo(5); // Foo {a: 5, b: 5, say: ƒ}
// 实例化对象的基因(proto 隐式原型)
obj2.__proto__ ; // {say: ƒ, walk: ƒ}
obj2.walk(); // "walk,true"
console.log(obj.__proto__ === Foo.prototype)// true
console.log(obj.__proto__ === obj2.__proto__)// true
// 构造函数的原型就是实例化对象的隐式原型
复制代码

obj2继承了母亲的prototype的内容,通过 __proto__ 继承

任何(实例化)对象拥有一个属性constructor,构造器。它指向当前对象的构造函数。

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

Person.prototype = {
    say: function () {
        //通过this访问实例化对象的属性
        console.log(`我的名字是${this.name}`)
    }
}
复制代码

这一步的本质是通过new Object(say())创建一个对象赋值给Person.prototype

所以Person.prototype.constructor === Object

如果没有修改Person的原型,p.constructor===Person为true

如果修改了Person的原型,p.constructor是Object,不是Person

var p = new Person("张三");
p.say()// 我的名字是张三

p.constructor === Person // false
// 修正constructor的指向,修正之后访问constructor就可以知道实例化对象的构造函数
Person.prototype.constructor = Person
p.constructor === Person // true
复制代码

函数也是一个对象,也有构造函数

Person.constructor === Function;//true
Function.constructor === Function;//true
Object.constructor === Function;//true
复制代码

----2020-11-18 06:03

对象身上属性的访问顺序:

obj.say();//"哈哈哈"
// 万物之源: Object.prototype
obj.toString()
console.log(window.__proto__.__proto__.__proto__.__proto__ === Object.prototype)//true
复制代码

先在对象身上查找,如果没有就查找隐式原型,如果还是没有就去隐式原型里面的隐式原型查找,直到找到Object的原型

Object.prototype是对象,那这个对象是哪里来的?

——来自于构建js世界的顶层语言生成。

constructor 构造器

function Person(a) {
    this.name = a;
}
// 这一步的本质是通过new Object(say())创建一个对象赋值给Person.prototype 
// 所以Person.prototype.constructor === Object
Person.prototype = {
    say: function () {
        //通过this访问实例化对象的属性
        console.log(`我的名字是${this.name}`)
    }
}
var p = new Person("张三");
p.say()// 我的名字是张三
// 如果没有修改Person的原型,p.constructor===Person为true
// 如果修改了Person的原型,p.constructor是Object,不是Person
p.constructor === Person // false
// 修正constructor的指向,修正之后访问constructor就可以知道实例化对象的构造函数
Person.prototype.constructor = Person
p.constructor === Person // true
复制代码

Function

函数是什么数据类型?

Object

函数身上也有__proto__?

是的,Person.proto //ƒ () { [native code] }

Person构造函数是由Function实例化而来Person.proto === Function.prototype//true

Function是由Object实例化而来吗?

Function.proto === Object.prototype//false

Function.proto === Function.prototype//true?

实例化对象都有原型,所以规定上述内容,形成一个闭环

Object.proto ===Function.prototype?

Function创建了Object

原型链的终点都是Object.prototype

一个小案例:

// 控制台输入:
({}) == "[object Object]" // true
// 原理: {}调用了隐式原型__proto__即Object.prototype中的toString()方法转换成"[object Object]"
({toString: function(){return 3}}) == 3  // true
// 原理: 根据原型链,调用原型的时候,对象里面有toString()方法优先调用对象里面的
复制代码

var obj = new Foo(3);这一步做了什么?

生成一个对象,函数内部的this会变成这个对象。

var obj = Object.create()//创建一个新的对象,接收一个参数
var obj2 = Object.create(null)  //{} 无中生有,不适用于Object原型链的规则
obj2.__proto__ //undefined create创建的对象没有任何参数方法
obj2.__proto__ = Person.prototype //关联原型
Person.call(obj2)//通过call关联this
obj2.say()//报错
obj2.__proto__.say() //__proto__是属性不是原型

var obj3 = Object.create({});//除了null,传入其他的内容都适用原型链查找规则
obj3.__proto__ // 有参数
复制代码
免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

物联网

476

相关文章推荐

未登录头像

暂无评论