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个要点

  1. 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了`null`意外)
  2. 所有的引用类型(数组、对象、函数),都有一个`__proto__`属性,属性值是一个普通的对象
  3. 所有的函数,都有一个`prototype`属性,属性值也是一个普通的对象
  4. 所有的引用类型(数组、对象、函数),`__proto__`属性值指向它的构造函数的`prototype`属性值
  5. 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的`__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`在执行时,就指向了当前这个触发事件执行的对象。

 

 

posted @ 2020-11-23 23:41  风露  阅读(123)  评论(0编辑  收藏  举报