一、什么是原型链
    MDN英文解释:
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
    JavaScript is a bit confusing for developers experienced in class-based languages (like Java or C++), as it is dynamic and does not provide a class implementation per se (the **class** keyword is introduced in ES2015, but is syntactical sugar, JavaScript remains prototype-based).
    When it comes to inheritance, JavaScript only has one construct: objects. Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with **null** as its prototype. By definition, **null** has no prototype, and acts as the final link in this prototype chain.
    Nearly all objects in JavaScript are instances of [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) which sits on the top of a prototype chain.

    个人理解:实例有自身[[prototype]]属性,指向构造函数的prototype,构造函数原型对象也有自己的[[prototype]],这样通过[[prototype]]串联起来的继承关系,叫作原型链,原型链的顶端是Object.prototype(Object.prototype.[[prototype]] 指向 null)

    mdn中的代码示例:

    1. // Let's create an object o from function f with its own properties a and b:
    2. let f = function () {
    3. this.a = 1;
    4. this.b = 2;
    5. }
    6. let o = new f(); // {a: 1, b: 2}
    7. // add properties in f function's prototype
    8. f.prototype.b = 3;
    9. f.prototype.c = 4;
    10. // do not set the prototype f.prototype = {b:3,c:4}; this will break the prototype chain
    11. // o.[[Prototype]] has properties b and c.
    12. // o.[[Prototype]].[[Prototype]] is Object.prototype.
    13. // Finally, o.[[Prototype]].[[Prototype]].[[Prototype]] is null.
    14. // This is the end of the prototype chain, as null,
    15. // by definition, has no [[Prototype]].
    16. // Thus, the full prototype chain looks like:
    17. // {a: 1, b: 2} ---> {b: 3, c: 4} ---> Object.prototype ---> null
    18. console.log(o.a); // 1
    19. // Is there an 'a' own property on o? Yes, and its value is 1.
    20. console.log(o.b); // 2
    21. // Is there a 'b' own property on o? Yes, and its value is 2.
    22. // The prototype also has a 'b' property, but it's not visited.
    23. // This is called Property Shadowing
    24. console.log(o.c); // 4
    25. // Is there a 'c' own property on o? No, check its prototype.
    26. // Is there a 'c' own property on o.[[Prototype]]? Yes, its value is 4.
    27. console.log(o.d); // undefined
    28. // Is there a 'd' own property on o? No, check its prototype.
    29. // Is there a 'd' own property on o.[[Prototype]]? No, check its prototype.
    30. // o.[[Prototype]].[[Prototype]] is Object.prototype and there is no 'd' property by default, check its prototype.
    31. // o.[[Prototype]].[[Prototype]].[[Prototype]] is null, stop searching,
    32. // no property found, return undefined.

    二、函数Object与函数Function的关系
    Object[[prototype]]指向构造函数Function.prototype
    Function[[prototype]]指向Function.prototype
    Function.prototype[[prototype]]指向Object.prototype
    Object.prototype为原型链顶端,其原型指向null,包含了一个toString,valueOf方法,很多对象的valueOf和toString继承于此,有一个例外是Array.prototype.toString方法,该方法重写了(将每个元素字符串后,用’,’连接)。
    image.png三、后代实例可以操作原型的引用类属性,原始类值属性则不行。
    难点:
    如果示例视图操作原型上的原始值类型,可能会给自身添加属性
    image.png
    四、this
    (1)对象中,当函数作为对象里的方法被调用时,this 被设置为调用该函数的对象。
    this 的绑定只受最接近的成员引用的影响

    1. let obj = {
    2. name: 'obj',
    3. o : {
    4. fn : function(){console.log(this.name)},
    5. nane: 'o'
    6. }
    7. }
    8. obj.o.fn() // => 'o'

    (2)原型链中,如果该方法存在于原型链中,this为调用该方法的实例
    (3)构造函数中,使用new关键字,this将被绑定到实例(this被return出去)
    (4)作为dom事件处理函数,this指向触发事件的元素
    (5)在class中,方法和普通函数一样,取决去caller,想要改写这个行为,可在cunstructor中,绑定到this上。

    1. class Car{
    2. constructor(){
    3. this.sayHi = this.sayHi.bind(this)
    4. }
    5. sayHi(){
    6. console.log(this.name)
    7. }
    8. get name(){
    9. return 'Car name'
    10. }
    11. }

    五、创建对象的方法:
    (1)字面量 var obj = {}
    (2)new构造函数 var obj = new Object()
    这两种方式一样,字面量方式,赋值更方便,隐式通过new Object来创建。原型都是Object.prototype
    (3)通过自定义构造函数创造的对象,原型指向构造函数的prototype
    (4)通过Object.create()参数为实例对象的原型,可以改变js默认指定的原型,用来自定义实例原型,继承特定对象,如果参数传null,则该实例没有原型,所以并非所有对象都继承于Object.prototype。这样的实例是不能手动添加proto的,手动添加上的是自定义属性。对象原型是系统添加的。对象属性可以更改,但是不能手动添加

    1. let obj = {}
    2. let obj1 = Object.create(Object.prototype)
    3. console.log(obj.__proto__ === Object.prototype) // => true

    六、包装类原型函数方法调用

    1. let num = 1
    2. console.log(num.toString())
    3. // => '1' 并非调用Object.prototype上的toString方法,调用的是Number.prototype.toString
    4. // 为什么Number会自己写个toString方法呢?
    5. // Object.prototype.toString.call(1) 返回的是'[object Number]'
    6. // Number.prototype.toString.call(1) 返回的是'1'

    七、call和apply
    作用:调用方法,并改变其内部this指向
    方法调用其实有隐式地call
    apply后一个参数为数组,传参更方便一些,用得频率更高

    1. function test(){}
    2. test() // => test.call() 系统有隐式地调用call,没传参
    3. function Car (name,age){
    4. this.name = name
    5. this.age = age
    6. }
    7. var newCar = {}
    8. Car.call(newCar,'benz','one')
    9. console.log(newCar) => {name: 'benz',age:'one'}

    借用构造函数
    call和apply的使用指导,将不同的构造函数结合起来,丰富实例的属性与方法。适合协同开发、方法分类、在原有功能上拓展。

    1. function Computor1 (){
    2. this.plus = function(a,b){console.log(a + b)}
    3. this.minus = function(a,b){console.log(a - b)}
    4. }
    5. function Computor2 (){
    6. //使用apply,给丰富实例属性方法
    7. Computor1.apply(this)
    8. this.mul = function(a,b){console.log(a*b)}
    9. this.divide = fcuntion(a,b){console.log(a%b)}
    10. }
    11. let fullComputor = new Computor2()