js之原型和原型链
一些知识点相关的面试题和答案
面试官:什么是构造函数
答:构造函数的本质是一个普通函数,他的特点是需要通过new
关键字来调用,用来创建对象的实例。所有的引用类型,如[],{},function等都是由构造函数实例化而来。 一般首字母大写。 解析:首字母大写只是约定俗成的规范。首字母小写的函数也可以用作构造函数。
面试官:什么是原型和原型链
答:原型模式是JS实现继承的一种方式。 所有的函数都有一个prototype
属性,通过new
生成一个对象时,prototype
会被实例化为对象的属性。 所有的引用类型都有一个__proto__
指向其构造函数的prototype
。原型链的话,指的就是当访问一个引用类型时,如果本身没有这个属性或方法,就会通过__proto__
属性在父级的原型中找,一级一级往上,直到最顶层为止。 解析:原型链最顶层Object的prototype
的__proto__
指向为null。
面试官:如何理解 constructor 属性
答:所有函数的原型对象都有一个constructor
属性指向函数本身。 解析:实例化的对象可以通过[].__proto__.constructor
获取到其构造函数。
面试官:描述new 操作符的执行过程
答: 1. 创建一个空对象。 2. 将这个空对象的__proto__
指向构造函数的prototype
。 3. 将构造函数的this
指向这个对象。 4. 执行构造函数中的代码。
面试官:如何判断一个变量是数组类型
答: 使用instanceof
关键字 或者constructor
属性。 解析:instanceof
的原理是判断操作符左边对象的原型链上是否有右边构造函数的prototype
属性。
总结性的图表,代码例子或笔试题目和解析,让知识点更容易懂
关于构造函数和原型
构造函数:相当于java中“类”的存在,如原生JS中的 Array, Function, String, Date 等等,都是构造函数。例如 new Date() 通过new操作符进行调用,用来创建一个Date对象的实例。
一个便于理解的栗子,描述js通过原型模式实现继承的过程
function Animal (name) { // 构造函数
this.name = name
}
Animal.prototype.type = 'animal' // 原型上的属性和方法可以被继承
Animal.prototype.eat = function () {
console.log('eat')
}
let dog = new Animal('忠犬八公') // 通过new 调用构造函数创建Animal的实例dog
console.log(dog.name) // 输出:忠犬八公
console.log(dog.type) // 输出:animal
dog.eat() // 输出:eat
console.log(dog.__proto__) // 输出:{ type:'animal', eat: f, __proto__: ...}
// dog.__proto__ 指向其构造函数Animal的prototype对象
一个关于原型的实用型例子
function Elem(id) {
this.elem = document.getElementById(id)
}
Elem.prototype.html = function (val) {
var elem = this.elem
if (val) {
elem.innerHTML = val
return this // 链式编程
}else{
return elem.innerHTML
}
}
Elem.prototype.on = function (type, fn) {
var elem = this.elem
elem.addEventListener(type, fn)
}
var div1 = new Elem('div1')
div1.html('灶门碳治郎').on('click', (e) => {
alert('灶门碳治郎')
})
这个栗子,使用原型将对 dom 节点的操作封装起来,只要创建一个Elem实例就轻松插入 dom 和添加事件监听。
原型链
![](https://img.haomeiwen.com/i21103877/9b7b71adc3d8e1c1.png)
所有的引用类型会有一个 proto 属性指向其构造函数的 prototype ,当访问这个引用类型的变量和方法时,会通过 proto 属性一层层往上找。如 [] 不止有构造函数 Array 原型上的方法,还有可以通过原型链找到 Object 原型上的方法。
关于instanceof 和 constructor
instanceof : 判断操作符右边的参数是否在左边的原型链上。 所以 [] instanceof Object 也为true
let obj = {}
let arr = []
console.log(typeof(obj)) // object
console.log(typeof(arr)) // object
console.log(obj instanceof Array) // false
console.log(arr instanceof Array) // true
console.log(obj.constructor === Array) // false
console.log(arr.constructor === Array) // true
通过以上代码可以学习通过 instanceof 关键字和 constructor 属性进行数据类型判断的使用方式。
知识延伸
JS究竟是先有Object还是先有Function呢?
console.log(Function instanceof Object) // 输出:true
console.log(Object instanceof Function) // 输出:true
Object和Function究竟是什么关系?
![](https://img.haomeiwen.com/i21103877/1b31179ff2c08e6e.png)
简单理解为:
1.Function 在 Object 的原型链上,因为 Object 是构造函数,他的 proto 指向 Function 的原型
2.Object 在 Function 的原型链上,因为 Function 是构造函数,他的 proto 指向的也是他自己的原型,然而 Function.prototype 本质上是一个对象,所以 Function.prototype.proto 指向 Object.prototype 。
关于链式编程
上述“一个关于原型的实用例子”中,提到了 链式编程 ,在此做简单介绍
function Dog(){
this.run = function(){
alert('dog is run...')
return this // 链式编程的关键
}
this.eat = function(){
alert('dog is eat...')
return this
}
this.sleep = function(){
alert('dog is sleep...')
return this
}
}
var d1 = new Dog()
d1.run().eat().sleep()
通过以上代码可以看出
链式编程的设计模式就是, 调用的函数的时候,可以基于其返回值继续调用其他方法 。
关键在于方法执行结束后需要有一个供继续调用的返回值,如 this 等。
(网络资源整理而来)