Javascript - 原型&原型链

原型

概念:一个函数可以看成一个类,原型是所有类都有的一个属性,原型的作用就是给这个类的每一个对象都添加一个统一的方法

  • 所有引用类型都有一个 proto 属性,属性值是一个普通的对象
  • 所有函数都有一个 prototype 属性,属性值是一个普通对象
  • 所有引用类型的proto**** 属性都指向它的构造函数的 prototype
  • 使用 hasOwnProperty() 可以判断这个属性是不是对象本身的属性
1
2
var a = [1, 2, 3];
a.__proto__ === Array.prototype; // true

原型链

概念:每个对象都有一个proto,它指向它的 prototype 原型对象,而 prototype 原型对象又具有一个自己的原型对象,就这样层层向下上直到一个对象的原型 prototype 为 null 这个查询的路径就是原型链

  • 当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的proto隐式原型上查找,即它的构造函数的 prototype,如果还没有找到就会再在构造函数的 prototype 的proto中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
1
2
3
4
5
6
function Parent(month) {
this.month = month;
}
var child = new Parent("zhangsan");
console.log(child.month); // "zhangsan"
console.log(child.father); //undefined

在 child 中查找某个属性时,会执行以下操作

访问路径:

  • 一直往上层查找,直到到 null 还没有找到,则返回 undefined
  • Object.prototype.proto === null
  • 所有从原型或更高级原型中的得到、执行的方法,其中的 this 在执行时,指向当前这个触发事件执行的对象

总结

  • 原型和原型链是 JS 实现继承的一种模型。
  • 原型链的形成是真正是靠proto** 而非 prototype**
  • 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(null 除外)
  • 所有的引用类型(数组、对象、函数),都有一个proto属性,属性值是一个普通的对象
  • 所有的函数,都有一个 prototype 属性,属性值也是一个普通的对象
  • 所有的引用类型(数组、对象、函数),proto属性值指向它的构造函数的 prototype 属性值

执行 printName 时很好理解,但是执行 alertName 时发生了什么?这里再记住一个重点 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的proto(即它的构造函数的 prototype)中寻找,因此 f.alertName 就会找到 Foo.prototype.alertName。
那么如何判断这个属性是不是对象本身的属性呢?使用 hasOwnProperty,常用的地方是遍历一个对象的时候。
自动检测
var item
for (item in f) {
// 高级浏览器已经在 for in 中屏蔽了来自原型的属性,但是这里建议大家还是加上这个判断,保证程序的健壮性
if (f.hasOwnProperty(item)) {
console.log(item)
}
}

2,谈谈 This 对象的理解

先搞明白一个很重要的概念 —— this 的值是在执行的时候才能确认,定义的时候不能确认!
因为 this 是执行上下文环境的一部分,而执行上下文需要在代码执行之前确定,而不是定义的时候。看如下例子

1
2
3
4
5
6
7
8
9
10
var a = {
name: "A",
fn: function () {
console.log(this.name);
},
};
a.fn(); // this === a
a.fn.call({ name: "B" }); // this === {name: 'B'}
var fn1 = a.fn;
fn1(); // this === window

this 执行会有不同,主要集中在这几个场景中

  • 作为构造函数执行,构造函数中
  • 作为对象属性执行,上述代码中 a.fn()
  • 作为普通函数执行,上述代码中 fn1()
  • 用于 call apply bind,上述代码中 a.fn.call({name: ‘B’})


this 分为几个不同的使用场景,在 function 中 this 指的的是 window,如果是实用 new 调用的话 this 指的是当前的实例化对象,在事件调用函数中 this 指的调用事件的 dom,特殊的是在 IE 中的 attachEvent 中的 this 总是指向全局对象 Window;,在定时器中 this 指的是 window,在 es6 中有一个箭头函数,在箭头函数中 this 永远指向的是父级对象,this 也是可以改变的,在 js 中 call, apply, bind 都可以改变 this 的指向, call, apply 都是执行一个函数并且改变 this,区别就是参数传递不一样,而 bind 是返回一个绑定 this 之后的