JS高级
这里是对JS高级的一些总结~
文章目录
显式原型和隐式原型
-
每个函数的function都有一个prototype,即显式原型属性,默认指向一个空的object对象
-
每个实例对象都有一个__proto__,可称为隐式原型
-
对象的隐式原型的值为其对应构造函数的显式原型的值
// 定义构造函数
function Fn() { //内部语句:this.prototype={}
}
console.log(Fn.prototype);
var fn = new Fn() // 创建实例对象
console.log(fn.__proto__);
//内部语句this.__proto__ = Fn.prototype
console.log(Fn.prototype === fn.__proto__);//true
// 给原型添加方法
Fn.prototype.test = function () {
console.log('test()');
}
fn.test();//在object里面
原型链
- 原型链
访问一个对象的属性时,现在自身属性中查找,找到返回。如果没有,再沿着__proto这条链上查找,找到返回,如果没找到,返回undefined
- 别名:隐式原型链
- 作用:查找对象的属性(方法)
- 构造函数/原型/实体对象的关系
实例对象的隐式原型等于构造函数的显式原型
a. 函数的显式原型指向的对象:默认是空的object实例对象(当object不满足)
console.log(Fn.prototype instanceof Object); //true
console.log(Object.prototype instanceof Object); //false
console.log(Function.prototype instanceof Object); //true
b. 所有函数都是Function 的实例(包括Function)
console.log(Function.__proto__===Function.prototype);
//Object的原型对象是原型链的尽头
console.log(Object.prototype.__proto__) //null
//原型对象中有一个属性constructor,它指向函数对象
//fun.prototype.contructor===fun
原型链的属性问题
- 读取对象的属性值时,会自动到原型链中查找
- 设置对象的属性值时,不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
- 方法一半定义在原型中,属性一半通过构造函数定义在对象本身上
function Fn() {
}
Fn.prototype.a = 'xxx';
var fn1 = new Fn();
console.log(fn1.a, fn);
var fn2 = new Fn();
fn2.a = 'yyy' //直接添加
console.log(fn1.a, fn2.a, fn2);
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.setName = function (name) {
this.name = name;
}
var p1 = new Person('tom', 12);
p1.setName('bob');
console.log(p1);
instanceof
-
表达式:A instanceof B
-
如果B函数的显式原型对象在A对象的原型链上,则返回true,否则返回false
-
Function是通过new自己产生的实例
function Foo() {
}
var f1 = new Foo();
console.log(f1 instanceof Foo); //true
console.log(f1 instanceof Object); //true
原型链继承
内存溢出和内存泄漏
内存溢出
- 一种程序运行出现的错误
- 程序运行需要的内存超过了剩余的内存
例:
var obj={}
for(var i=0;i<10000;i++){
obj[i] = new Array(100000)
console.log('-----');
}
内存泄漏
-
占用的内存没有及时泄漏
-
内存泄漏积累多了就容易导致内存溢出
-
常见的内存泄漏:
-
意外的局部变量
-
没有及时清理的定时器或回调函数
-
闭包
-
function fn() {
a = 3; // 直接赋值相当于全局变量
console.log(a);
}
fn();
作用域与作用域链
查找变量:从作用域的顶端依次向下查找
GO:全局上下文
AO:执行器上下文
function a(){
function b(){
var b = 234;
}
var a = 123;
b();
console.log(a);
}
var glob = 100;
a();
//a defined a.[[scope]] --> 0: GO{}
//a doing a.[[scope]] --> 0: AO{}
// 1: GO{}
闭包
当内部函数被保存到外部(非全局变量)时,将会生成闭包。闭包会导致原有的作用域链不释放,造成内存泄漏(占用内存)。
闭包的作用
- 实现公有变量
- 可以做缓存(存储结构
- 可以实现封装,属性私有化
- 模块化开发,防止污染全局变量
预编译
1. 全局预编译
a. 创建GO对象(Golbal Object,可以理解为window)
b. 找到变量声明,赋值为undefined
c. 找到函数声明(function(){}),函数名作为GO的属性名,函数体作为GO的属性值
2. 函数中的预编译
a. 创建AO对象(Active Object, 即执行期上下文)
b. 找形参和参数声明,将变量和幸参作为AO的属性名,赋值为undefined
c. 将实参和实参统一
d. 在函数中找函数声明
JS用在本地存储一些函数
**push() **可向数组的末尾添加一个或多个元素,并返回新的长度。
注意: 新元素将添加在数组的末尾。
注意: 此方法改变数组的长度。
提示: 在数组起始位置添加元素请使用 unshift() 方法。