JavaScript高级程序设计第十章阅读第一部分

99 阅读4分钟

10.9 this

函数的this关键字在JavaScript中的表现略有不同。在严格模式下和非严格模式下略有差异

在绝大多数情况下,函数的调用方式决定了this的值(运行时绑定),this不能在执行期间被赋值 并且在每次函数被调用时this的值也会不同。ES5引入了bind方法来设置函数的this值

无论是否在严格模式下,全局环境中this都指向全局对象

	console.log(this===window);	//返回true
	a=37;
	console.log(window.a);		//返回37
	this.b="MDN";
	console.log(window.b);		//返回 MDN
	console.log(b);				//"MDN"

在函数内部,this的值取决于函数被调用的方式

	function f1(){
		return this;
	}
	conosole.log(f1()===window);	//返回true

然而,在严格模式下,如果进入执行环境时没有设置this的值,this会保持为undefined

	function f2(){
		"use strict";
		return this
	}
	console.log(f2()===undefined);	//返回true

bind方法

	function f(){
		return this.a;
	}
	var g=f.bind(a:"JackMa");
	console.log(g());
	var h=g.bind(a:"MarkJie");
	console.log(h());			//返回	JackMa,bind只能绑定一次
	
	var o={a:37,f:f,g:g,h:h};
	console.log(o.a,o.f(),o.g(),o.h());		//返回37 37 JackMa JackMa

函数作为对象里的方法被调用时,this被设置为调用该函数的对象。 下面的例子中,当o.f()被调用时,函数内部的this将绑定在o对象上

	var o={
		prop:37,
		f:function(){
			return this.prop;
		}
	}
	console.log(o.f());		//返回 37

原型链中的this

对于在对象原型链上某处定义的方法,同样的概念也适用。如果该方法存在一个对象的原型链上,那么this指向的是调用这个方法的对象,就像该方法在该对象上一样。

	var o={
		f:function(){
			return this.a+this.b;
		}
	}
	var p=Object.create(o);
	p.a=1;
	p.b=5;
	console.log(p.f());		//返回	5

	var s=new Object(o);
	s.a=20;
	s.b=5;
	
	console.log(s.f());		//返回	25,这里的this.a是s.a

Sample1 哪个对象调用的方法,方法中的this就指向那个对象

	window.color="red";
	let o={
		color:"blue";
	}
	let s={
		color:"black";
	}
	
	function sayColor(){
		return this.color;
	}
	console.log(this.sayColor());	//返回 red	this指向window
	o.sayColor=sayColor;
	console.log(o.sayColor());		//返回 blue	this指向o
	s.sayColor=sayColor;
	console.log(s.sayColor());		//返回 black this指向s

10.10 函数属性和方法

前面提到过,ECMAScript中的函数是对象,因此有属性和方法。每个函数都有两个属性length和prototype,其中,length属性保存函数定义的命名参数个数。

prototype属性

prototype属性是ECMAScript中最有趣的部分。prototype是保存引用类型所有实例方法的地方。 意味着,toString()、valueOf()等方法实际上都保存在prototype上

function还有两个函数,一个是apply()和call()这两个方法都会指定this值来调用函数。

sample\apply()函数

	let nums=[1,3,5,7,9];
	function sum(num1,num2){
		return num1+num2;
	}
	function callSum1(num1,num2){
		return sum.apply(this,arguments);	//传入 arguments对象
	}
	function callSum2(num1,num2){
		return sum.apply(this,[num1,num2]);
	}
	console.log(callSum1(10,10));		//返回 20
	console.log(callSum2(100,200));		//返回 300
	
	function plu(num){
		let ret=0;
		for(let=0;i<num.length;i++){
			ret+=num[i];
		}
		return ret;
	}
	nums.push(55);
	function callSum3(num){
		return plu.apply(this,arguments);
	}
	function callSum4(num){
		return plu.apply(this,[num]);
	}
	console.log(callSum3(nums));		//返回 80
	console.log(callSum4(nums));		//返回 80
	
	console.log(Math.max.apply(null,nums));	//返回 55
	console.log(Math.min.apply(null,nums));	//返回 1
	console.log(plu.apply(null,[nums]));	//返回 80

注意,apply(this,[nums]) [nums]为一个类数组的参数,可以是arguments可以是数组

apply()和call()真正强大的地方并不是给函数传参。而是控制函数调用上下文,即函数体内this值得能力

Sample控制函数的参数调用

	window.color="red";
	let p={
		color:"pink",
	}
	
	let b={
		color:'black'
	}

	function sayColor(){
		return this.color;
	}
	sayColor();		//返回red
	sayColor.call(this);		//返回	red
	sayColor.call(window);		//返回 	red
	sayColor.call(p);			//返回	pink
	sayColor.call(b);			//返回	black

bind方法

bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数作为新函数的参数供调用。

	const test={
		name:"JackMa",
		getName:function(){
			return this.name;
		}
	}
	const notGetX=test.getName;
	console.log(notGetX());		//返回 undefined
	
	const GetX=notGetX.bind(test);
	console.log(GetX());		//返回42

bind()最简单的用法是创建一个函数,无论怎样调用,这个函数都有同样的this值。JavaScript新手经常犯的错误是将一个方法从对象中拿出来,然后再调用。期望方法中的this还是原来的对象。如果不做特殊处理,则会丢失

10.11 函数表达式

函数表达式包括函数声明和函数表达式 MDN:函数在JS中是头等公民,它和其它对象一样具有属性和方法,简而言之函数是Function对象的实例

sample 在FireFox中打开

	let fun=function(x,y){
		return x+y;
	}
	console.log(fun.constructor);	//fun的constructor指向fun的构造函数,返回的是Function	

形参和实参

函数定义

语法:

	function FUNC([parms,[parms]]){statements};

FUNC 函数名,parms参数,statements组成函数体的声明语句

函数表达式