file
作者 | Jeskson
来源 | 达达前端小酒馆
1
究竟是什么样的题目让我徒弟疑惑呢?让我们看看截图先,来源于wx群:
file
看看我是怎么回答的:
file
file
file
file
file
function Foo() {
getName = function () { alert (1); };
return this;
}
var getName;
//只提升变量声明
function getName() { alert (5);}
//提升函数声明,覆盖var的声明
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
getName = function () { alert (4);};
//最终的赋值再次覆盖function getName声明
getName();
//最终输出4
看懂没呢?没看懂也别急哈:
先让我们了解函数的定义:
函数声明,可以先调用再声明
dadaFn();
function dadaFn(){
console.log(dadaFn);
}
file
/ 返回 f -> function
function dadaFn() {
console.log(dadaFn);
}
let daDafn = function() {
console.log("dada");
};
daDafn();
file
let fn = function() {
console.log(111);
}
fn(); //111
VM1188:2 111
undefined
let daDafn = function() {
console.log("dada");
}
daDafn();
VM1197:2 dada
undefined
let da = () => {};
console.log( da.prototype );
file
JavaScript prototype属性,可以让你向对象添加属性和方法:
格式:
object.prototype.name = value;
function dada (name,age) {
this.name = name;
this.age = age;
}
var dashu = new dada("dashucoding", 13);
dada.prototype.job = null;
dashu.job = it;
console.log(dashu.jog);
输出结果:
it
let da1 = new Function('a', 'b');
da1(1,2);
file
let da1 = new Function('a', 'b');
da1(1,2);
VM65:3 Uncaught ReferenceError: b is not defined
at eval (eval at <anonymous> (local-ntp.html:1), <anonymous>:3:1)
at <anonymous>:3:1
(anonymous) @ VM65:3
(anonymous) @ VM64:3
let fn1 = new Function('a', 'b', 'console.log(a * b)');
fn1(1, 2); //2
VM69:3 2
undefined
预解析,变量提升的概念:
file
file
function Foo() {
getName = function () { console.log (1); };
return this;
}
Foo.getName = function () { console.log (2);};
Foo.prototype.getName = function () { console.log (3);};
var getName = function () { console.log (4);};
function getName() { console.log (5);}
//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
VM243:5 2
VM243:7 4
VM243:2 1
VM243:2 1
VM243:5 2
VM243:6 3
VM243:6 3
//答案:
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3
变量定义提升,this指针指向,运算符优先级
原型、继承、全局变量污染、对象属性及原型属性优先级
在JavaScript中,prototype对象是实现面向对象的一个重要机制。
每个函数就是一个对象(Function),函数对象都有一个子对象 prototype对象,类是以函数的形式来定义的。prototype表示该函数的原型,也表示一个类的成员的集合。
通过new创建一个类的实例对象的时候,prototype对象的成员都成为实例化对象的成员。
1、该对象被类所引用,只有函数对象才可引用; 2、在new实例化后,其成员被实例化,实例对象方可调用。
同时,函数是一个对象,函数对象若直接声明成员,不用被实例化即可调用。
prototype 属性使您有能力向对象添加属性和方法。
构造函数的简单介绍
file
function Person(){
this.name = 'dada';
}
var boy = new Person();
console.log(boy.name); //'dada'
VM254:5 dada
undefined
file
为了解决构造函数的对象实例之间无法共享属性的缺点,js提供了prototype属性。
js中每个数据类型都是对象(除了null和undefined)。
每个对象都继承自另外一个对象,后者称为“原型”(prototype)对象,只有null除外,它没有自己的原型对象。
原型对象上的所有属性和方法,都会被对象实例所共享。
通过构造函数生成对象实例时,会将对象实例的原型指向构造函数的prototype属性。
每一个构造函数都有一个prototype属性,这个属性就是对象实例的原型对象。
原型对象的属性不是对象实例的属性。
对于对象实例来说,prototype是对象实例的原型对象。
所以prototype即是属性,又是对象。
file
原型链:原型链主要用于继承,每个对象都有一个proto属性指向其构造函数的原型对象,当访问对象的属性和方法时,会先在对象自身进行查找,如果不存在,则沿着proto属性向上一级查找,直到没找到返回 undefined,这样的查找过程,称之为原型链。
原型链,请找我文章:一篇文章带你了解JavaScript中的变量,作用域,和内存问题。
function Foo() {
getName = function () { console.log (1); };
return this;
}
Foo.getName = function () { console.log (2);};
Foo.prototype.getName = function () { console.log (3);};
var getName = function () { console.log (4);};
function getName() { console.log (5);}
//请写出以下输出结果:
Foo.getName(); // 2
看代码,先定义一个Foo()的函数,之后为Foo创建一个叫getName的静态属性,用来存储一个匿名的函数,之后为Foo的原型对象,新创建了一个叫getName的匿名函数。
var getName = function () { console.log (4);};
function getName() { console.log (5);}
然后通过函数变量表达式,创建一个getName的匿名函数,然后由通过函数变量表达式,创建一个getName的函数。
最后一个是声明一个叫getName的函数。
Foo.getName(); // 2
这个不用说就是访问Foo()函数上存储的静态属性,答为2。
下一个问:
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
getName(); 的答案呢? // 5
function Foo() {
getName = function () { console.log (1); };
return this;
}
这里要分开理解看
Foo.getName = function () { console.log (2);};
Foo.prototype.getName = function () { console.log (3);};
var getName = function () { console.log (4);};
function getName() { console.log (5);}
file
function Foo() {
getName = function () { alert (1); };
return this;
}
var getName;
//只提升变量声明
function getName() { alert (5);}
//提升函数声明,覆盖var的声明
Foo.getName = function () { alert (2);};
getName = function () { alert (4);};
//最终的赋值再次覆盖function getName声明
getName();
//最终输出4
var getName 只提升变量声明
function getName 函数声明,覆盖var的声明
直接调用getName()函数,就是访问当前上文作用域内的叫getName的函数
file
这样var getName提升,函数整体提升到上面了,那么就剩下getName结果为4的那个了。
一个是变量作用域问题,一个是this指向问题。
Foo().getName();
第一个Foo()函数:
function Foo() {
getName = function() {
console.log('1');
}
}
即Foo().getName()中
file
先执行Foo()函数,然后调用Foo函数返回的返回值对象的getName属性函数。
file
getName(); // 函数 1
相当于window.getName(),因为这个变量被Foo函数执行时修改了,结果同样为1。
file
new Foo.getName();
file
点 . 的优先级高于new操作,等价于:
new (Foo.getName)();
// 将getName函数作为了构造函数来执行
// 2
file
new Foo().getName(); // 3
// 运算符优先级括号高于new
等价于
(new Foo()).getName()
先执行Foo函数,此时作为构造函数,有返回值。
file
若有返回值则检查其返回值是否为引用类型
file
若返回值是引用类型,则实际返回值为这个引用类型。
file
价于
(new Foo()).getName()
# ```
![file](https://upload-images.jianshu.io/upload_images/11158618-8cf05e8df59bfce8.jpeg)
new new Foo().getName();
new ((new Foo()).getName)();