作用域篇
作用域,啊?作用域,啊!那没事了
1)
var a = 2
function P() {
this.a = 5
this.fn = function() {
console.log(this.a)
}
}
var obj1 = new P()
obj1.fn() //5 对象上执行,this指向对象obj
var obj2 = new P().fn
obj2() //2 全局中执行,this指向全局windowjs函数this始终指向执行它的地方
class Animal {
constructor(name) {
this.props = {
name
}
}
fly() {
function canFly() { // 单独的函数作用域
// 此处的this为undefined
return this.props.name === "birds";
}
if (canFly()) {
console.log("i can")
} else {
throw new error("no")
}
}
}
const animal = new Animal('birds')
try {
animal.fly() // 执行时遇见报错,自断跳到catch
} catch (e) {
console.log(e) // 执行,结果为TypeError: Cannot read property 'props' of undefined
}区分指向和作用域
3)
var i = 5;
function fn(i) {
return function(n) {
console.log(n + (++i))
}
}
var f = fn(1) // i=1
f(2) // 闭包常驻,i为1,则输出4,f中i变成2
fn(3)(4) // 新闭包空间,输出8
fn(5)(6) // 同上,输出12
f(7) // 使用f的闭包空间,输出10,f中i变成3
console.log(i) // 5,没有操作过外部i++i先加后赋值;闭包值常驻
4)
var x = 10;
function fn() {
console.log(x); // 函数内使用非定义在函数内的变量时,会在定义处往上层找,直到顶层停止
}
function show(f) {
var x = 20;
f();
}
show(fn); // 输出10let a = 0,
b = 0;
function A(a) {
A = function(b) {
console.log(a + b++)
}
console.log(a++)
}
A(1) // 这一步将外部A方法覆盖为内部A方法,输出1,a变成2
A(2) // 这一步实则使用内部A方法,a为内部A方法定义地方往上找,找到a=2;输出 4i++选赋值后加;函数内使用非定义在函数内的变量时,会在定义处往上层找,直到顶层停止
5)
function Person() {
//0
getAge = function () {
console.log(10)
}
return this;
}
//1
Person.getAge = function () {
console.log(20)
}
//2
Person.prototype.getAge = function () {
console.log(30)
}
//3
var getAge = function () { // 变量提升
console.log(40)
}
//4
function getAge() { // 变量提升,优先于方法3
console.log(50)
}
Person.getAge(); // 执行方法1,输出20
getAge(); // 执行方法3,输出40
Person().getAge(); // 执行方法0,且将方法3覆盖为方法0,输出10
new Person.getAge(); // 实例化方法1,输出20
getAge(); // 执行已经变成方法0的方法3,输出10
new Person().getAge(); // 实例化Person,调用其原型上的方法2,输出30new xx.xxx()和new xx().xxx()是两个东西,前者实例化xx上的xxx,后者执行实例化xx后原型上的xxx方法;仔细看
6)
function sidEffecting(ary) {
ary[0] = ary[2];
}
function bar(a, b, c) { //操作一:改成 (a,b,c=4) 会怎样
c = 10 // 将arguments[2]值赋为10,[2,2,10]
sidEffecting(arguments); // 将arguments[2]值赋值给arguments[0],[10,2,10]
return a + b + c;
}
console.log(bar(2, 2, 2)) // 22
// 如果执行操作一
// 将c定义在函数参数的作用域中,外部无法改变,c覆盖为与arguments无关的内容,输出14var x = 1;
function foo(x, y = function() { x = 2; }) { //传参内单独一个作用域空间
x = 3; // 这里的x覆盖内部x
//var x = 3
y(); // 由于内部x与y方法定义在传参的作用域空间,所以覆盖内部x
console.log(x); // 输出2
}
foo()
console.log(x); // 输出1
// 如果将函数内部的x=3改为var x=3;
// 内部重新声明了一个x,导致y方法无法修改新x的值,使用内部输出3,外部仍然输出1对于有默认值的参数,对应的arguments属性则无法被赋值;函数的传参位置会单独开辟一个作用域空间
7)
function fun(n,o) {
console.log(o)
return {
fun:function(m){
return fun(m,n);
}
};
}
var a = fun(0); // 创建一个数据空间a,输出undefined,n=0
a.fun(1); // 使用空间a,输出0
a.fun(2); // 使用空间a,输出0
a.fun(3); // 使用空间a,输出0
var b = fun(0).fun(1).fun(2).fun(3); // 链式后方法使用前一个方法创建的空间,最终创建空间b,依次输出 undefined 0 1 2
var c = fun(0).fun(1); // 同上,最终创建空间c,输出 undefined 0,n=1
c.fun(2); // 使用空间c,输出1
c.fun(3); // 使用空间c,输出1链式调用会创建一个共享的空间,类似于闭包
8)
var num = 1;
var myObject = {
num: 2,
add: function() {
this.num = 3;
(function() {
// this为外层函数执行地方的外层
console.log(this.num);
this.num = 4;
})();
console.log(this.num);
},
sub: function() {
console.log(this.num)
}
}
myObject.add(); // add的this指向myObject,add内自执行函数this指向定义位置执行地方的外层,此处为window,输出 1 3,myObject.num=3 全局num=4
console.log(myObject.num); // 3
console.log(num); // 4
var sub = myObject.sub;
sub(); // 全局执行,this指向window,输出4在函数内定义且在同一地方执行的内层函数(包括自执行函数),在调用时会默认执行在外层函数执行区域
