2020.11.29
01.原型链的关系
①.实例对象通过关键字new和构造函数来创建
②.实例对象通过constructor属性来找到实例化自己的构造函数
③.构造函数通过prototype属性来找到自己的prototype属性
④.实例对象的__proto__指向实例化自己的构造函数的prototype
⑤.一个对象的__proto__指向构造函数的prototype,因为prototype自身又是一个对象,也有__proto__属性,如果prototype.__proto__指向Object.prototype,说明这个对象是单一的独立的,不是继承而来的
⑥.object.prototype的构造函数是Object
⑦.通过最外层的Object拿到实例化对象==>通过new重新创建==>new Object(实例化对象)
⑧.通过最外层的Object拿到构造函数的prototype==>通过new重新创建==>new Object(构造函数.prototype)
原型链:当从一个对象那里调取属性或方法时,如果该对象自身不存在这样的属性或者方法,就会去关联的prototype那里寻找,如果prototype没有,就会去prototype关联的prototype那里寻找。如果还没有,会一直向上寻找,直到prototype…prototype…为null。从而形成了原型链(根本上来说就是继承)
判断a是否存在于b的原型链中==>a.isPrototypeOf(b)
好处:可以判断对象的关联性
/*
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
语法:Object.create(proto, [propertiesObject])
*/
var person={
name:'zs'
}
//通过person创建对象student。类似于继承
var student=Object.create(person);
案例:判断原型链存在关系
var person={
name:'zs'
}
var student=Object.create(person);
var teacher=Object.create(student);
console.log(teacher.isPrototypeOf(teacher));//false
console.log(student.isPrototypeOf(teacher));//true
console.log(person.isPrototypeOf(teacher));//true
console.log(Object.prototype.isPrototypeOf(person));//true
/*分析:
关系:obj==>person==>student==>teacher
自身不能说存在于自身的原型链中==>false
在上面的存在于下面的原型链中,所以Object.prototype、person、student都存在于teacher的原型链中==>true
*/
a.hasOwnProperty(b)判断b属性是a自有的还是继承过来的
var person={
name:'zs'
}
var student=Object.create(person);
var teacher=Object.create(student);
student.zid=101;
console.log(teacher.zid);//101
console.log(teacher.hasOwnProperty('zid'));//false,因为teacher.zid=101是从student继承来的
teacher.zid=001;
console.log(teacher.zid);//001
console.log(teacher.hasOwnProperty('zid'));//true,自有属性
// 如果一个对象既有自有属性,又可以继承。以自有属性为准
02.get和set
封装一个获取和设置的方法
var circle={
r:20,
// get获取值 get+空格+变量名
// set设置值 set+空格+变量名
get acr(){
return Math.PI*this.r*this.r;
},
set acr(value){
this.r=value;
}
}
// 如果是赋值,自动调用set方法
circle.acr=100;
// 如果是获取值,自动调用get方法
console.log(circle.acr);//3.1415*100*100=31415
03.属性特征
//正常赋值,属性可以直接修改,属性可以被遍历出来
var stu={
name:'zs'
}
stu.name='小明';
for(var i in stu){
console.log(i);//name
}
//某些属性比较重要,单独设置,一般特殊情况才这样使用
//设置属性的时候,可以配置属性特征
Object.defineProperty(stu,'password',{
//password的值
value:123,
//是否可以被修改,true可以修改,false不可修改,默认值false
writable:true,
//是否可以被遍历,true可以遍历,false不可遍历,默认值false
enumerable:true,
//是否可以被重新配置,true可以重新配置,false不可重新配置,默认值false
configurable:true
});
04.变量提升
案例1
console.log(a);
var a=10;//undefined
/*等价于
var a=10;
console.log(a);
a=10;
*/
如果一个变量声明,会把声明提升到整个作用域的最前面,赋值还是在原来的位置
案例2
console.log(a)
a=10;//报错 a is not defined
//a没有声明,在赋值之前没有办法直接使用
/*
a=10;
console.log(a);//10
*/
如果变量没有声明,作用域是赋值以后的区域
案例3
add();
function add(){
console.log(111);//111
}
/*等价于
function add(){
console.log(111);//111
}
add();
*/
通过该方法定义函数,会把整个函数提升到作用域最前面。
案例4
add();//报错 add is not a function
var add=function(){
console.log(111);
}
/*等价于
var add;
add();//报错 add is not a function
add=function(){
console.log(111);
}
*/
通过以下方法定义函数,只会把变量的定义提升到作用域最前面
案例5
var a=10;
function add(){
console.log(a);//10
}
add();
/*等价于
var a;
a=10;
function add(){
console.log(a);
}
add();
*/
var a=10;
function add(){
console.log(a);//undefined
var a=100;
}
add();
/*等价于
var a;
a=10;
function add(){
//a的作用域在add的{}内
var a;
//按照就近原则找到上一行新声明的a,a只是声明了但未赋值==>undefined
console.log(a);
a=100;
}
add();
*/
变量提升,会把变量声明提升到整个作用域最前面。js中只有函数的作用域,变量的作用域,是向上寻找距离其最近的开始的函数的{变量的作用范围就是该{}以内。
案例6
function add(){
var a=100;
}
add();
console.log(a);//报错 a is not defined
//a的作用域在add内,在外面操作就会报错
案例7
function add(){
a=100;
}
//console.log(a);//add执行前输出,报错 a is not defined
add();//如果不执行add(),就会报错
console.log(a);//add执行后输出,100
执行函数相当于给变量赋值。变量没有声明,作用域是赋值以后都可以使用 。如果不执行函数,相当于不会执行赋值语句,此时进行操作(输出/赋值等)会报错。
05.作用域和作用域链
作用域:在js(暂不包括es6)中只有函数的作用域,在函数内部声明的变量,才能称为局部变量。全局和局部只是相对来说
作用域链:在某个作用域内使用变量的时候,首先会在该作用域内寻找该变量,如果没有,会一直向上寻找。这样的一种链式关系就是作用域链。其实指的就是变量的就近原则。
例如:
var m=10;
function add(){
function mul(){
//mul里没有m,向上在add里寻找,add里也没有,再向上,找到m=10
console.log(m);//10
}
mul();
}
add();