YBFACC / blog

仅记录个人学习使用
3 stars 0 forks source link

原型 #4

Open YBFACC opened 4 years ago

YBFACC commented 4 years ago

原型

JavaScript 继承通过原型链来实现--每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法

BB0FB8AA-62D5-4F10-90FD-571EF7B03780

此图出自《JavaScript忍者秘籍(第2版)》

函数独有prototype

function.prototype是个对象,用来保存需要共享的属性

function name(params) {}
console.log(typeof name.prototype)//object

每个对象都需要使用某个函数,我们总不可能给每个对象都加个函数。这也太麻烦了。

我们可以给他们的原型对象上挂一个公用属性。

let a = { name: 'A' }

let b = { name: 'B' }

Object.prototype.say = function () {
  console.log(this.name)
}

a.say() //A
b.say() //B

规则:如果试图引用对象(obj)的某个属性,会首先在对象内部寻找该属性,直至找不到,然后才在该对象的原型(obj.__proto__)里去找这个属性

.__proto__

.__proto__([[prototype]])是串联起原型链的关键,指向原型对象

function apple() {
  this.name = 'apple'
}

let a = new apple()

console.log(a.__proto__ === apple.prototype)//true

不推荐使用此属性

来自MDN的警告:该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。

替代品

function apple() {
  this.name = 'apple'
}

let a = new apple()

//读
console.log(Object.getPrototypeOf(a) === a.__proto__)

//写
a.__proto__ = Object.prototype

Object.setPrototypeOf(a, apple.prototype)

//创建
let b = Object.create(apple.prototype)

instanceof运算符

instanceof 运算符用来检测 constructor.prototype是否存在于参数 object 的原型链上MDN

function apple() {
  this.name = 'apple'
}

let a = new apple()

console.log(a instanceof apple)//true

isPrototypeOf()

方法用于测试一个对象是否存在于另一个对象的原型链上MDN

function apple() {
  this.name = 'apple'
}

let a = new apple()

console.log(apple.prototype.isPrototypeOf(a)) //true

产生对象的方式

直接字面量赋值

let a = {}
console.log(a instanceof Object)//true

直接由字面量赋值的对象,继承全局函数Object

使用new关键字

function apple() {
  this.name = 'apple'
}

let a = new apple()

console.log(a instanceof apple)//true
console.log(a instanceof Object)//true

使用new关键字生成的对象,继承自function.prototype原型对象

New一个对象的过程

1.创建一个全新的对象

2.这个新对象的原型(Object.getPrototypeOf(target))指向构造函数的prototype对象

3.该函数的this会绑定在新创建的对象上

4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

var obj = {}//1
obj.__proto__ = F.prototype//2
F.call(obj)//3
return obj//4

原型链的终点

console.log(Object.prototype.__proto__)//null

拒绝查找原型链

所有继承了 Object 的对象都会继承到 hasOwnProperty 方法。这个方法可以用来检测一个对象是否含有特定的自身属性;和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。MDN

let a = { name: 'A' }

let b = { name: 'B' }

Object.prototype.say = function () {
  console.log(this.name)
}

console.log(a.hasOwnProperty('name'))

console.log(a.hasOwnProperty('say'))
Object.prototype.bar = 1;

var foo = {
    moo: 2
};
for(var i in foo) {
    console.log(i); 
}

此题引用来自这些前端基础题你能答对几道?(测试你的基础掌握,附答案解析)

自己做这题时,像不起来 in 的特性了。

意外

这里有个问题=>字符串字面量为什么可以调用split()API?

let num = '1234'
let arr = num.split('')

字面量继承了String.prototype?

console.log(num instanceof String)//false

嗯?没有!!难道原型出错了?🤨

我们去查查MDN

字符串字面量 (通过单引号或双引号定义) 和 直接调用 String 方法(没有通过 new 生成字符串对象实例)的字符串都是基本字符串。JavaScript会自动将基本字符串转换为字符串对象,只有将基本字符串转化为字符串对象之后才可以使用字符串对象的方法。当基本字符串需要调用一个字符串对象才有的方法或者查询值的时候(基本字符串是没有这些方法的),JavaScript 会自动将基本字符串转化为字符串对象并且调用相应的方法或者执行查询。MDN

原来字面量在使用API时,会自动转化为对象。没翻车😘

参考

JS基础-函数、对象和原型、原型链的关系

JS原型链与继承别再被问倒了

MDN