精华内容
下载资源
问答
  • 是一种用户定义的引用数据类型,也称类类型。每个类包含数据说明和一组操作数据或传递信息的函数。类的实例称为对象。构成 类由类名、构造函数、属性、方法组成。属性、方法属于成员,可以分为公共成员,保护成员...

    定义

    class是面向对象程序设计实现信息封装的基础。类是一种用户定义的引用数据类型,也称类类型。每个类包含数据说明和一组操作数据或传递信息的函数。类的实例称为对象。

    构成

    类由类名、构造函数、属性、方法组成。属性、方法属于成员,可以分为公共成员,保护成员、私有成员。

    定义类

    声明一个仅有类名的类。

    class Year{
      constructor(){

      }
    }

    // 简写
    class Year{

    }
    1cace6154e9a1ee6cd61497984245f1c.png

    公共属性

    公共属性可以被实例对象访问或修改,类的属性默认是公共属性。

    class Year{
      constructor(year){
        this.year = year;  // 公共属性
      }
    }
    let yearCs = new Year(2021);
    console.log(yearCs.year);  // 2021
    59a5f58c626b49815c74c1ba50df0194.png

    私有属性

    私有属性不可以被实例对象访问,仅在类的内部访问或修改,写法是使用一个#作为前缀。

    class Year{
      constructor(year){
        this.year = year;
      }
      #month = 1;  // 私有属性
    }
    let yearCs = new Year(2021);
    console.log(yearCs['#month']);  // undefined
    3bbe5fb7fe594e13ee848cca12b42657.png

    静态属性

    静态属性是使用关键字static声明,将静态属性添加到类的构造函数中,用类本身访问或修改。

    class Year{
      constructor(year){
        this.year = year;
      }
      #month = 1;
      static day = 1;  // 静态属性
    }
    let yearCs = new Year(2021);
    console.log(Year.day);  // 1
    70545a936505970f8eb37b4a5bdb7d8e.png

    静态私有属性

    静态私有属性是使用关键字static#声明,将静态私有属性添加到类的构造函数中,不能被用类本身访问。

    class Year{
      constructor(year){
        this.year = year;
      }
      #month = 1;
      static day = 1;
      static #hour = 1;  // 静态私有属性
    }
    console.log(Year['#hour']);  // undefined
    d6a54f7808b8eff8dba9356b0e5e137f.png

    属性对比

    Class方式定义类与Function定义类的区别,想想输出的内容,欢迎留言哦!

    /**
     * Class定义类
     */

    class YearClass{
      constructor(year){
        this.year = year;
      }
      #month = 1;
      static day = 1;
      static #hour = 1;
    }
    let yearCs = new YearClass(2021);
    console.log(yearCs.year);  // ???
    console.log(yearCs['#month']);  // ???
    console.log(YearClass.day);  // ???
    console.log(YearClass['#hour']);  // ???

    /**
     * Function 方式定义类
     */

    function YearFunction(year){
      this.year = year;
      this['#month'] = 1;
    }
    YearFunction.day = 1;
    YearFunction['#hour'] = 1;
    let yearFn = new YearFunction(2021);
    console.log(yearFn.year);  // ???
    console.log(yearFn['#month']);  // ???
    console.log(YearFunction.day);  // ???
    console.log(YearFunction['#hour']);  // ???
    a21387f57cf4e34edcb6a7b2dd3c0882.png
    Class
    cc8c46570d6a6762596d593e85c7f205.png
    Function

    公共方法

    公共方法可以被实例对象调用。

    class Year{
      constructor(year){
        this.year = year;
      }
      #month = 1;
      getYear(){
        return `今夕是何年${this.year},何月${this.#month}`;
      }
      setYear(year){
        this.year = year;
        this.#month = year%2;
      }
    }

    let yearCs = new Year(2021);
    console.log(yearCs.year, yearCs['#month']);  // 2021 undefined
    console.log(yearCs.getYear());  // 今夕是何年2021,何月1
    yearCs.setYear(2022);
    console.log(yearCs.getYear());  // 今夕是何年2022,何月0
    61b86057f7436107366ff2863c10e95a.png

    定义类Year,包括公共属性year、私有属性#month,公共方法getYearsetYear。实例对象仅可以访问公共成员,在类的内部可以访问、修改私有属于#month,可以保护类的内部数据,虽然,实例对象不能访问私有成员,但是在实例对象的节点上是暴露相关信息。

    私有方法

    私有方法不可以被实例对象调用,写法是使用一个#作为前缀。

    class Year{
      constructor(year){
        this.year = year;
      }
      #month = 1;
      getYear(){
        return `今夕是何年${this.year}`;
      }
      #getMonth(){
        return `今夕是何月${this.#month}`;
      }
    }

    let yearCs = new Year(2021);
    console.log(yearCs['getYear']());  // 今夕是何年2021
    console.log(yearCs['#getMonth']());  // Uncaught TypeError: yearCs.#getMonth is not a function
    773b1c6689a017fe21c5518b71fbcb9d.png

    公共方法可以被实例对象访问,私有方法不可以被实例对象访问,强制访问会报错哦。高能预警:公共方法getYear是在原型链上,私有方法#getMonth在实例上。

    静态方法

    静态方法是使用关键字static声明,将静态方法添加到类的构造函数中,用类本身调用。

    class Year{
      constructor(year){
        this.year = year;
      }
      #month = 1;
      static day = 1;
      getYear(){
        return `今夕是何年${this.year}`;
      }
      #getMonth(){
        return `今夕是何月${this.#month}`;
      }
      static getDay(){
        return `今夕是何天${this.day}`
      }
    }

    let yearCs = new Year(2021);
    console.log(Year.getDay());  // 今夕是何天1
    f76d792d5e473fa5556d53be5acd4485.png

    静态方法是通过类调用。静态方法在类的构造函数上。

    静态私有方法

    class Year{
      constructor(year){
        this.year = year;
      }
      #month = 1;
      static day = 1;
      static #hour = 1;
      getYear(){
        return Year.#getHour();
      }
      #getMonth(){
        return `今夕是何月${this.#month}`;
      }
      static getDay(){
        return Year.#getHour(); 
      }
      static #getHour(){
        return `今夕是何时${Year.#hour}`;
      }
    }

    let yearCs = new Year(2021);
    console.log(Year['#getHour']());  // Uncaught TypeError: Year.#getHour is not a function
    console.log(Year.getDay());  // 今夕是何时1
    console.log(yearCs.getDay());  // 今夕是何时1
    5dad26a448a165be05e699bec806dc5b.png

    静态私有方法不能被类本身调用,但是,可以把静态私有方法给公共方法或静态公共方法内部调用。静态私有方法在类的构造函数上。

    方法对比

    Class方式定义类与Function定义类的区别,想想输出的内容,欢迎留言哦!

    class YearClass{
      constructor(year){
        this.year = year;
      }
      #month = 1;
      static day = 1;
      static #hour = 1;
      getYear(){
        return `今夕是何年${this.year}`;
      }
      #getMonth(){
        return `今夕是何月${this.#month}`;
      }
      static getDay(){
        return `今夕是何天${Year.day}`;
      }
      static #getHour(){
        return `今夕是何时${Year.#hour}`;
      }
    }
    let yearCs = new YearClass(2021);
    console.log(yearCs.getYear());  // ???
    console.log(yearCs.#getMonth());  // ???
    console.log(YearClass.getDay());  // ???
    console.log(YearClass.#getHour());  // ???


    function YearFunction(year){
      this.year = year;
      this.#month = 1;
    }

    YearFunction.day = 1;
    YearFunction.#hour = 1;

    YearFunction.prototype.getYear = function getYear(){
      return `今夕是何年${this.year}`;
    };
    YearFunction.getDay = function getDay(){
      return `今夕是何天${Year.day}`;
    }

    YearFunction.#getHour = function #getHour(){
      return `今夕是何时${Year.#hour}`;
    }

    let yearFn = new YearFunction(2021);
    console.log(yearFn.getYear());  // ???
    console.log(YearFunction().getDay());  // ???
    console.log(YearFunction().#getHour());  // ???
    0eff58c67925256b063885330169372a.png
    Class
    3376ec8c625e093851c7a48d7daf5c1e.png
    Function

    总结

    关于Class,公共属性、私有属性、私有方法挂在实例对象上,静态公共属性、静态私有属性、静态私有方法在类的构造函数上,公共方法在原型链上。

    关于Function,公共属性挂在实例对象上,静态公共属性、静态公共方法在类的构造函数上,公共方法原型链

    经常有人说classfunction的语法糖,其实,随着时间的推移,class关键字不仅仅是function语法糖,更具有新特性,如私有属性、私有方法是function类不具备的,而且class定义的方法比function定义的方法优化了,去掉了function定义方式产生的prototype部分。

    调用对象的属性或方法时,我们都知道obj.nameobj['name']是一样的效果。今天给大家展示一个特列:

    function YearFunction(year){
      this.year = year;  // 公共属性
      this['#month'] = 1;  // 公共属性
      this.#month = 1;  // Uncaught SyntaxError: Private field '#month' must be declared in an enclosing class
    }

    let yearFn = new YearFunction(2021);

    语法错误:私有字段必需在类Class中声明。

    a32af4b0fc2c519dd2c20ec23556f4fe.png

    关注哦!优质原创文章在这里等你哦!

    展开全文
  • 、如何判断个对象是否可以被回收? ①、枚举根节点做可达性分析(根搜索路径算法) 为了解决引用计数法的循环引用...从GC Roots的对象开始向下搜索,如果个对象到GC Root没有任何引用链相连时,则说明此对...

     一、如何判断一个对象是否可以被回收?

    ①、枚举根节点做可达性分析(根搜索路径算法)

    为了解决引用计数法的循环引用问题,Java使用了可达性分析的方法。

    对于我们的几种算法:复制、标清、标整,--->都要使用GC引用遍历

    基本思路就是通过一系列名为“GC Roots"的对象作为起始点。从GC Roots的对象开始向下搜索,如果一个对象到GC Root是没有任何引用链相连时,则说明此对象不可用。。

    二、Java中怎样的对象会做为”GC Roots"?

    答:Ⅰ①虚拟机栈(栈帧中的局部变量区,也叫局部变量表)中引用的对象。

    ②方法区的类静态属性引用的对象。

    ③方法区中常量引用的对象。

    ④本地方法栈中JNI(Native方法)引用的对象。

    代码演示:

    什么样的对象不可用?

    从GC Roots的对象开始向下搜索,如果一个对象到GC Root是

    没有任何引用链相连时,则说明此对象不可用。

     

    展开全文
  • 前面提到,引用是一种数据类型,而且不是对象,所以它不可能按引用传递,所以它是按值传递的,它么它的值究竟是什么呢?是对象的地址。  由此可见,对象作为参数的时候是按值传递的,对吗?错!为什么错,让我们看...
  • 工厂模式:工厂模式是一种经常被使用到的模式,根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例, 通常这一组类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了...
  • 是一种非常简单的语言。其后越来越多的人们注意到了这种语言并对其扩展提出了各种建议。在许多人的无私奉献下以及这种语言本身的源代码自由性质,它演变成为一种特点丰富的语言,而且现在还在成长中。 PHP虽然很...
  • 这里有另外一种方法,如果你想多学一点东西,请接着往下看。 选中所有的尾注文本,点“格式︱字体”,改为“隐藏文字”,切换到普通视图,选择“视图︱脚注”,此时所有的尾注出现在窗口的下端,在“尾注”下拉列表...
  • php高级开发教程说明

    2008-11-27 11:39:22
    尽管它被称之为一种语言,但P H P并不是一种真正独立 的语言,而是许多语言的混和体。它主要用C的句法,但与C有很大不同。它是被解释的, P H P 能识别不同的变量类型,但没有严格的类型检查, P H P识别类,但没有...
  • 我已经尝试通过Add to Bulid path和在Porperties当中Add Extern Jars两种方法了,如图所示Reference Libraries当中已经添加了我所需要的jar了,但是我在import的时候仍然is not accessible,并且不可引用其中的class...
  • jQuery.sub() jQuery 1.5提供了一种创建和修改jQuery副本的方式。可以用来添加不向外部公开的方法,或者对jQuery的某些方法进行重新定义以提供新功能,或者提供更好的封装、避免名称空间冲突。当然,也可以用来开发...
  • 嗨,你真的懂this吗?

    2020-12-02 23:21:09
    隐式绑定的丢失发生在回调函数中(事件回调也其中一种),我们来看下面一个例子: <pre><code>javascript function sayHi(){ console.log('Hello,', this.name); } var person1 = { name: '...
  • 关于js 判断数据类型的方法js 判断数据类型的方法有哪几?关于 == 和 === 的区别?关于 == 的一些说明关于 === 全等于的一些说明JS 中类型转换有哪些?关于闭包什么闭包?闭包有哪些作用?闭包有那些表现形式? 缘起

    缘起

    笔者最近在近两周的面试中, 遇到了大大小小形形色色的面试题。很多问题都是知道但是说不出来,所以想记录下来, 希望可以帮到大家,也可以方便自己以后查阅。
    面试题无疑就是那几种类型的题, 所以笔者将按分类 分几次发, 也会有对应的问题扩展的解答。 希望可以帮到大家。
    说明一下,面试题远不止这些,笔者只是就自己所遇到的做一个记录。若有说的不对的地方,还请大家指出来,大家共同进步!

    Js基础的数据类型相关问题

    1. Js 的基础数据类型有哪些?

    • null
    • undefined
    • boolean
    • string
    • number
    • symbol
    • bigint

    数据类型扩展问题

    1-1. js 的引用数据类型有哪些?

    引用数据类型:

    对象 Object(普通对象 Object, 数组对象 Array, 函数对象 Function, 正则对象 RegExp, 日期对象 Date, 数学函数 Math)

    1-2. 0.1+0.2 为什么不等于 0.3?

    0.10.2在转换成二进制后会无限循环,由于标准位数的限制后面多余的位数会被截掉,此时就已经出现了精度的损失,相加后因浮点数小数位的限制而截断的二进制数字在转换为十进制就会变成0.30000000000000004

    1-3. 为什么添加BigInt数据类型?

    由于js中,所有的数字都以双精度64位浮点格式表示,这导致JS中的Number无法精确表示非常大的整数,它会将非常大的整数四舍五入,也就是说 js 只能表示在-( 2^53 - 1) 到 2^53 - 1 之间的的数,任何超出范围的的数都可能会失去精度。所以需要BigInt ,BigInt 可以表示任意大的整数。

    console.log(999999999999999);  //=>10000000000000000
    
    // 由于精度受损,也会有一定的安全性问题,如下
    9007199254740992 === 9007199254740993;    // -> true 居然是true!
    
    

    更多关于 BigInt 的知识 点这里 这里就不过多的讲述了。

    1-4. null 是对象吗?

    typeof null // -> "object"
    

    答案: null 不是对象;

    原因:
    虽然使用 typeof 判断 null 的数据类型为 object,但是 null 不是对象 。这也是js 存在的一个有机的 Bug。 在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象然而 null 表示为全零,所以将它错误的判断为 object

    关于js 判断数据类型的方法

    js 判断数据类型的方法有哪几种?

    方法1. 使用 typeof 判断数据类型

    对于原始数据类型而言, 除了 null 都可以使用typeof 判断出正确的数据类型。

    对于引用数据类型, 除了function ,都显示为 "object"

    缺点: 使用 typeof 判断引用数据类型的数据并不准确。

    方法2. 使用instanceof 判断数据类型

    instanceof的原理其实就是基于原型链的查询,只要是在原型链上能找到的都返回 true

    注意:

    1 instanceof Number // false
    '1' instanceof String  // false
    
    let a= {};
    a instanceof Object  // true
    

    大家也可以尝试一下;
    缺点: 实际上相对于基础数据类型的话 instanceof 是不能准确的判断数据类型的。

    方法3. 使用 Object.prototype.toString.call 方法判断

    实际是继承Object 的原型方法判断

    Object.prototype.toString.call('1')  //  "[object String]"
    Object.prototype.toString.call(1)  //  "[object Number]"
    Object.prototype.toString.call({})  //  "[object Object]"
    

    使用这个方法就可以对基本数据类型和引用数据类型的做一个区分了。

    关于 == 和 === 的区别?

    关于 == 的一些说明

    == 会对等式两边的值 自动转换数据类型之后在比较。

    '1'==1  //  true
    

    由此可以看出,== 只要两边的值相等,就会返回true(NaN 除外,NaN 不等于任何数值,包括他本身)。
    == 的转换规则如下:

    • 两边数据类型相同,就比较值的大小是否相等;
    • 数据类型不同时:

    1.判断双方是否为 nullundefined;是的话返回 true

    null == undefined  //  true
    null == null  //  true
    undefined == undefined  //  true
    

    .
    2. 判断数据类型是否为 stringnumber;是的话 将 string 转为 number 再比较。

    '1' == 1  // true
    

    .
    3. 判断其中一方是否为 Boolean; 是的话就把Boolean 转化成 Number,再比较(true 为 1,false为 0)。
    4. 如果其中一方为 Object,且另一方为StringNumber或者Symbol,会将Object转换成字符串,再进行比较。

    console.log({a: 1} == true);//false
    console.log({a: 1} == "[object Object]");//true
    

    .

    关于 === 全等于的一些说明

    === 不会自动转换数据类型,也叫严格相等。如果等式两边表达式的数据类型不一致 , 就会直接返回false;也就是说等式两边的数据类型都要相等才会返回true

    所以避免出现一些错误的判断都建议使用 === 来对数据进行一个相等判断;

    注意:由于 NaN 的特殊性,只要等式两边由一方为 NaN 都会返回false

    当然也有判断 NaN 的方法,那就是 isNaN() 函数

    isNaN(NaN)  //  true
    

    JS 中类型转换有哪些?

    主要分为三类:

    • 转为数字
    • 转为字符串
    • 装维布尔值
      具体转换规则如下:
      js数据类型转换
      图表形式:
      在这里插入图片描述

    关于闭包

    什么是闭包?闭包有哪些作用?

    (红宝书)闭包是指那些引用了另外一个函数作用域中变量的函数,通常是在嵌套函数中实现的。

    闭包的作用:

    • 读取函数内部的变量
    • 让这些变量的值保存在内存里面,实现数据共享

    闭包不能滥用,否则会导致内存泄露,影响网页的性能。闭包使用完了后,要立即释放资源,将引用变量指向null

    闭包有那些表现形式?

    1.函数作为返回值

    var num = 2
    function outer() {
     var num = 0 //内部变量
     return function add() {
     //通过return返回add函数,就可以在outer函数外访问了。
     num++ //内部函数有引用,作为add函数的一部分了
     console.log(num)
     }
    }
    
    var func1 = outer() //
    func1() //实际上是调用add函数, 输出1
    

    2.函数作为参数传递

    var num = 2
    function outer() {
     var num = 0 //内部变量
     function add() {
     	num++ //内部函数有引用,作为add函数的一部分了
     	console.log(num)
     }
     foo (add)
    }
    function foo (fn){
      // 函数以参数的方式传递执行 闭包 
    	fn()
    }
    
    outer() // 1
    

    3.在定时器、事件监听、Ajax请求、跨窗口通信、Web Workers或者任何异步中,只要使用了回调函数,实际上就是在使用闭包。

    保存了全局作用域 window当前作用域

    setTimeOut(function timeHandler(){
    	console.log(123)
    },100)
    

    4.立即执行函数(IIFE)也是闭包的形式,保存了 全局作用域window当前函数作用域。可以使用全局变量。

    var num = 5;
    (function init(){
    	console.log(num)  // 5
    })()
    

    闭包的经典笔试题

    1.以下代码输出什么 ? 为什么 ? 如何修改 ?

     for ( var i=1;i<=5;i++) {
        setTimeout(function timer(){
              console.log(i);
         },i*1000)
    }
    

    因为setTimeout 是一个宏任务,在主线程主任务执行完之后才执行宏任务。因此,在循环结束之后才会执行 setTimeout回调。这个时候要使用 i 当前作用域下面并没有,就为向上级查找,这个时候的 i 变成了6, 所以会输出一堆6

    解决办法
    1. 使用 闭包(立即执行函数的形式)

    for ( var i=1;i<=5;i++) {
      (function (j){
    	setTimeout(function timer(){
              console.log(j);
         },j*1000)
      })(i)  
    } // 1,2,3,4,5
    

    2. 使用 setTimeout的第三个参数

    for ( var i=1;i<=5;i++) {
        setTimeout(function timer(j){
              console.log(j);
         },i*1000,i)
    } // 1,2,3,4,5
    

    3. 使用ES6的 let 定义

     for ( let i=1;i<=5;i++) {
        setTimeout(function timer(){
              console.log(i);
         },i*1000)
    }
    

    由于let 的块级作用域,let 之后的作用域链也就不存在了。

    对原型链的理解

    JavaScript对象通过__proto__ 指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条, 即原型链。

    原型链的顶端是什么?

    原型链顶端是Object.prototype

    Object 的原型最后是什么?

    object 的原型最后的值是 null

    console.log(Object.prototype.__proto__ === null),返回true
    

    null 表示没有对象,即该处不应有值,所以Object.prototype没有原型。

    __proto__是什么

    function Person(){
    }
    

    绝大部分浏览器支持这个非标准的方法访问原型,然而它并不存在与Person.prototype中。

    实际上它来自Object.prototype,当使用obj.__proto__时,可以理解为返回来Object.getPrototype(obj)

    js有几种继承方法

    每个对象都会从原型继承属性,继承意味着复制操作,然而JS默认不会复制对象的属性,相反,JS只是在两个对象之间创建一个关联,这样子 一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承。

    以下继承方法参考js灵魂之问

    第一种: 借助call

     function Parent1(){
        this.name = 'parent1';
      }
      Parent1.prototype.add = function () {}
      
      function Child1(){
        Parent1.call(this);
        this.type = 'child1'
      }
      console.log(new Child1);
    

    注意: 这种方式子类只能拿到父类的属性,获取不到父类原型对象中的方法。
    在这里插入图片描述

    第二种: 原型链继承

      function Parent2() {
        this.name = 'parent2';
        this.play = [1, 2, 3]
      }
     Parent2.prototype.add = function () {}
     
      function Child2() {
        this.type = 'child2';
      }
      Child2.prototype = new Parent2();
    
      console.log(new Child2());
    

    结果如下:在这里插入图片描述
    这种方法是可以成功继承到父类的属性和原型方法,但是有个潜在的问题,如下:

      var s1 = new Child2();
      var s2 = new Child2();
      s1.play.push(4);
      console.log(s1.play, s2.play);
    

    在这里插入图片描述
    注意: 修改s1 的属性值, s2 的属性也变化了,因为两个实例使用的是同一个原型对象。

    call 和原型 的组合继承

      function Parent3 () {
        this.name = 'parent3';
        this.play = [1, 2, 3];
      }
       Parent3.prototype.add = function () {}
    
      function Child3() {
        Parent3.call(this); // 执行一次
        this.type = 'child3';
      }
      Child3.prototype = new Parent3();  // 执行两次
      console.log(new Child3 () )
      
      var s3 = new Child3();
      var s4 = new Child3();
      s3.play.push(4);
      console.log(s3.play, s4.play);
    
    

    在这里插入图片描述
    可以看到属性和方法都继承了,并且也没有共享实例的问题。但是这一种写法其实也有一个问题,那就是 Parent3 的构造函数会执行两次,增加了性能的消耗。

    组合继承 优化

      function Parent4 () {
        this.name = 'parent4';
        this.play = [1, 2, 3];
      }
       Parent4.prototype.add = function () {}
        
      function Child4() {
        Parent4.call(this);
        this.type = 'child4';
      }
      Child4.prototype = Parent4.prototype;
      console.log(new Child4())
    
    

    将父类原型对象直接给到子类,父类构造函数只执行一次,而且父类的属性和方法都能继承.
    在这里插入图片描述
    注意: 子类实例的构造函数 是Parent4,显然这是不对的,应该是Child4

    (推荐)寄生组合继承

      function Parent5 () {
        this.name = 'parent5';
        this.play = [1, 2, 3];
      }
       Parent5.prototype.add = function () {}
       
      function Child5() {
        Parent5.call(this);
        this.type = 'child5';
      }
      Child5.prototype = Object.create(Parent5.prototype);
      Child5.prototype.constructor = Child5;
    
    

    这是最推荐的一种方式,接近完美的继承,也是组合继承的进阶版。

    ES6 的extends 继承

    extends被编译之后的实现原理也是使用了 Object.create方法继承父类的静态方法。

    extends 的语法

    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    }
    
    class ColorPoint extends Point {
      constructor(x, y, color) {
        super(x, y);
        this.color = color; // 正确
      }
    }
    

    在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。

    面向对象的设计不一定是最好的,还是的依据具体的业务场景判断。

    继承的最大问题在于:无法决定继承哪些属性,所有属性都得继承。

    一方面父类是无法描述所有子类的细节情况的,为了不同的子类特性去增加不同的父类,代码势必会大量重复,另一方面一旦子类有所变动,父类也要进行相应的更新,代码的耦合性太高,维护性不好。

    那如何来解决继承的诸多问题呢?

    用组合,这也是当今编程语法发展的趋势,比如golang完全采用的是面向组合的设计方式
    顾名思义,面向组合就是先设计一系列零件,然后将这些零件进行拼装,来形成不同的实例或者类。
    这样复用性也很好,代码耦合小。

    .

    参考:
    原生JS灵魂之问
    yck前端面试之道
    原型链的详细讲解

    展开全文
  • C语言编程要点

    2017-09-18 00:10:37
    13.4. 存储日期的最好方法是一种? 193 13.5. 存储时间的最好方法是一种? 194 第14章 系统调用 194 14.1. 怎样检索环境变量(environment variables)的值? 195 14.2. 怎样在程序中调用DOS函数? 195 14.3. 怎样在...
  • JVM-逃逸分析

    2020-07-25 22:13:43
    逃逸分析: 就是分析Java对象的动态作用域,如果在方法内创建了个对象,而且外部对象能够引用到这个对象的话,这就是方法逃逸 (作用域逃出了这个方法) ,如果能够被其它线程使用到的话,这就是线程逃逸...

    JVM-逃逸分析

    jvm学习记录

    这个可以从一个问题入手:Java中的对象都是在堆中分配吗?说明为什么!
    这个很明显,稍微会点JVM知识的人都会知道,但是JVM是怎么来判断是否应该在堆上分配还是其它地方分配?

    主要有这两种逃逸情况,我们来聊一聊。

    • 方法逃逸
    • 线程逃逸

    1.什么是逃逸分析技术

    逃逸分析: 就是分析Java对象的动态作用域,如果在一个方法内创建了一个对象,而且外部对象能够引用到这个对象的话,这就是方法逃逸 (作用域逃出了这个方法) ,如果能够被其它线程使用到的话,这就是线程逃逸(作用域逃出了这个线程)

    逃逸分析(Escape Analysis)简单来讲就是,Java Hotspot 虚拟机可以分析新创建对象的使用范围,并决定是否在 Java 堆上分配内存的一项技术。

    	//下面两个方法,将创建的对象 s 返回,这样可以被其他方法或线程引用。
    	public String getStr(){
            String s = "这是个测试案例";
            return s;
        }
        public StringBuilder getStr1(){
            StringBuilder s = new StringBuilder();
            s.append("这是个测试案例");
            return s;
        }
        //下面就没有逃逸出这个方法
        public String getStr2(){
            StringBuilder s = new StringBuilder();
            s.append("这是个测试案例");
            return s.toString();
        }
    

    设置逃逸分析的 JVM 参数如下:

    • 开启逃逸分析:-XX:+DoEscapeAnalysis
    • 关闭逃逸分析:-XX:-DoEscapeAnalysis
    • 显示分析结果:-XX:+PrintEscapeAnalysis

    从jdk 1.7开始已经默认开始逃逸分析,如需关闭,需要指定-XX:-DoEscapeAnalysis

    2.逃逸分析算法

    个人能力有限,下面这段全靠百度。

    Java Hotspot 编译器实现下面论文中描述的逃逸算法:

    [Choi99] Jong-Deok Choi, Manish Gupta, Mauricio Seffano,
    Vugranam C. Sreedhar, Sam Midkiff,
    “Escape Analysis for Java”, Procedings of ACM SIGPLAN
    OOPSLA Conference, November 1, 1999

    根据 Jong-Deok Choi, Manish Gupta, Mauricio Seffano,Vugranam C.
    Sreedhar, Sam Midkiff 等大牛在论文《Escape Analysis for Java》中描述的算法进行逃逸分析的。

    该算法引入了连通图,用连通图来构建对象和对象引用之间的可达性关系,并在次基础上,提出一种组合数据流分析法。

    由于算法是上下文相关和流敏感的,并且模拟了对象任意层次的嵌套关系,所以分析精度较高,只是运行时间和内存消耗相对较大。

    3.逃逸分析优化

    利用逃逸分析,编译器可以进行如下优化:

    • 同步消除,也叫锁消除。
    • 标量替换
    • 栈上分配

    3.1、同步消除(锁消除)

    在JIT编译过程中,如果发现一个对象不会被其它线程(多线程)访问到,那么针对这个对象的同步措施就可以省略掉,即「锁销除」。例如 Vector 和 StringBuffer ,它们中的很多方法都是加了锁的,当某个对象确定是线程安全的情况下,JIT编译器会在编译这段代码时进行锁消除来提升效率。JDK8中,同步消除默认开启。

    就像下面这个方法

    public void func() {
        Object o = new Object();
        synchronized(o) {
            System.out.println(o);
        }
    }
    

    代码中对o这个对象进行加锁,但是o对象的生命周期只在func()方法中,并不会被其他线程所访问到,所以在JIT编译阶段就会被优化掉。优化成如下:

    public void func() {
        Object o= new Object();
        System.out.println(o);
    }
    

    或者

    //代码中createStringBuffer方法中的局部对象buf,
    //就只在该方法内的作用域有效,不同线程同时调用createStringBuffer()方法时,
    //都会创建不同的buf 对象,因此此时的append操作若是使用同步操作,就是白白浪费的系统资源
    //在开启逃逸分析与锁消除后,会自动将锁消除掉,减少每次获取锁的开销
    public static String createStringBuffer(String str1, String str2) {
            StringBuffer buf = new StringBuffer();
            buf.append(str1);// append方法是同步操作,里面加了synchronized
            buf.append(str2);
            return buf.toString();
        }
    

    这种优化是很好的,避免了对象加锁解锁的各种开销。

    -server //运行在server模式
    -XX:+DoEscapeAnalysis //开启逃逸分析
    -XX:+EliminateLocks  //开启锁消除
    

    3.2、标量替换

    首先要明白标量和聚合量
    「标量(Scalar)」是指无法再分解成更小粒度的数据,例如 Java 中的原始数据类型(int,long 等),相对如果一个数据可以继续分解,则称之为「聚合量(Aggregate)」,例如 Java对象,它可以将其成员变量分解。在 JIT 编译过程中,经过逃逸分析确定一个对象不会被其他线程或者方法访问,那么会将对象的创建替换成为多个成员变量的创建,称之为「标量替换」。

    假如我们只用到了它的部分属性的话就只需要在栈或者寄存器上创建它用到的成员标量,节省了内存空间,也提升了应用程序性能。

    如下代码演示:

    public static void main(String[] args) {
       test();
    }
    
    private static void test() {
       Point p = new Point1,2;
       System.out.println("p.x="+p.x+"; p.y="+p.y);
    }
    class Point{
        private int x;
        private int y;
    }
    

    以上代码中,p对象并没有逃逸出test方法,并且p对象是可以拆解成标量的。那么,JIT就会不会直接创建Point对象,而是直接使用两个标量int x ,int y来替代Point对象。
    它可能就会变成以下:

    private static void test() {
       int x = 1;
       int y = 2;
       System.out.println("p.x="+x+"; p.y="+y);
    }
    

    标量替换减少了对象创建需要的内存开销,可以减少GC的频率

    3.3、栈上分配

    「栈上分配」是指对象和数据不是创建在堆上,而是创建在栈上,随着方法的结束自动销毁。但实际上,JVM 例如常用的「HotSpot」虚拟机并没有实现栈上分配,实际是用「标量替换」代替实现的。

    4.线程逃逸

    简单点说就是:这个对象被其他线程访问到,比如赋值给了实例变量,并被其他线程访问到了。对象逃出了当前线程。

    线程中创建对象会首先在TLAB上尝试创建(这个是在堆上年轻代的Eden中的),但 TLAB 通常都很小,所以对象相对比较大的时候,会在 Eden 区的共享区域进行分配。

    TLAB 的全称是 Thread Local Allocation Buffer,JVM 默认给每个线程开辟一个 buffer 区域,用来加速对象分配。这个 buffer 就放在 Eden 区中。而没有分配的Eden区域就是共享区域了。

    展开全文
  • 1、java向上造型强制转换的好处这还...c++里面的虚函数java里面的接口向上造型一个泛型对象的引用例如,假设我们有很多箱子,每个箱子里都装有不同的水果,我们需要找到一种方法能够通用的处理任何一箱水果。更通...
  • JAVA面试题最全集

    2010-03-13 13:09:10
    2.J2EE是一种技术还是一种平台,他提供了那些技术。 3.什么是Application Server,它有什么功能和优点。 4.简单介绍连接池的优点和原理。 5.Web.xml的作用 四、其他 1.Web安全性的考虑(表单验证、浏览器Basic...
  •  继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而...
  • java 面试题 总结

    2009-09-16 08:45:34
    继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而...
  • java面试宝典

    2013-02-28 16:04:01
    21、当个对象被当作参数传递到方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底值传递还是引用传递? 10 22、我们在web 应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,...
  • 千方百计笔试题大全

    2011-11-30 21:58:33
    21、当个对象被当作参数传递到方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底值传递还是引用传递? 10 22、我们在web 应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,...
  • 最新Java面试宝典pdf版

    热门讨论 2011-08-31 11:29:22
    10、使用final关键字修饰个变量时,是引用不能变,还是引用的对象不能变? 11 11、"=="和equals方法究竟有什么区别? 11 12、静态变量和实例变量的区别? 12 13、是否可以从个static方法内部发出对非static方法...
  • C#微软培训教材(高清PDF)

    千次下载 热门讨论 2009-07-30 08:51:17
    C#--微软.NET的第语言 本书着重介绍语言本身,比较少涉及应用,不错的入门书,从头讲起,不怕不明白。 <<page 1>> page begin==================== 目 目目 目 录 录录 录 第部分 C#语言概述.4 ...
  • java面试题典 java 面试题 经典

    热门讨论 2010-06-18 13:42:36
    8. 用JAVA实现一种排序,JAVA类实现序列化的方法(二种)? 如在COLLECTION框架中,实现比较要实现什么样的接口? 49 9. 编程:编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 但是...
  • 2.22 有没有一种自动方法来跟踪联合的哪个域在使用? 59 枚举 60 2.23 枚举和一组预处理的#define有什么不同? 60 2.24 枚举可移植吗? 60 2.25 有什么显示枚举值符号的容易方法吗? 60 位域 60 2.26 一些...
  • Java面试宝典2010版

    2011-06-27 09:48:27
    10、在weblogic管理制台中对一个应用域(或者说是一个网站,Domain)进行jms及ejb或连接池等相关信息进行配置后,实际保存在什么文件中? 11、说说weblogic中一个Domain的缺省目录结构?比如要将一个简单的helloWorld.jsp...
  • java面试题

    2018-01-01 15:35:15
    76.4. 在weblogic管理制台中对一个应用域(或者说是一个网站,Domain)进行jms及ejb或连接池等相关信息进行配置后,实际保存在什么文件中? 86 76.5. 在weblogic中发布ejb需涉及到哪些配置文件 87 76.6. 如何在weblogic中...
  • C#微软培训资料

    2014-01-22 14:10:17
    章第章 第章 .NET 编 编 编程语言 程语言编程语言 程语言 C#.4 1.1 Microsoft.NET——场新的革命.4 1.2 .NET 与 C#.6 1.3 C#语言的特点.8 1.4 小 结 .11 第二章 运行环境 全面了解.NET....
  • java基础题 很全面

    2009-05-09 09:24:24
    16. 在weblogic管理制台中对一个应用域(或者说是一个网站,Domain)进行jms及ejb或连接池等相关信息进行配置后,实际保存在什么文件中? 22 17. 说说weblogic中一个Domain的缺省目录结构?比如要将一个简单的helloWorld....
  • 到底指针是一种数组,还是数组是一种指针?  6.11 我看到一些“搞笑”的代码,包含5["abcdef"]这样的“表达式”。这为什么是合法的C语言表达式呢?  数组的指针  6.12 既然数组引用会退化为指针,如果array是...
  • 到底指针是一种数组,还是数组是一种指针? 6.11 我看到一些“搞笑”的代码,包含5["abcdef"]这样的“表达式”。这为什么是合法的C语言表达式呢? 数组的指针 6.12 既然数组引用会退化为指针,如果array是数组,...
  • 到底指针是一种数组,还是数组是一种指针? 6.11 我看到一些“搞笑”的代码,包含5["abcdef"]这样的“表达式”。这为什么是合法的C语言表达式呢? 数组的指针 6.12 既然数组引用会退化为指针,如果array是数组...

空空如也

空空如也

1 2 3 4 5 6
收藏数 103
精华内容 41
关键字:

引用是一种说明方法吗