JavaScripts高阶(9)前端必须了解的函数的三种角色

1、普通函数

  • 堆栈内存
  • 作用域链

2、类(构造函数)

  • prototype 原型
  • __proto__ 原型链
  • 实例

3、普通对象

  • 和普通的obj没啥区别,就是对键值对的增删改查

三种角色没有必然关系

1、私有变量只跟普通函数有关,在作为类和普通对象情况下是没用的(获取不到)

2、prototype是函数作为普通对象的一个属性,但是prototype里边放的东西就跟它就没关系了而是跟它的实例有关系;

3、凡是Fn.prototype.xxx=xxx都是跟作为构造函数创建出来的实例有关

4、在new Fn()的方式中,函数体中的this.xxx=xxx 都是跟作为构造函数创建出来的实例有关

5、作为普通对象时,只有 Fn.属性名=属性值 这种才和它有关系

6、函数体中的代码跟作为普通对象没关系,因为函数体中放的是字符串,不执行一点意义也没有,而作为对象不需要执行就能操作键值对

7、new xxx也会使函数执行

function Fn(){
	var n=10;
	this.m=100;
}
Fn.prototype.aa=function(){
	console.log('aa')
}
Fn.bb=function(){
	console.log('bb')
}

//=>普通函数的执行
Fn();     //this:window     有一个私有变量 n  ; 和原型以及属性没有关系

//=>构造函数执行
var f=new Fn();  //this:f    
console.log(f.n)   //undefined n为私有变量 和实例没有关系
console.log(f.m)   //100  实例的私有属性
f.aa();           //'aa'   通过原型链找到了 Fn.prototype上的方法
f.bb();           //bb  is undefined  bb是把Fn当做一个普通对象设置的属性而已;和实例等没有半毛钱关系

//=>普通对象   只跟Fn.bb有关   prototype是函数对象的一个属性,但是prototype里边放的东西跟它就没关系了
Fn.bb()       //'bb'



复制代码

以Number内置类为例:

console.dir(Number)

把Number作为普通对象加入的方法,点前边必须为Number

Number的prototype里存的方法是实例的方法,所以点前边必须是Number的具体实例才能调用(数字或者NaN)

jQuery这个类库中提供了很多的方法,其中有一部分是写在原型上的,有一部分是把它当做普通对象来设置的

~function  (){
	function jQuery(){
		//...
		//return  [jQuery实例]
	}
	jQuery.prototype.animate=function (){}
	jQuery.ajax=function(){}
	
	window.jQuery = window.$ =jQuery;
}();

$(); //返回实例
$().ajax()  //不能调用,ajax是普通对象的键值对
$.ajax()  //可以  直接调取普通对象键值对
$().animate()  //可以   

$.animate()  //不可以   对象上没有animate这个属性
复制代码

var getName=function(){},在全局变量提升中只是定义 没赋值,getName为undefined,在代码执行的时候才赋值;function getName 声明并赋值全局 getName 为‘console.log(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(5)的函数顶掉
	console.log(4)
}
function getName(){         //全局变量提升阶段声明并定义 代码执行的时候就不再进行任何操作
	console.log(5)
}
Foo.getName();               //  2
getName();                   //4
Foo().getName();             //  1
getName();					 //1
new Foo.getName();           //=>A:(Foo.getName) =>new A;   2
new Foo().getName()          //=>B:new Foo() =>B.getName()  3
new new Foo().getName();     //=>C:new Foo() =>把C.getName作为一个整体new(C是Foo的实例) D:C.getName  =>  new D()  3

//=>全局作用域  
//变量提升 Foo,getName
//Foo=AAAFFF111(1、开辟堆内存2、存字符串3、建立联系)天生自带 prototype
//getName=AAAFFF222(1、开辟堆内存2、存字符串3、建立联系)天生自带 prototype
		//var getName=,在全局变量提升中只是定义 没赋值;function getName 声明并赋值全局 getName  为‘console.log(5)’  **重要注意点**

//=>代码执行
//AAAFFF111.getName=bbbFFF111   console.log(2)  Foo作为普通对象添加键值对
//AAAFFF111.prototype.getName=bbbFFF222   console.log(3)
//var getName=, 因为在变量提升中声明过所以只赋值;所以全局getName为‘console.log(4)’
//Foo作为普通对象的getName执行  2
//全局getName(window.getName)执行 4
//Foo作为普通函数执行,把返回值的getName执行
	//Foo作为普通函数执行形成私有作用域  
		//形参赋值  变量提升没有
		//代码执行
			//全局getName  console.log(1)
			//return this  为 window
			//window.getName执行  1
//全局getName(window.getName)执行   1
//(new (Foo.getName))()  Foo作为普通对象的getName属性 执行  2
//(new Foo()).getName()  实例.getName执行    3
//(new ((new Foo()).getName))()     (实例.getName)的实例  执行  3
复制代码

在Foo后面没有东西的时候,new Foo和new Foo()是一样的;但是在Foo后面有东西时就不一样了:new Foo.getName() 是把new Foo.getName作为一个整体new的 相当于A:(Foo.getName) new A;new Foo().getName() 先new Foo() 让实例的getName执行

js中的运算符优先级 (数值越大优先级越高)

从左到右:同级别 从左到右先写谁,谁的优先级高

image.png

image.png

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享