原型对象
概念: 每一个构造函数都有有一个prototype属性,当通过new来使用这个构造函数时,系统会创建出一个对象,prototype这个属性就指向这个对象(假设为A),该对象中的属性和方法都可以被该构造函数创建出来的实例继承。 则 A 就是该实例的原型对象,且用__proto__属性指向这个A对象。
例: obj1 和 obj2 就是 Fn 构造出来的一个实例对象,该对象可以调用其原型对象上的属性和方法,如果该实例有同样的方法,则调用自己的。
<script>
function Fn(name,age){
this.name = name;
this.age = age;
}
Fn.prototype.eat(){
consoloe.log("水果");
}
Fn.prototype.run = function() {
console.log("游泳")
}
var obj1 = new Fn("cici",12);
var obj2 = new Fn("lulu",11);
obj1.eat(); // 水果
obj1.run = function() {
console.log("跑步")
}
obj1.run(); // 跑步
</script>
注:
- 系统会为每一个函数对象分配一个prototype的属性,(仅限函数),指向该构造函数的原型对象;
- 每个对象都有一个__proto__属性,也指向创建出这个对象的构造函数的原型对象。
原型对象的作用: 避免重复开拓空间,减少冗余;当实例有共同的属性和方法时,便可存在原型对象中。
原型对象的使用:
- 利用对象的动态特性添加属性,语法:构造函数名.prototype.xxx=yyyy;
- 直接替换掉对象,语法:构造函数名.prototype={};但是替换之前的对象依然存在
原型链
图示:
注:
所有对象都是由object创建出来的,所以所有对象的__proto__ 都指向object.prototype;
所有的普通函数都是由Function创建的,所以普通函数的__proto__都指向Function.prototype;
对象访问数据都是顺着自己的原型链一层一层往深处找,不会跨连访问;
js的 预编译
javascript 引擎三步骤:
- 语法分析:分析是否有语法上的低级错误;
- 预编译:在全局作用域,开拓空间存放变量和函数;分为全局预编译和函数预编译
- 解释执行
全局预编译
- 创建GO对象 GO={} (上下文)存放变量和函数
- 变量声明提升 (赋值并不会提升)
- 函数提升 (整体提升)
- 注意:同名的变量和函数直接替换
例:
<script>
console.log(a) // function a(){}
var a=10
function a () {
}
console.log(a) // 10
</script>
代码预编译过程:
GO {a:}
GO {a:function a(){}}
函数预编译
- 创建AO对象(执行期上下文)函数每调用一次,便创建一次
- 变量声明和形参提升
- 实参传值给形参
- 函数声明提升
例:
function fn(a) {
console.log(a);
var a = 123;
console.log(a);
function a() {}
console.log(a);
var b = function () {}
console.log(b);
function d() {}
}
fn(1)
变量声明和形参提升,重名替换
AO {a:undefiend,
b:undefiend,
}
实参传值形参
AO{
a:1
b:undefiend,
}
函数声明提升
AO{
a: function(){};
b:undefiend,
d:function d() {}
}
执行结果:
function(){}
123
123
function(){1}
作用域
变量作用域
全局作用域,