Part5:数据类型检测、回调函数、发布订阅、继承

一、数据类型检测

1.typeof
/*
 * typeof:用来检测数据类型的运算符
 *    typeof [value]
 * @return
 *    首先是个字符串
 *    字符串中包含对应的数据类型,例如:"number"、"object"、"undefined"、"function"、"boolean"、"symbol"...
 * @局限性
 *    typeof null  =>"object"
 *    不能具体区分对象数据类型的值(无法检测是正则还是数组等)
 *    typeof []    =>"object"
 *    typeof {}    =>"object"
 *    typeof /^$/  =>"object"
 * @优势
 *    使用方便,所以在真实项目中,我们也会大量应用它来检测,尤其是在检测基本类型值(除null之外)和函数类型值的时候,它还是很方便的
 */
/* function func(n, m, callback) {
	/!* 形参赋值默认值 *!/
	//=>ES6: func(n = 0, m = 0)
	//=>检测形参的值是否为UNDEFINED
	// n === undefined ? n = 0 : null;
	// typeof m === "undefined" ? m = 0 : null;
	//=>基于逻辑或和逻辑与处理(瑕疵:不仅仅是不传赋值默认值,如果传递的值是假也会处理成为默认值)
	// n = n || 0;
	// m = m || 0;

	/!* 回调函数执行 *!/
	// typeof callback === "function" ? callback() : null;
	// callback && callback(); //=>瑕疵:传递的为真即可执行,不一定是一个函数,这样写是开发者心里已经知道,要不然不传,要传就是一个函数
}
func(10, 20, function anonymous() {}); */
2.instanceof & constructor
/*
 * instanceof:本意是用来检测实例是否隶属于某个类的运算符,我们基于这样的方式,也可以用来做某些数据类型的检测,例如:数组、正则等
 * @局限性
 *    不能处理基本数据类型值
 *    只要在当前实例的原型链(__proto__)中出现过的类,检测结果都是true(用户可能会手动修改原型链的指向:example.__proto__ 或者 在类的继承中 等情况)
 */
// function func() {
// 	// arguments:类数组
// 	// arguments.__proto__ = Array.prototype;
// 	// console.log(arguments instanceof Array); //=>true
// }
// func();

// let arr = [],
// 	reg = /^$/,
// 	obj = {};
// console.log(arr instanceof Array); //=>true
// console.log(reg instanceof Array); //=>false
// console.log(arr instanceof Object); //=>true
// console.log(obj instanceof Array); //=>false

// console.log(1 instanceof Number); //=>false
//=>创建值的两种方式(不管哪种方式都是所属类的实例)
//字面量:let n = 12;
//构造函数:let m = new Number('12');

/*
 * constructor:构造函数 
 * @原理:在类的原型上一般都会带有CONSTRUCTOR属性,存储当前类本身,我们也是利用这一点,获取某的实例CONSTRUCTOR属性值,验证是否为所属的类,从而进行数据类型检测
 * @局限性:CONSTRUCTOR属性值太容易被修改了
 */
// let n = 12,
// 	arr = [];
// console.log(n.constructor === Number); //=>true
// console.log(arr.constructor === Array); //=>true
// console.log(arr.constructor === Object); //=>false
// arr.constructor = 111; //=>设置私有属性
// console.log(arr.constructor === Array); //=>false
// Func.prototype={}; //=>这样原型上没有CONSTRUCTOR属性(重构了)
3.Object.prototype.toString.call([value])
/*
 * Object.prototype.toString.call([value]):调用Object原型上的toString方法,让方法执行的时候,方法中的this是要检测的数据类型 ,从而获取到数据类型所属类的详细信息
 * @信息的模板 
 *    "[object 所属类]" ,例如:"[object Array]"...
 * 
 * 在所有的数据类型类中,他们的原型上都有toString方法,除Object.prototype.toString不是把数据值转换为字符串,其余的都是转为字符串,而Object原型上的toString是检测当前实例隶属类的详细信息的(检测数据类型)...
 *    obj.toString()
 *    1.首先基于原型链查找机制,找到Object.prototype.toString
 *    2.把找到的方法执行,方法中的this -> obj
 *    3.方法内部把this(obj)的所属类信息输出
 *    =>方法执行,方法中的this是谁,就是检测谁的所属类信息
 * 
 * 这个方法很强大,所有数据类型隶属的类信息检测的一清二楚
 *    "[object Number]"
 *    String/Boolean/Null/Undefined/Symbol/Object/Array/RegExp/Date/Math/Function...
 */
// let _obj = {},
// 	toString = _obj.toString;
// console.log(_obj.toString.call(100)); //=>"[object Number]"
// console.log(Object.prototype.toString.call(100)); //=>"[object Number]"

/* function func(n, m) {
	return n + m;
}
let obj1 = {},
	obj2 = {
		name: '珠峰培训'
	}; */
// console.log([12, 23].toString()); //=>"12,23"
// console.log(/^\d+$/.toString()); //=>"/^\d+$/"
// console.log(func.toString()); //=>"function func(n, m) {..."
// console.log(obj1.toString()); //=>"[object Object]"
// console.log(obj2.toString()); //=>"[object Object]"
4.封装一个数据类型检测的方法

【注】:真实项目可用

var _obj = {
		isNumeric: "Number",
		isBoolean: 'Boolean',
		isString: 'String',
		isNull: 'Null',
		isUndefined: 'Undefined',
		isSymbol: 'Symbol',
		isPlainObject: 'Object',
		isArray: 'Array',
		isRegExp: 'RegExp',
		isDate: 'Date',
		isFunction: "Function",
		isWindow: 'Window'
	},
	_toString = _obj.toString,
	_type = {};
for (var key in _obj) {
	if (!_obj.hasOwnProperty(key)) break;
	_type[key] = (function () {
		var reg = new RegExp("^\\[object " + _obj[key] + "\\]$");
		return function anonymous(val) {
			return reg.test(_toString.call(val));
		}
	})();
}

// console.log(_type.isNumeric(12));//true

二、回调函数

1.回调函数的基础概念
/*
 * 把一个函数当做实参传递给另外一个函数,在另外一个函数执行的过程中,把传递进来的函数执行,这种机制就是回调函数 
 * @真实场景应用
 *    AJAX异步请求成功做什么事
 *    浏览器内置的一些方法支持回调函数
 *    插件组件封装中的钩子函数(生命周期函数)
 *    ......
 */
/* new Drag('.box', {
	dragstart: function () {},
	dragmove: function () {},
	dragend: function () {}
}); */

/* let arr = [10, 20, 30];
//=>forEach/sort/map/find/filter/some/every/reduce...
arr.forEach((item, index) => {});
setTimeout(() => {}, 1000); */

/* function queryData(callback) {
	$.ajax({
		url: 'xxx.json',
		method: 'get',
		async: true,
		success: result => {
			typeof callback === 'function' ? callback(result) : null;
		}
	});
}
queryData(function anonymous(data) {
	//=>data:服务器返回的结果
}); */
2.封装each方法【真实项目可用】
<script>
var _obj = {
		isNumeric: "Number",
		isBoolean: 'Boolean',
		isString: 'String',
		isNull: 'Null',
		isUndefined: 'Undefined',
		isSymbol: 'Symbol',
		isPlainObject: 'Object',
		isArray: 'Array',
		isRegExp: 'RegExp',
		isDate: 'Date',
		isFunction: "Function",
		isWindow: 'Window'
	},
	_toString = _obj.toString, //_toString相当于Object.prototype.toString
	_type = {};
for (var key in _obj) {
	if (!_obj.hasOwnProperty(key)) break;
	_type[key] = (function () {
		var reg = new RegExp("^\\[object " + _obj[key] + "\\]$");
		return function anonymous(val) {
			return reg.test(_toString.call(val));
		}
	})();
}


/*
 * _each:遍历数组、类数组、对象中的每一项 
 *   @params
 *     obj:需要迭代的数组、类数组、普通对象
 *     callback:回调函数(每遍历数组中的某一项,就会把回调函数执行一次;而且需要把当前遍历的内容和索引[属性值和属性名]传给回调函数;接收回调函数的返回结果,如果是false,则结束当前的循环,如果是其它值,让返回的值替换数组中的当前项,如果没有返回值,则什么都不处理...)
 *     context:传递的第三个参数,可以改变回调函数中的THIS指向,不传递默认是window
 *   @return
 *     返回一个新的数组或者对象(原来的数组或者对象不变)
 */
function _each(obj, callback, context = window) {
	let isLikeArray = _type.isArray(obj) || (('length' in obj) && _type.isNumeric(obj.length));
	typeof callback !== "function" ? callback = Function.prototype : null; //Function.prototype是一个匿名空函数

	//=>数组或者类数组
	if (isLikeArray) {
		let arr = [...obj];
		for (let i = 0; i < arr.length; i++) {
			let item = arr[i],
				result = callback.call(context, item, i);
			if (result === false) break;
			if (typeof result === "undefined") continue;
			arr[i] = result;
		}
		return arr;
	}

	//=>对象的处理
	let opp = {
		...obj
	};
	for (let key in opp) {
		if (!opp.hasOwnProperty(key)) break;
		let value = opp[key],
			result = callback.call(context, value, key);
		if (result === false) break;
		if (typeof result === "undefined") continue;
		opp[key] = result;
	}
	return opp;
}

//测试数组
let arr = [10, 20, 30, 40];
let arr2 = _each(arr, (item, index) => {
	console.log(item, index);//10 0; 20 1; 30 2		
	if (index >= 2) return false;
	return item * 10;
});
console.log(arr, arr2);// [10, 20, 30, 40]   [100, 200, 30, 40]


//测试类数组
/* function func() {
	let arr = _each(arguments, (item, index) => {
		console.log(item, index);//10 0; 20 1; 30 2
		if (index >= 2) return false;
		return item * 10;
	});
	console.log(arguments, arr);
	// Arguments(4)[10, 20, 30, 40]  [100, 200, 30, 40]
}
func(10, 20, 30, 40); */


//测试对象
/*let obj = {
	name: '珠峰',
	year: 10,
	teacher: '哇咔咔~'
};
let obj2 = _each(obj, function (value, key) {
	// console.log(this); //=>document
	// console.log(value, key);
	if (key === "name") {
		return "珠峰培训@zhufeng";
	}
}, document);
console.log(obj, obj2); 
//{name: "珠峰", year: 10, teacher: "哇咔咔~"}  
//{name: "珠峰培训@zhufeng", year: 10, teacher: "哇咔咔~"} */
</script>
3.字符串replace方法的封装
/*
 * 重写字符串内置方法replace 
 *    1.正则在字符串中匹配几次,我们传递的回调函数就会被执行几次(前提:正则设置了global修饰符)
 *    2.每一次执行回调函数,都把当前正则匹配的信息(既有大正则,也有小分组的)传递给回调函数
 *    3.还要接收回调函数的返回值,返回的是啥内容,就要把当前字符串中正则匹配这一部分内容替换成啥
 */
/* ~ function () {
	//=>处理字符串:把字符串中的某一项替换成另外一项
	function handle(str, val1, val2) {
		let index = str.indexOf(val1);
		return str.substring(0, index) + val2 + str.substring(index + val1.length);
	}

	function replace(reg, callback) {
		let _this = this.substring(0),
			isGlobal = reg.global,
			arr = reg.exec(this);
		while (arr) {
			//=>捕获到的结果是数组(执行回调函数,把捕获的结果传递给它);还要接收回调函数执行的返回值,用返回值替换字符串中当前正则匹配的内容;
			if (typeof callback === "function") {
				let res = callback.apply(null, arr);
				_this = handle(_this, arr[0], res);
			}
			arr = reg.exec(this);
			//=>不设置GLOBAL的情况执行一次
			if (!isGlobal) break;
		}
		return _this;
	}
	String.prototype.replace = replace;
}();
let str = "{0}年{1}月{2}日",
	arr = ['2019', '09', '03'];
str = str.replace(/\{(\d)\}/g, function (content, group1) {
	return '@#' + arr[group1];
});
console.log(str); */

三、发布订阅

1.发布订阅和DOM2事件池机制
 DOM0DOM2
 1.语法上的区别
     box.onclick=function(){}
     box.addEventListener('click',function(){})
 2.底层运行机制上的区别
     DOM0就是给元素的某个属性绑定方法(有效绑定的方法只有一个)
     DOM2是基于事件池机制完成,每增加一个绑定的方法,都会往事件池中存放一个...当事件触发会依次执行事件池中的事情 =>【发布订阅其实就是模拟的事件池机制(可以给同一个元素的某个事件绑定多个不同的方法)】
 3.DOM2中可以给一些特殊的事件类型绑定方法,这些事件类型DOM0不支持绑定,例如:
     DOMContentLoaded、transitionend. . .I
 $(document).ready() =>$(function(){})   VS   window.onload
 DOM2的事件池机制
     1.基于addEventListener/attachEvent(IE6~8)向事件池中追加方法:新版本浏览器会根据元素和事件类型对新增的方法做重复校验,但是IE6~8不可以
     2.当事件行为触发,会把事件池中的方法按照增加的顺序依次执行,但是IE6~8中执行的顺序是不固定的
2.JQuery中的发布订阅
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button class="sumbit">点我啊</button>
    <script src="js/jquery.min.js"></script>
    <script>
        // 创建一个事件池 $.callbacks()
        let $pond1 = $.Callbacks();
        $('.sumbit').click(function () {
            // 点击的时候通知事件池中的方法执行,而且还可以给每个方法都传递实参
            $pond1.fire(100, 200);
        });
        let fn1 = function () {
            console.log(1);
        };
        let fn2 = function () {
            console.log(2);
        };
        let fn3 = function () {
            console.log(3);
        };
        // 把需要做的事情陆续添加到事件池中 $pond.add(func)/$pond.remove(func)
        $pond1.add(fn1);
        // $pond1.add(fn1);//=>JQ中没有做去重处理
        $pond1.add(fn2);
        $pond1.add(fn3);
        let fn4 = function (n, m) {
            console.log(4, n + m);//4  300
        };
        $pond1.add(fn4);
    </script>
</body>

</html>
3.基于ES6封装发布订阅库

【subscribe.js】:自己封装的发布订阅库

let _subscribe = (function () {
    // Subscribe:发布订阅类
    class Subscribe {
        constructor() {
            // 创建一个事件池,用来存储后期需要执行的方法
            this.$pond = [];
        }
        // 向事件池中追加方法(重复处理)
        add(func) {
            let flag = this.$pond.some(item => {
                return item === func;
            });
            !flag ? this.$pond.push(func) : null;
        }
        // 从事件池中移除方法
        remove(func) {
            let $pond = this.$pond;
            for (let i = 0; i < $pond.length; i++) {
                let item = $pond[i];
                if (item === func) {
                    // 移除(顺序不变的情况下基本只能用splice)
                    $pond.splice(i, 1);
                    break;
                }
            }
        }
        // 通知事件池中的方法按照顺序依次执行
        fire(...args) {
            let $pond = this.$pond;
            for (let i = 0; i < $pond.length; i++) {
                let item = $pond[i];
                item.call(this, ...args);
            }
        }
    }
    // 暴露给外面使用
    return function subscribe() {
        return new Subscribe();
    }
})();

导入subscribe.js库,开始使用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button class="sumbit">点我啊</button>
    <script src="js/subscribe.js"></script>
    <script>
        let pond=_subscribe();
        document.querySelector('.sumbit').onclick=function(ev){
            pond.fire(ev);
        }
        let fn1 = function () {
            console.log(1);
        };
        let fn2 = function () {
            console.log(2);
        };
        pond.add(fn1);
        pond.add(fn1);//自己的方法实现去重了
        pond.add(fn2);
        let fn3 = function () {
            console.log(3);
        };
        let fn4 = function (ev) {
            console.log(4, ev);//4  MouseEvent{...}
        };
        pond.add(fn3);
        pond.add(fn4);
    </script>
</body>

</html>
4.解决数组塌陷问题

在这里插入图片描述
【subscribe.js】:自己封装的发布订阅库----最终版

let _subscribe = (function () {
    // Subscribe:发布订阅类
    class Subscribe {
        constructor() {
            // 创建一个事件池,用来存储后期需要执行的方法
            this.$pond = [];
        }
        // 向事件池中追加方法(重复处理)
        add(func) {
            let flag = this.$pond.some(item => {
                return item === func;
            });
            !flag ? this.$pond.push(func) : null;
        }
        // 从事件池中移除方法
        remove(func) {
            let $pond = this.$pond;
            for (let i = 0; i < $pond.length; i++) {
                let item = $pond[i];
                if (item === func) {
                    // 移除(顺序不变的情况下基本只能用splice),但是不能这样写,这样会导致数组塌陷问题,我们不能真移除,只能把当前项赋值为null
                    // $pond.splice(i, 1);
                    $pond[i] = null;
                    break;
                }
            }
        }
        // 通知事件池中的方法按照顺序依次执行
        fire(...args) {
            let $pond = this.$pond;
            for (let i = 0; i < $pond.length; i++) {
                let item = $pond[i];
                if (typeof item !== 'function') {
                    // 此时再删除
                    this.$pond.splice(i, 1);
                    i--;
                    continue;
                }
                item.call(this, ...args);
            }
        }
    }
    // 暴露给外面使用
    return function subscribe() {
        return new Subscribe();
    }
})();

导入subscribe.js库,开始使用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button class="sumbit">点我啊</button>
    <script src="js/subscribe.js"></script>
    <!-- <script>
        let pond=_subscribe();
        document.querySelector('.sumbit').οnclick=function(ev){
            pond.fire(ev);
        }
        let fn1 = function () {
            console.log(1);
        };
        let fn2 = function () {
            console.log(2);
        };
        pond.add(fn1);
        pond.add(fn1);//自己的方法实现去重了
        pond.add(fn2);
        let fn3 = function () {
            console.log(3);
        };
        let fn4 = function (ev) {
            console.log(4, ev);//4  MouseEvent{...}
        };
        pond.add(fn3);
        pond.add(fn4);
    </script> -->

    <script>
        let pond=_subscribe();
        document.querySelector('.sumbit').onclick=function(ev){
            pond.fire(ev);
        }
        let fn1 = function () {
            console.log(1);
        };
        let fn2 = function () {
            console.log(2);
            pond.remove(fn1); //需要注意的地方
        };
        let fn3 = function () {
            console.log(3);
        };
        let fn4 = function () {
            console.log(4);
        };
        pond.add(fn1);
        pond.add(fn2);
        pond.add(fn3);
        pond.add(fn4);
    </script>
</body>

</html>

四、继承【4种】

1.函数封装重载和对面向对象的理解
 /*
  * 封装:低耦合高内聚
  * 多态:重载和重写
  *    【重载】:方法名相同,形参个数或者类型不一样(JS中不存在真正意义上的重载,JS中重载指的是同一个方法,根据传参不同,实现出不同的效果)
  *    【重写】:在类的继承中,子类可以重写父类中的方法,
  * 继承:子类继承父类中的属性和方法    
  */

 /*
 function sum(x, y, z) {
     if (typeof z === 'undefined') {
         //...
         return;
     }
     //...
 }
 sum(1, 2);
 sum(1, 2, 3);
 */


 /*
 function sum(n, m) {
     console.log(1);
 }

 function sum(n, m, x) {
     console.log(2);
 }
 sum(1, 2); //2
 sum(1, 2, 3); //2
 */

 /*
 JAVA中是存在重载的:根据传递参数的个数和类型,执行对应的函数
 public void sum(int n,int m){}
 public void sum(int n,int m,float x){}
 public void sum(int n,int m,String x){}
 sum(1,2);
 sum(1,2,3.5);
 sum(1,2,'DD');
 sum();//报错,找不到
 */
2.原型继承
  /*
   * 继承:子类继承父类中的属性和方法(目的:让子类的实例可以调取父类中的属性和方法)
   *   方案一:原型继承
   *      让父类中的属性和方法在子类实例的原型链上
   *      child.prototype = new Parent();
   *      child.prototype.constructor = child;
   *   特点:
   *      1.不像其他语言中的继承一样(其他语言的继承一般是拷贝继承,也就是子类继承父类,会把父类中的属性和方法拷贝一份到子类中,供子类的实例调取使用),他是把父类的原型放到子类实例的原型上,实例像调取这些方法,是基于__proto__原型链查找机制完成的
   *      2.子类可以重写父类上的方法(这样会导致父类的其他实例也收到影响)
   *      3.父类中私有或者公有的属性方法,最后都会变为子类中公有的属性和方法
   */

  function A(x) {
      this.x = x;
  }
  A.prototype.getX = function () {
      console.log(this.x);
  }
  B.prototype = new A(200);
  function B(y) {
      this.y = y;
  }
  B.prototype.getY = function () {
      console.log(this.y);
  }
  let b1 = new B(100);
  console.log(b1.y);// 100
  console.log(b1.x);// 200
  b1.getY();// 100 
  b1.getX();// 200 

在这里插入图片描述

3.call继承
 /*
 * 继承:子类继承父类中的属性和方法(目的:让子类的实例可以调取父类中的属性和方法)
 *   方案二:call继承
 *      特点:child方法中把parent当做普通函数执行,让parent中的this指向child的实例,相当于给child的实例设置了很多私有的属性或者方法
 *      1.只能继承父类私有的属性或者方法(因为是把parent当做普通函数执行,和其原型上的属性和方法没有关系)
 *      2.父类私有的变为子类私有的 
 */
function A(x) {
    this.x = x;
}
A.prototype.getX = function () {
    console.log(this.x);
}
function B(y) {
    // this: B的实例b1
    A.call(this,200);// b1.x = 200
    this.y = y;
}
B.prototype.getY = function () {
    console.log(this.y);
}
let b1 = new B(100);
console.log(b1.y); // 100
console.log(b1.x); // 200
b1.getY(); // 100 
4.寄生组合继承【推荐】
 <script>
     /*
      * 继承:子类继承父类中的属性和方法(目的:让子类的实例可以调取父类中的属性和方法)
      *   方案三:寄生组合继承 = call继承 + 类似于原型继承  
      *      特点:父类私有和公有分别是子类实例的私有和公有属性方法(推荐)
      */
     function A(x) {
         this.x = x;
     }
     A.prototype.getX = function () {
         console.log(this.x);
     }

     function B(y) {
         // this: B的实例b1
         A.call(this, 200); // b1.x = 200
         this.y = y;
     }
     // Object.create(obj): 创建一个空对象,让空对象__proto__指向obj
     B.prototype = Object.create(A.prototype);
     B.prototype.constructor = B;
     B.prototype.getY = function () {
         console.log(this.y);
     }
     let b1 = new B(100);
     console.log(b1.y); // 100
     console.log(b1.x); // 200
     b1.getY(); // 100 
     b1.getX(); // 200     
 </script>

 <script>
     // 【补充】:重写内置Object.create
     // Object.create=function(obj){
     //     function Fn(){}
     //     Fn.prototype = obj;
     //     return new Fn();
     // }
 </script>

在这里插入图片描述

5.ES6中的继承
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        /*
        class A {
            constructor(x) {
                this.x = x;
            }
            getX() {
                console.log(this.x);
            }
        }
        class B {
            constructor(y) {
                // A.call(this, 200);//Uncaught TypeError: Class constructor A cannot be invoked without 'new'
                this.y = y;
            }
            getY() {
                console.log(this.y);
            }
        }
        // B.prototype = Object.create(A.prototype);//不允许重定向原型的指向
        let b1 = new B(200);
        */
    </script>

    <script>
        class A {
            constructor(x) {
                this.x = x;
            }
            getX() {
                console.log(this.x);
            }
        }
        // ES6中的继承:  class child extends parent{} => B.prototype.__proto__ = A.prototype
        class B extends A {
            constructor(y) {
                //子类只要继承父类,可以不写constructor,一旦写了,则在constructor中的第一句话必须始super();
                //不写constructor,浏览器会自己默认创建constructor(...args){super(...args)}
                super(200); //相当于A.call(this,200); => 把父类当做普通方法执行,给方法传递参数,让方法中的this是子类的实例     
                this.y = y;
            }
            getY() {
                console.log(this.y);
            }
        }
        let b1 = new B(100);
        console.log(b1); //B {x: 200, y: 100}
    </script>

    <script>
        /*
        // ES6中的继承实战应用1:
        class Login extends React.Component {
            constructor(props) {
                super(props);
            }
            componentWillMount() {
                //此处的this:Login的实例
                this.setState(); // React.Component.prototype.setState
            }
            render() {

            }
            componentDidMount() {

            }
        }
        */


        /*
        // ES6中的继承实战应用2:
        // Promise.prototype上的方法:then、catch、finally
        class Dialog extends Promise {
            constructor() {
                super();
            }
            show() {
                //此处的this:Dialog的实例
                this.then().then(); //真实项目一般不这么写
            }
        }
        */


        /*
        // ES6中的继承实战应用:
        class Utils {
            query() {}
        }
        class Dialog extends Utils {
            constructor() {
                super();
                this.query(); //this: Dialog的实例,通过继承,实例可以调取父类原型上的方法
            }
        }
        */
    </script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值