js中this的问题及其他内容

call与apply bind

同:都是都是function对象原型上的方法,用来改变this指向的

不同:传参形式不同call(obj,10,20,30) allpy(obj,[10,20,30])函数直接执行

还有一个方法bind,bind传参与call相同,但是返回的是一个函数,它不会马上执行。

call的性能更好,尤其是传给函数参数大于三个时,这种方式会返回一个新函数,但不会马上执行。

apply:

func.apply(thisArg, [argsArray])

thisArg: 必选,func函数运行时的this值。指定为null或undefined时会自动替换为指向全局对象。

js中new操作符都干了什么

new操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。

1、创建一个空的对象

2、将构造函数作用域赋给新对象(因此this就指向了这个新对象)

3、执行构造函数(为这个新对象添加属性)

4、返回新对象 (所以函数中不需要return)

this的问题

函数内部

this的值取决于函数被调用的方式。

在非严格模式下,且this的值不是由调用设置的,所以this的值默认指向全局对象,即window。;在严格模式下,如果进入执行环境中没有设置this的值,this的值为undefined。

function fn1(){
	return this
}
fn1()===window
function fn2(){
	"use strict"
	return this
}
fn2() === undefined  //true

类上下文

this的表现与在函数中类似(类本质上也是函数)

在类的构造函数中,this是一个常规对象,类中所有的非静态方法都会被添加到this的原形中。(静态方法不是this的属性,它们只是类自身的属性)

类中的this

和普通函数一样,方法中的this取决于它们如何被调用,有时,改写行为,让类中的this值总是指向这个类实例会很有用。

 constructor() {
    // Bind sayBye but not sayHi to show the difference
    this.sayBye = this.sayBye.bind(this);
  }

类内部总是严格模式。

this和对象转换

function add(c,d){
	return this.a+this.b+c+d
}
let o = {a:1,b:3}
//第一个参数用作“this”的对象。其余用作函数的参数
add.call(o,5,7)  // 16 
add.apply(o,[10,20]) // 34 

非严格模式下使用call和apply时,如果用作this的值不是对象,则会被尝试转换为对象。null和undefined被转换为全局对象。其他类型会使用相应的构造函数转换为对象。

function bar(){
	console.log(Object.prototype.toString.call(this));
}
bar.call(7);     // [object Number]
bar.call('foo'); // [object String]
bar.call(undefined); // [object global]

bind方法

调用bind方法会创建一个新函数,this将永远的被绑定到bind的第一个参数,无论后续这个函数如何被调用。

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var h = g.bind({a:'yoo'}); // bind只生效一次!
console.log(h()); // azerty

var o = {a:37, f:f, g:g, h:h};
console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty

作为对象的方法

this的绑定只受最接近的成员引用的影响。

原型链中的this

记住原型链的特性,先在自身找,由于继承了原型链上的属性(方法),所以函数的this指向当前对象。也就是函数是作为当前对象的方法调用的,所以它的this指向了当前对象。

作为构造函数

当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。

构造函数默认是返回this所指向的那个对象,但它也可以手动返回一个对象(如果返回值不是一个对象,则返回this对象)

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37


function C2(){
  this.a = 37;  //“僵尸代码”,对外部没有任何影响
  return {a:38};   //手动返回对象
}

o = new C2();
console.log(o.a); // logs 38

作为一个DOM事件处理函数

当函数被用作事件处理函数时,它的this指向触发事件的元素。

作为一个内联事件处理函数

当代码被内联on-event处理函数调用时,它的this指向监听器所在的DOM元素。

<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>

当没有设置内部函数的this时,它会指向global/window对象(非严格模式下)

<button onclick="alert((function(){return this})());">
  Show inner this
</button>

函数表达式

​ 函数表达式和函数声明的最主要区别是函数名称,在函数表达式中可省略它,从而创建匿名函数。一个函数表达式可被用作IIFE(立即执行函数)。

函数表达式提升

函数表达式没有提升,与函数声明不同。

命名函数表达式

如果要在函数体内部引用当前函数,则需要创建一个命名函数。函数名称将只会作为函数体(作用域)的本地变量(即不可在外部进行调用)。

展开语法

函数调用时

等价于apply的方式

function myfunc(x,y,z){ }
let args = [1,2,3];

myfunc.apply(null,args)
//使用展开语法
myfunc(...args);

在new表达式中使用

使用new关键字来调用构造函数时,不能直接使用数组+apply的方式(apply调用的是[[ Call ]],而不是构造 [[Constructor]])。

var dateFields = [1970, 0, 1]; // 1970年1月1日
var d = new Date(...dateFields);

使用的便捷性

  1. 构造字面量数组时更便捷
var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes']; 
  1. 数组拷贝
let arr = [1,2,3]
let arr2 = [...arr]   //[1,2,3]

实际展开语法和Object.assign()行为一致,执行的都是浅拷贝。

构建对象字面量时

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };

var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 }

不能替换或模拟Object.assign()函数。(具体参看mdn官方文档)

只能用于可迭代对象

var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
var array2 = {...obj}  //  {'key1': 'value1'}

in操作符

如果指定的属性在指定的对象或其原型链中,则in运算符返回true。

// 数组
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
0 in trees        // 返回true
3 in trees        // 返回true
6 in trees        // 返回false
"bay" in trees    // 返回false (必须使用索引号,而不是数组元素的值)

"length" in trees // 返回true (length是一个数组属性)

对于继承来的属性,in运算符也会返回true。

arguments

是一个传递给函数的参数的类数组对象。

arguments对象是所有(非箭头)函数中都可用的局部变量,可以用下面的方式引用:

arguments[0];
arguments[1];

arguments对象不是一个Array,它类似Array,但只有length属性和索引元素,也不能进行pop.但它可以被转换为一个真正的Array:

let args = Array.prototype.slice.call(arguments);
let args = [].slice.call(arguments);

对参数使用扩展语法:使用Array.from()或 扩展运算符讲将参数转换为真实数组。

let args = Array.from(arguments);
let args = [...arguments]

属性:

arguments.callee:指向参数所属的当前执行的函数;指向调用当前函数的函数。

arguments.length:传递给函数的参数数量。

argumnens[@@iterator]:返回一个新的Array迭代器对象,该对象包含参数中每个索引的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值