原型
原型相关的东西
- 每个函数都有一个显式原型属性: prototype
- 每个实例都有一个隐式原型属性: proto
- 对象的隐式原型的值 = 其对应构造函数的显式原型的值.
- 原型对象:
– prototype和__proto__是属性, 不是原型对象.
– 每个函数都有一个prototype属性(显式原型属性), 它默认指向一个Object空对象, 即 原型对象.
– 原型对象中有一个constructor属性, 它指向函数对象.
– 每个实例对象都有一个__proto__属性(隐式原型属性).
原型链
-
相关内容:
– 原型链是从对象的__proto__开始的
– 查找属性会顺着原型链找;设置属性值不会顺着原型链
– __proto__的作用是继承或者找方法(比如调用bind,call,apply)
– 查找对象上属性的流程: 比如: a.b
步骤:
先看a是否在作用域链上(一直找到window), 如果不存在, 就会报错; 如果存在, 则会判断a的类型 --> 如果a是基本类型, 则报错 --> 如果a是地址值, 则会解析b, 查找b属性 --> 查找b属性, 先在自身找, 找到了返回; 如果没有找到, 就顺着原型链找, 找到了返回, 没找到返回undefined.
总结: 查找属性, 则会顺着原型链找.
– 设置对象上属性值不会顺着原型链 ( 区别上面的 ) (如下代码)
-
简单版的原型链:
instanceof() 方法
- A instanceof B --> 判断A是否是B的实例 (instanceof不能用来判断基本数据类型) --> A是实例对象, B是构造函数
- 返回值是 true 或者 false .
继承(看之前的笔记)
作用域
作用域相关的东西(包括了作用域链)
- 作用域分类: 全局作用域; 函数作用域; 块级作用域 (ES6新增的: const / let)
- 作用域链: 多个嵌套的作用域形成的由内向外的结构, 用于查找变量.
- 变量声明提升 与 函数声明提升 :
变量提升: 在变量定义语义之前, 就可以访问到这个变量;
函数声明提升: 在函数定义语义之前, 就执行函数;
原因: 简单来说就是执行全局代码和函数前会进行预解析/处理 (也就是, 将var变量声明放在最前面执行; 将function函数声明放在最前面执行); - 声明提升(顺序):
a) 形参;
b) 函数(当形参和函数同名时, 可以覆盖形参)
c) 变量(当变量与形参和函数同名时, 不可以覆盖形参和函数, 但是可以重新赋值)
注意事项: 函数表达式和函数构造器声明的函数不会被提升
var是在函数作用域中声明变量的; let / const是在块级作用域声明变量的; 如果想在块级作用域中声明函数, 则使用函数表达式.
例子:
/*
第一个声明提升:
1.形参 -- a:1,b:2
2.函数:function a(),函数名a与形参名a重复了,则函数会覆盖形参
3.console.log(a) 是 function.
*/
//第一个
function fn(a, b) {
console.log(a); //function
function a() {}
}
fn(1, 2)
/*
第二个声明提升:虽然函数优先提升,变量后提升,但是变量提升如果有重名,则不允许覆盖已有的形参或函数
1.没有形参
2.函数:function a()
3.变量:a
4.console.log(a) 是 function ---变量不可以覆盖函数和形参
5.变量:a=1(给变量a赋值了)
6.console.log(a) 是 1
*/
//第二个
function fn() {
console.log(a); //function
var a = 1;
console.log(a); //1
function a() {}
}
fn()
/*
第三个声明提升:
1.形参 -- a:1
2.变量 -- a
3.console.log(a) 是 1 (这里是因为变量不能覆盖形参)
*/
//第三个
function fn(a) {
//虽然变量后提升,但是不能覆盖同名形参
console.log(a); //1
var a = 2;
}
fn(1)
/* //区别上面的代码(上面的代码形参赋值),而下面这个代码形参没有赋值
function fn(a) {
//虽然定义了一个形参,但是形参没有赋值
//虽然变量后提升,但是不能覆盖同名形参
console.log(a); //undefind
var a = 2;
}
fn() */
/*
第四个声明提升:
1.形参:a:1
2.变量:a
3.console.log(a) 是 1
4.变量赋值:a=2
5.console.log(a) 是 2
*/
//第四个
function fn1(a) {
console.log(a); //1
var a = 2;
console.log(a); //2
}
fn1(1);
/*
第五个声明提升:
1.形参:a(没有赋值)
2.变量:a
3.console.log(a) 是 undefined(检测的是形参)
4.变量赋值:a=2
5.console.log(a) 是 2
*/
//第五个
function fn1(a) {
console.log(a); //undefined
var a = 2;
console.log(a); //2
}
fn1();
/*
第六个声明提升:
1.没有形参
2.函数function foo() {}
3.变量foo(变量不会影响函数)
4.console.log(foo) 是 function
5.变量赋值foo=1
*/
//第六个
function fn2() {
console.log(foo); //function
function foo() {}
var foo = 1;
}
fn2();
/*
第七个声明提升:
1.全局函数:function a() {}
2.变量a
3.console.log(typeof a) 是 function(检测的是函数)
*/
//第七个
function a() {}
var a ;
console.log(typeof a) //function
/*
第八个声明变量:
1.这里是块级作用域
2.变量b会得到提升
3.(b in window)是true
4.(!(b in window))是false
5.因为是false,所以if语句不会执行,则b不能被赋值
6.console.log(b)是undefined
*/
//第八个
if (!(b in window)) {
var b = 1;
}
console.log(b); //undefined
/*
第九个声明提升:
1.函数:function c(c)
2.变量:c (注意:虽然变量声明会被函数声明所覆盖,但是可以重新赋值)
3.变量赋值 c=1,则此时同名的c已经被重新赋值了,由函数变成了数值
4.c(2) 是 c is not a function (c已经变成了数值,所以不是函数了,没办法调用)
*/
//第九个
var c = 1 ;
function c(c) {
console.log(c);
var c = 3;
}
c(2); //c is not a function
var b = 1;
function fn() {
var b = 2;
console.log(b); //2(先在局部作用域找,再在全局作用域找)
}
b = 3;
fn();