文章目录
- 五、JS中不完善的报错+手动改进(throw+【argument】+补充:【...rest】)
- 1.函数参数中报错不完善
- 2.var局部作用域中的bug
- 六、使JS的原生方法失效+恢复
- 七、多个js文件全局遍历冲突问题
- 八、方法与函数
一、原型继承
实例中,tom本身没有run方法,无法调用run
但如果想调用,则可让tom的原型对象指向Student,这样,tom对象在调用run方法时,在本对象中查不到run方法时,则会去tom对象的__proto__属性中去查找run方法,也就是先在tom对象的原型链上查找紧邻上一个原型对象中的方法
当然,要注意的是,将tom的原型指向Student时,Student的原型也会连接过来
每个对象和原型都有原型,对象的原型指向原型对象,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。
作为一个对象,当你访问其中的一个属性或方法的时候,如果这个对象中没有这个方法或属性,那么JavaScript引擎将会访问这个对象的__proto__属性所指向的上一个对象,并在那个对象中查找指定的方法或属性,如果不能找到,那就会继续通过那个对象 的__proto__属性指向的对象进行向上查找,直到这个链表结束
二、Class关键字
1.ES6之前
在ES6之前,只能这样定义类
<script>
"use strict";
function Student(name) {
this.name = name;
}
//给Student类新增一个方法,上面的Student(name)为构造函数
//给类增加方法,因此需指向Student(name)函数的原型对象
Student.prototype.hello = function () {
console.log('Hello ' + this.name);
}
</script>
引入一张图
2.ES6后
在ES6时,引入了Class关键字,使得此操作更加方便、合理和规范
<script>
"use strict";
class Student {
constructor(name) {
this.name = name;
}
hello() {
console.log('Hello ' + this.name)
}
}
</script>
继承用关键字extends
<script>
"use strict";
class Student {
constructor(name) {
this.name = name;
}
hello() {
console.log('Hello ' + this.name)
}
}
class PrimaryStudent extends Student {
constructor(name, grade) {
super(name);
this.grade = grade;
}
say() {
console.log('I‘m a primary student');
}
}
</script>
如图,extends本质也是原型链的思想
(注:下图Object原型后面还有连接的原型)
3.补充
(1)得到原型类:
方法一:对象实例名._proto_
方法二:类名.prototype
三、Map和Set
二者为ES6的新增数据类型。
Map:(键值对)
常用方法:
- set(‘key’, value):添加某个值。
- delete(value):删除某个值。
- get(‘key’):得到此键的某个值
Set:(去重的无序集合)
常用方法:
- add(value):添加某个值。
- delete(value):删除某个值。
- has(value):某值是否在集合内。
- clear():清除集合中所有元素。
四、Iterator(迭代器)
为ES6新特性。
1.遍历数组
普通的遍历方法如下:
for in:遍历下标
for of:遍历值
2.遍历Map
for of:遍历键+值
3.遍历Set
for of:遍历值
五、JS中不完善的报错+手动改进(throw+【argument】+补充:【…rest】)
1.函数参数中报错不完善
例子:
<script>
"use strict";
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
函数传递多个参数,或不传递参数,或是传递另一种类型的参数,都不会报错,最多是NaN值,从而可能导致间接报错,但不会出现直接报错
加一段判断参数类型的语句,来手动抛出异常(但也只能解决只传一个参数时的类型问题)
<script>
"use strict";
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a Number~';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
由于可利用JS的关键字arguments来接收多个函数参数,否则,若函数只定义了一个参数,则其它传入的参数(从第二个参数往后的所有参数),都不会参与到函数中,但却保留在arguments中
<script>
"use strict";
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a Number~';
}
console.log('x=>' + x);
console.log('argument遍历');
for (let i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
因此,再次改进代码,即可写出一个报错完整的函数
<script>
"use strict";
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a Number~';
}
if (arguments.length > 1) {
throw 'Please Input one arg~'
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
补充:另外,还有一个…rest(ES6新增),写在函数定义的参数列表最后面,用于接收除已定义参数外的额外传入的参数
<script>
"use strict";
function talk(x, ...rest) {
let i;
for (i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
console.log('-----------------------')
console.log(rest);
}
</script>
2.var局部作用域中的bug
<script>
"use strict";
for (var i = 0; i < 2; i++) {
console.log('in: ' + i);
}
//仍然可以输出i
console.log('out: ' + i);
</script>
改进:将var改为let
<script>
"use strict";
for (let i = 0; i < 2; i++) {
console.log('in: ' + i);
}
//不可以输出i
console.log('out: ' + i);
</script>
六、使JS的原生方法失效+恢复
预先记录原方法引用,随后消除原方法:
<script>
"use strict";
let x = 'xxx';
var old_alert = window.alert;
window.alert = function (){
}
window.alert(123);
window.old_alert('old: ' + x);
</script>
当然,也可以设置恢复
<script>
"use strict";
let x = 'xxx';
var old_alert = window.alert;
window.alert = function (){
}
window.alert(123);
// window.old_alert('old: ' + x);
//恢复
window.alert = old_alert;
window.old_alert('re-old: ' + x);
</script>
七、多个js文件全局遍历冲突问题
问题:由于我们所有的全局变量都会绑定到window对象上,因此,如果使用不同的js文件,遇到相同名字的全局变量时,就会产生冲突。
解决方法:在每个js中都自定义一个唯一的全局变量对象,将这个脚本文件中的所有全局变量都赋予该全局变量对象,从而降低全局命名冲突的问题。(JQuery也参考了这个思想)
例如:
<script>
"use strict";
//唯一全局变量
var appT = {};
appT.name = 'zlc';
appT.add = function(x, y) {
return x + y;
}
//使用时
console.log(window.appT.add(1, 2));
</script>
八、方法与函数
(在讲述的时候需格外注意,不要将方法说成函数)
方法:
或是这样的形式
方法调用:obj.method(),需要加括号
函数:
用函数的apply方法调用函数:格式:函数名.apply(对象, 参数列表);
普通函数调用和apply函数调用,结果相同
直接调用getAge()函数将会报错
因为函数中的this,都是指向调用此函数的对象,因此在实例中的getAge()函数,直接调用的话,也就是单纯作为独立函数调用的时候,将对函数的this使用默认绑定:绑定到全局的window对象,由于window对象中未设置birth属性,而函数体中又有this.birth,因此报错。最终用student对象调用此函数,this才会指向student对象,进而才会取到birth属性值。