JS原型及原型链
1、构造函数、原型对象、实例化原型对象三者的关系:
2、构造函数new的几个过程
- 创建一个新对象
- `this`指向这个新对象
- 执行代码,即对`this`赋值
- 返回`this`
function Foo(name) { this.name = name this.type = 'foo' } var foo = new Foo('beijing')
3、构造函数 - 扩展
- `var a = {}`其实是`var a = new Object()`的语法糖
- `var a = []`其实是`var a = new Array()`的语法糖
- `function Foo(){...}`其实是`var Foo = new Function(...)`的语法糖
4、原型链的5个要点
- 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了`null`意外)
- 所有的引用类型(数组、对象、函数),都有一个`__proto__`属性,属性值是一个普通的对象
- 所有的函数,都有一个`prototype`属性,属性值也是一个普通的对象
- 所有的引用类型(数组、对象、函数),`__proto__`属性值指向它的构造函数的`prototype`属性值
- 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的`__proto__`(即它的构造函数的`prototype`)中寻找
var obj = {}; obj.a = 100; var arr = []; arr.a = 100; function fn () {} fn.a = 100; console.log(obj.__proto__); console.log(arr.__proto__); console.log(fn.__proto__); console.log(fn.prototype) console.log(obj.__proto__ === Object.prototype)
5、prototype继承
所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法:
Date
对象从Date.prototype
继承。Array
对象从Array.prototype
继承。Person
对象从Person.prototype
继承。
所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。
JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
Date
对象, Array
对象, 以及 Person
对象从 Object.prototype
继承。
6、原型链实例
// 动物 function Animal() { this.eat = function () { console.log('animal eat') } } // 狗 function Dog() { this.bark = function () { console.log('dog bark') } } Dog.prototype = new Animal() // 哈士奇 var hashiqi = new Dog()
// 构造函数 function DomElement(selector) { var result = document.querySelectorAll(selector) var length = result.length var i for (i = 0; i < length; i++) { this[i] = selectorResult[i] } this.length = length } // 修改原型 DomElement.prototype = { constructor: DomElement, get: function (index) { return this[index] }, forEach: function (fn) { var i for (i = 0; i < this.length; i++) { const elem = this[i] const result = fn.call(elem, elem, i) if (result === false) { break } } return this 指向当前触发时间的对象,可以无限触发,多次调用 }, on: function (type, fn) { return this.forEach(elem => { elem.addEventListener(type, fn, false) }) } } // 使用 var $div = new DomElement('div') $div.on('click', function() { console.log('click') })
7、伪数组、类数组
实际应用中,和数组同样重要、起同样作用并且更加灵活的数据结构还是“伪数组”或者“类数据”(jquery 就用到了)。因此,在实际应用中,只需要判断`length`属性是否是数字即可。
var arr = [] var likeArr = { 0: 'aaa', 1: 'bbb', 2: 'ccc', length: 3 } typeof arr.length === 'number' // true typeof likeArr.length === 'number' // true
8、如何准确判断一个变量是数组类型
typeof仅能判断 值类型,引用类型中,仅能判断 function和object
判断数组的话,需要用instanceof
instanceof原理:(基于的是原型链)
如果要计算`f instanceof Foo`是不是正确,就要判断`f`的原型一层一层往上,能否对应到`Foo.prototype`。同理,如果要计算`f instanceof Object`是不是正确,就要判断`f`的原型一层一层往上,能否对应到`Object.prototype`
// 构造函数 function Foo(name, age) { this.name = name } Foo.prototype.alertName = function () { alert(this.name) } // 创建示例 var f = new Foo('zhangsan') f.printName = function () { console.log(this.name) } // 测试 f.printName() f.alertName()
9、原型链示意图
10、如何判断一个这个属性是不是对象本身的属性
使用`hasOwnProperty`(屏蔽了来自原型的属性),常用的地方是遍历一个对象的时候
var item for (item in f) { // 高级浏览器已经在 for in 中屏蔽了来自原型的属性,但是这里建议还是加上这个判断,保证程序的健壮性 if (f.hasOwnProperty(item)) { console.log(item) } }
11、原型链中的`this`
所有的从原型或者更高级的原型中得到、执行的方法,其中的`this`在执行时,就指向了当前这个触发事件执行的对象。