原型
一、前奏:面向对象
创建对象的方式:
- 简写方式,直接通过语法糖简写
var a = {}
- 通过new Object创建
let a = new Object()
关于Object:
可以看出Object是一个函数,之所以可以用new Object创建对象是因为,Object的本质是一个构造函数,构造函数和普通的函数没有本质区别,只是可以用来构造一些东西。
二、对象和构造函数
写一个构造函数:
- 内部用this指代需要生成的实例化对象
- 使用new实例化对象
- 函数的名称需要首字母大写
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__ // 有参数
复制代码
No more data