最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 2021-05-12 JavaScript基础-原型与原型链

    正文概述 掘金(徐茂增)   2021-03-29   466

    面向对象

    面向对象编程(Object Oriented Programming,缩写OOP):将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟,其有三个特征:封装、继承和多态

    对象

    • 对象是单个实物的抽象
    • 对象是一个容器,封装了属性(property)和方法(method)

    构造函数:就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构,为了与普通函数区别,构造函数名字的第一个字母通常大写

    有两个特点:

    • 函数体内部使用了this关键字,代表了所要生成的对象实例
    • 生成对象的时候,必须使用new命令

    new命令运行的基本原理:

    1. 创建一个空对象,作为将要返回的实例对象
    2. 将这个空对象的原型,指向构造函数的prototype属性
    3. 将空对象赋值给函数内部的this关键字
    4. 开始执行构造函数内部的代码

    new命令的内部运行代码:

    function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
      // 将 arguments 对象转为数组
      var args = [].slice.call(arguments);
      // 取出构造函数
      var constructor = args.shift();
      // 创建一个空对象,继承构造函数的 prototype 属性
      var context = Object.create(constructor.prototype);
      // 执行构造函数
      var result = constructor.apply(context, args);
      // 如果返回结果是对象,就直接返回,否则返回 context 对象
      return (typeof result === 'object' && result != null) ? result : context;
    }
    
    // 实例
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    var actor = _new(Person, '张三', 28);
    

    使用new.target属性可以判断函数调用的时候,是否使用new命令

    Object.create() 创建实例对象: 构造函数作为模板,可以生成实例对象。但是,有时拿不到构造函数,只能拿到一个现有的对象。我们希望以这个现有的对象作为模板,生成新的实例对象,这时就可以使用Object.create()方法,继承了前者的属性和方法

    this关键字

    简单说,this就是属性或方法“当前”所在的对象

    • 它总是返回一个对象
    • 由于对象的属性可以赋给另一个对象,所以属性所在的当前对象是可变的,即this的指向是可变的
    • 它的设计目的就是在函数体内部,指代函数当前的运行环境
    使用场合
    1. 事件调用环境——谁触发事件,指向谁
    2. 全局环境——window(浏览器环境)、module.exports(node环境),严格模式都是undefined
    3. 构造函数——构造函数中的this,指的是实例对象
    4. 对象的方法——如果对象的方法里面包含thisthis的指向就是方法运行时所在的对象。该方法赋值给另一个对象,就会改变this的指向
    5. 在箭头函数中——指的是函数定义生效时所在的对象,而不是使用时所在的对象
    this的五种绑定规则(除了箭头函数,this总是指向调用该函数的对象)
    1. 默认绑定(严格/非严格模式):指向全局对象或者undefined
    2. 隐式绑定:上下文对象
    3. 显示绑定:使用callapplybind
    4. new绑定
    5. 箭头函数绑定: - 箭头函数不绑定this,箭头函数中的this相当于普通变量,指向外层作用域,对象没有单独的作用域 - 箭头函数的this寻值行为与普通变量相同,在作用域中逐级寻找 - 箭头函数的this无法通过bindcallapply来直接修改(可以间接修改) - 改变作用域中this的指向可以改变箭头函数的this - eg. function closure(){()=>{//code }},在此例中,我们通过改变封包环境closure.bind(another)(),来改变箭头函数this的指向
    使用注意点
    • 避免多层 this,由于this的指向是不确定的,所以切勿在函数中包含多层的this,使用一个变量固定this的值,然后内层函数调用这个变量,是非常常见的做法
    • 避免数组处理方法中的 this,数组的mapforeach方法,允许提供一个函数作为参数。这个函数内部不应该使用this,解决这个问题的一种方法,就是前面提到的,使用中间变量固定this;另一种方法是将this当作foreach方法的第二个参数,固定它的运行环境
    • 避免回调函数中的 this,回调函数中的this往往会改变指向,最好避免使用,为了解决这个问题,可以采用下面的一些方法对this进行绑定,也就是使得this固定指向某个对象,减少不确定性
    绑定 this的方法

    this的动态切换,固然为 JavaScript 创造了巨大的灵活性,但也使得编程变得困难和模糊。有时,需要把this固定下来,避免出现意想不到的情况。JavaScript 提供了callapplybind这三个方法,来切换/固定this的指向

    1. Function.prototype.call():函数实例的call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数,call方法的参数,应该是一个对象。如果参数为空、nullundefined,则默认传入全局对象,如果call方法的参数是一个原始值,那么这个原始值会自动转成对应的包装对象,然后传入call方法,形式如func.call(thisValue, arg1, arg2, ...)
    2. Function.prototype.apply()apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数,使用格式如下:func.apply(thisValue, [arg1, arg2, ...]),利用这一点,可以做一些有趣的应用: - 找出数组最大元素 - 将数组的空元素变为undefined - 转换类似数组的对象 - 绑定回调函数的对象
    3. Function.prototype.bind()bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数,bind()方法有一些使用注意点: - 每一次返回一个新函数 - 结合回调函数使用 - 结合call()方法使用

    原型与原型链

    prototype属性:每个函数都有一个prototype属性,指向一个对象,原型对象的所有属性和方法,都能被实例对象共享

    function f(){}
    f.prototype // f {}
    typeof f.prototype // 'object'
    

    函数默认具有prototype属性,对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型 总结一下,原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象 原型链:JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型…… 如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了Object.prototype的属性。这就是所有对象都有valueOftoString方法的原因,因为这是从Object.prototype继承的 那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是nullnull没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null

    constructor属性prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数

    function P(){}
    P.prototype.constructor === P // Function: P
    

    由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承

    function P() {}
    var p = new P();
    
    p.constructor === P // true
    p.constructor === P.prototype.constructor // true
    p.hasOwnProperty('constructor') // false
    

    constructor属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的 修改原型对象时,一般要同时修改constructor属性的指向 如果不能确定constructor属性是什么函数,还有一个办法:通过name属性,从实例得到构造函数的名称

    function Foo() {}
    var f = new Foo();
    f.constructor.name // "Foo"
    

    __proto__属性:这个属性是每个实例对象特有的(当然构造函数也有),指向函数的prototype原型对象,让实例找到自己的原型对象,查找原型链用的

    function P(){}
    var p = new P();
    p.__proto__ === P.prototype // P {}
    
    function A(){}
    var a = new A();
    A.prototype // A {}
    Function.prototype // [Function]
    Object.prototype // {}
    
    a.__proto__ // A {}
    a.__proyo__.__proto__ // {}
    a.__proto__.__proto__.__proto__ // null
    

    Object对象相关方法

    • Object.getPrototypeOf():返回参数对象的原型。这是获取原型对象的标准方法

      var F = function () {};
      var f = new F();
      Object.getPrototypeOf(f) === F.prototype // true
      

      下面是几种特殊对象的原型

      // 空对象的原型是 Object.prototype
      Object.getPrototypeOf({}) === Object.prototype // true
      
      // Object.prototype 的原型是 null
      Object.getPrototypeOf(Object.prototype) === null // true
      
      // 函数的原型是 Function.prototype
      function f() {}
      Object.getPrototypeOf(f) === Function.prototype // true
      
    • Object.setPrototypeOf():为参数对象设置原型,返回该参数对象。它接受两个参数,第一个是现有对象,第二个是原型对象

      var a = {};
      var b = {x: 1};
      Object.setPrototypeOf(a, b);
      
      Object.getPrototypeOf(a) === b // true
      a.x // 1
      
    • Object.create():该方法接受一个对象作为参数,然后以它为原型,返回一个实例对象。该实例完全继承原型对象的属性

      // 原型对象
      var A = {
        print: function () {
          console.log('hello');
        }
      };
      
      // 实例对象
      var B = Object.create(A);
      
      Object.getPrototypeOf(B) === A // true
      B.print() // hello
      B.print === A.print // true
      
    • Object.prototype.isPrototypeOf():实例对象的isPrototypeOf方法,用来判断该对象是否为参数对象的原型

      var o1 = {};
      var o2 = Object.create(o1);
      var o3 = Object.create(o2);
      
      o2.isPrototypeOf(o3) // true
      o1.isPrototypeOf(o3) // true
      
    • Object.prototype.__proto__:实例对象的__proto__属性(前后各两个下划线),返回该对象的原型

    • 获取原型对象方法的比较:

      • obj.__proto__
      • obj.constructor.prototype
      • Object.getPrototypeOf(obj) 推荐
    • Object.getOwnPropertyNames:返回一个数组,成员是参数对象本身的所有属性的键名,不包含继承的属性键名

    • Object.prototype.hasOwnProperty():返回一个布尔值,用于判断某个属性定义在对象自身,还是定义在原型链上

    • Object.keys():用来遍历对象的属性,参数是一个对象,返回一个数组;该数组的成员都是该对象自身而不是继承的所有属性名

    • Object.getOwnPropertyNames():返回包括不可枚举的所有属性名

    • Object.prototype.valueOf():返回一个对象的‘值’,默认情况下返回对象本身

    • Object.prototype.toString():返回一个对象的字符串形式,默认情况下返回类型字符串,其主要应用是判断数据类型

    参考链接

    • 网道/WangDoc.com-JavaScript教程/面向对象编程-wangdoc.com/javascript/….
    • Object对象的静态方法-wangdoc.com/javascript/…

    起源地下载网 » 2021-05-12 JavaScript基础-原型与原型链

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元