【前端口试】原型和原型链

1.题目

  • 怎样正确推断一个变量是数组
  • 写一个原型链继续的例子
  • 继续完成的其他体式格局
  • es6 完成继续的底层道理是什么
  • 形貌new一个对象的历程
  • zepto及其他源码中怎样运用原型链

2.知识点

2.1 组织函数

特征:以大写字母开首

function Foo(name,age){
    //var obj = {}
    //this = {}
    this.name = name;
    this.age = age;
    this.class = 'class1'
    // return this
}

var f1 = new Foo('liming',19);

扩大

var o = {} 是 var o = new Object() 的语法糖

var a = [] 是 var a = new Array() 的语法糖

function Foo(){} 相当于 var Foo = new Function(){}

2.2 原型划定规矩

五条划定规矩:

1.一切援用范例(对象,数组,函数)都具有对象特征,即能够自在扩大属性

2.一切援用范例(对象,数组,函数)都具有一个__proto__(隐式原型)属性,是一个一般对象

3.一切的函数都具有prototype(显式原型)属性,也是一个一般对象

4.一切援用范例(对象,数组,函数)__proto__值指向它组织函数的prototype

5.当试图获得一个对象的属性时,假如变量本身没有这个属性,则会去他的__proto__中去找

for (var key in object) {
    //高等浏览器中已屏障了来自原型的属性
    //发起加上推断保证顺序的健壮性
    if (object.hasOwnProperty(key)) {
        console.log(object[key]);
    }
}

2.3 原型链

obj.__ proto . proto . proto __ …

Object.prototype === null

instanceof 用于推断援用范例属于哪一个组织函数

obj instanceob Foo

实际意义:推断 Foo.prototype 在不在 obj的原型链上

3.题目解答

3.1 怎样正确推断一个变量是数组

arr instanceof Array

3.2 写一个原型链继续的例子

封装dom查询

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,fun){
    var elem = this.elem;
    elem.addEventListener(type,fun);
    return this;
}

var div1 = new Elem('id1');
div1.html("test").on('click',function(){
    console.log('点击');
})

3.3 继续完成的其他体式格局

3.3.1 原型继续

        var obj = {
            0:'a',
            1:'b',
            arr:[1]
        }
        
        function Foo(arr2){
            this.arr2 = [1]
        }

        Foo.prototype = obj;

        var foo1 = new Foo();
        var foo2 = new Foo();

        foo1.arr.push(2);
        foo1.arr2.push(2);

        console.log(foo2.arr);  //[1,2]
        console.log(foo2.arr2); //[1]

长处:完成简朴

瑕玷:

1.没法向父类组织函数传参

2.同时new两个对象时转变一个对象的原型中的援用范例的属性时,另一个对象的该属性也会修正。由于来自原型对象的援用属性是一切实例同享的。

3.3.2 组织继续

        function Super(b){
            this.b = b;
            this.fun = function(){}
        }
        function Foo(a,b){
            this.a = a;
            Super.call(this,b);
        }

        var foo1 = new Foo(1,2);
        console.log(foo1.b);

长处:能够向父类传参,子类不会同享父类的援用属性

瑕玷:没法完成函数复用,每一个子类都有新的fun,太多了就会影响机能,不能继续父类的原型对象。

3.3.3 组合继续

function Super(){
    // 只在此处声明基础属性和援用属性
    this.val = 1;
    this.arr = [1];
}
//  在此处声明函数
Super.prototype.fun1 = function(){};
Super.prototype.fun2 = function(){};
//Super.prototype.fun3...
function Sub(){
    Super.call(this);   // 中心
    // ...
}
Sub.prototype = new Super();    

长处:不存在援用属性同享题目,可传参,函数可复用

瑕玷:父类的属性会被实例化两次,猎取不到真正实例父类(没法辨别实例是父类建立照样父类建立的)

优化:

         function Super(b){
            this.b = b;
            this.fun = function(){}
        }

        Super.prototype.c = function(){console.log(1111)}

        function Foo(a,b){
            this.a = a;
            Super.call(this,b);
        }


        Foo.prototype = Super.prototype;
        //修复组织函数:
        var foo1 = new Foo(1,2);

瑕玷:没法辨别实例是父类建立照样子类建立的

3.3.4 寄生组合继续

         function Super(b){
            this.b = b;
        }

        Super.prototype.c = function(){console.log(1111)}

        function Foo(a,b){
            this.a = a;
            Super.call(this,b);
        }

        var f = new Function();
        f.prototype = Super.prototype;
        Foo.prototype = new f();
        //等同于 Foo.prototype = Object.create(Super.prototype);
        
        var foo1 = new Foo(1,2);

对父类的prototype举行一次寄生,即包装成一个空对象的prototype,再把这个对象实例化出来作为子类的peototype。

瑕玷:没法辨别实例是父类建立照样子类建立的

能够增加以下代码:

Foo.prototype.constructor = Foo

这类处理要领不能用于上面的组合优化要领,由于子类父类援用的是同一个原型对象,修正会同时修正。

总结:

继续主如果完成子类对父类要领,属性的复用。

来自原型对象的援用属性是一切实例同享的,所以我们要防止从原型中继续属性。

在组织函数中经由过程call函数能够继续父类组织函数的属性和要领,然则经由过程这类体式格局实例化出来的实例会将父类要领屡次存储,影响机能。

经由过程组合继续我们运用call继续属性,运用原型继续要领,能够处理以上两个题目,然则经由过程这类体式格局实例化出来的对象会存储两份父类组织函数中的属性。

用父类的原型组织一个新对象作为子类的原型,就处理了屡次存储的题目,所以终究的寄生组合继续就是最好继续体式格局,它的瑕玷就是誊写起来比较贫苦。

3.3.6 node源码中的继续完成


function inherits(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
}; 

function Stream(){
    //...
}

function OutgoingMessage() {
  Stream.call(this);
  //...
}

inherits(OutgoingMessage, Stream);

OutgoingMessage.prototype.setTimeout = ...

以上是寄生组合继续的一个实例。

1.在OutgoingMessage组织函数中经由过程call继续Stream组织中的属性。

2.挪用inherits要领继续Stream原型中的属性。

3.扩大OutgoingMessage本身原型的函数。

inherits要领中运用了Object.create要领,该要领的作用是经由过程指定的原型对象和属性建立一个新的对象。

ctor.prototype=Object.create(superCtor.prototype,{.....});

该要领实际上就做了我们上面寄生组合继续中的事情

var f = new Function();
f.prototype =superCtor.prototype;
return new f();

背面的参数是给原型对象增加属性,可选属性(非必填),即把本身作为新建立对象的组织函数。

value: 示意constructor 的属性值;
writable: 示意constructor 的属性值是不是可写;[默以为: false]
enumerable: 示意属性constructor 是不是能够被罗列;[默以为: false]
configurable: 示意属性constructor 是不是能够被设置,比方 对obj.a做 delete操纵是不是许可;[默以为: false]

3.4 es6继续的完成体式格局

参考我这篇文章:https://segmentfault.com/a/11…

3.5 形貌new一个对象的历程

  1. 建立一个对象
  2. {}._proto_ = 组织函数.prototype
  3. this指向这个对象
  4. 实行代码即对this赋值
  5. 返回this

3.6 zepto及其他源码中怎样运用原型链

var Zepto = (function(){

    var $,zepto = {}
    
    // ...省略N行代码...
    
    $ = function(selector, context){
        return zepto.init(selector, context)
    }

    zepto.init = function(selector, context) {
        var dom
        
        // 针对参数状况,分别对dom赋值
        
        // 终究挪用 zepto.Z 返回的数据
        return zepto.Z(dom, selector)
    }    

   fnction Z(dom, selector) {
      var i, len = dom ? dom.length : 0
     for (i = 0; i < len; i++) this[i] = dom[i]
      this.length = len
      this.selector = selector || ''
    }

   zepto.Z = function(dom, selector) {
     return new Z(dom, selector)
   }
  
    $.fn = {
        // 内里有若干个东西函数
    }
      
  
    zepto.Z.prototype = Z.prototype = $.fn
  
    
    // ...省略N行代码...
    
    return $
})()

window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)
    原文作者:ConardLi
    原文地址: https://segmentfault.com/a/1190000017816152
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞