JS常用知识点

我心飞翔 分类:javascript

基本概念

一:JS的输出方法

document.getElementById("").innerHTML=;		                        //id的地方输出
document.write();							//页面输出
console.log();								//控制台输出
alert();								//弹窗输出
 

二:JS的引入有三种

1、外部引入         <script src="js地址" type="text/javascript" charset="utf-8"></script>

2、内部引入         <script type="text/javascript">js代码</script>

3、行内引入         <body> 
                   <button οnclick="alert(123)">点击我</button>
                   <!--onclick:点击触发一个事件,alert:弹出一个对话框-->
                   </body>
 

三:JS语法(变量):

1、JS是大小写敏感的
2、每条语句结束应该加分号
3、变量必须以字母或_或$开头
4、变量不能是关键字
 

四:JS命名规范:

1、驼峰法命名	myName		第二个单词首字母大写
 

五:JS注释:

//		//单行注释
/* */		//多行注释
 

六:JS有七种数据类型:

1、(Number)数字类型:整数  或者是  小数  或者是  科学计数法
例子:1	1.2	12e5

2、(String)字符串类型:带有  双引号  或者  单引号  , 两者没啥区别
例子:"string"	'string'

3、(Boolean)布尔型:值只有  trun  或  false
4、(Object)对象类型:new object{}		        typeof返回是object对象
5、(Null)类型:null:空					typeof返回是object对象
6、(Undefined)类型:undefined:未定义	                typeof返回是object对象

额外引用类型:
(Array)数组类型:new Array[]			        typeof返回是object对象
(Function)函数类型:function()		                typeof返回是function对象

ES6新出的:
7、(Symbol)类型:方法let symbol = Symbol(参数)	作用:返回的值是唯一的,可以作为对象的标识符,
例子:(Symbol(1) === Symbol(1)) 输出false
 
注意:Undefined、Null、Number、Boolean、String 定义为基本数据类型,因为其是按值访问的,可以操作保存在变量中的实际的值。引用类型值是保存在内存中的对象,操作对象时,实际上操作的是对象的引用。

八:JS的运算符:

1、赋值,算术
=  +  -  *  /

2、条件,比较
==(先转换类型再比较)	===(直接比较类型和值)	<  >  !=  <=  >=

3、&&(and,两个都为true,才是true)	
4、||(或,两个条件一个为true,就是true)		
5、!(非,反着来
 

九:JS循环语句

1、for循环
2、while循环
3、do while循环
4、for in循环遍历数组和对象
5、for of遍历字符)
 

十一:JS判断条件语句

1、if() else if() else语句
2、switch() case: break default continue语句
3、(条件) ? 真:假三元运算符
4、??空值合并运算符		//值不是null和undefined,就返回该值
 

数字类型

数字类型的方法

1、Math.floor(num)向下舍入
2、Math.ceil(num)向上舍入
3、Math.round(num)向近舍入
4、num.toFixed(n)将数字后面的小数保留n位
5、isNaN(num)表示是否是非数字
6、parseInt(num)从字符串读取整数
7、parseFloat(num)从字符串读取小数
8、Math.random()随机返回一串0~1小数
9、Math.max(num)从中比较大小,返回最大值
10、Math.min(num)从中比较大小,返回最小值
11、Math.pow(num,次数)返回一个参数多少次幂
 

数组

从上面的对象我们知道对象允许存储键值集合,这很好,但是我们发现有一些场景对象不是很适合,比如:
当我们想在已有的元素中插入一个新的属性,就很麻烦了
这时候就由数组派上用场了,它能存储有序的集合
 

声明

创建一个空数组有两种语法:
let arr = new Array();
let arr = [];

绝大多数情况下都是使用第二种声明
let arr = ["Apple", 23, "Plum"];
alert( arr[0] ); // Apple
alert( arr[1] ); // 23
alert( arr[2] ); // Plum

let arr = ["Plum", 23, "Apple"];
alert( arr[0] ); // Plum
alert( arr[1] ); // 23
alert( arr[2] ); // Apple
从上面代码我们可以知道,数组元素是从0开始的,并且跟位置有关,不像对象,属性定位
 

常用的数组方法

  1. arr.push()				描述:从数组尾端添加元素
     
  2. arr.pop()				描述:从数组尾端删除元素
     
  3. arr.unshift()			        描述:从数组首部添加元素
     
  4. arr.shift()				描述:从数组首部删除元素
     
  5. arr.concat(...items)	    	        描述:返回一个数组:复制当前数组,并添加items,如果是数组,则取元素
     
    let arr2 = [5, 6];
    alert( arr.concat([3, 4]) ); // 1,2,3,4
    alert( arr.concat(arr2) ); // 1,2,5,6
 
  1. arr.indexOf(item, from)                 描述:从索引 from 开始搜索 item,如果找到则返回索引,否则返回 -1。
     
  2. arr.find(item,index,array)		描述:item是元素,index是查找的条件,array是查找的数组,从array数组查找index,如果返回true,那就返回item
     
  3. arr.findindex()			        描述:跟find一样,返回的是元素的索引
     
  4. let results = arr.filter()		描述:跟find差不多,如果找到元素item,则把这元素添加到results中,没找到返回空数组;
     
  5. arr.sort(a,b)				描述:快速排序,注意:这是按照首字排序,在sort()中,2>15,只会按照首字(首字符)比较,如果a>b,返回1,a=b,返回0,a<b,返回-1,则从小到大,反之一样
     
  6. arr.reverse()			        描述:返回一个颠倒arr元素中的数组
     
  7. arr.split(',')				描述:可以把逗号作为分隔符,分成一个个数组   
     
    let arr = names.split(', ');
    for (let name of arr) {
      alert( `A message to ${name}.` ); // A message to Bilbo(和其他名字)
    }
 
  1. arr.filter()                            描述:find 方法搜索的是使函数返回 true 的第一个(单个)元素。
     
  2. arr.slice()                             描述:它会返回一个新数组,将所有从索引 start 到 end(不包括 end)的数组项复制到一个新的数组
     
    alert( arr.slice(1, 3) ); // e,s(复制从位置 1 到位置 3 的元素)
    alert( arr.slice(-2) ); // s,t(复制从位置 -2 到尾端的元素)
 
  1. arr.splice()                            描述:返回删除后的数组,接受三个参数,第一个从第几个开始删除,第二个删除的数量,第三个添加的内容
     
    arr.splice(0, 3, "Let's", "dance");
    alert( arr ) // now ["Let's", "dance", "right", "now"]
 

字符串

字符串的方法

1、str.toUpperCase()转换为大写字母
2、str.toLowerCase()转换为小写字母
3、str.indexOf(查找的参数,从第n个位置开始查找)如果找到就返回索引的位置,否则返回-1
4、str.lastIndexOf()
5、str.includes(查找的参数,开始搜索的位置)有就返回true,没就返回false
6、str.startsWith(查找的参数)查找的参数开头,有就返回true,没就返回false
7、str.endsWith(查找的参数)查找的参数结尾,有就返回true,没就返回false
8、str.splice(start,end,item1...itemN)返回被删除的字符串从start到end部分,并且添加item1...itemN
9、str.slice(start,end)返回字符串从start到end(不包括end)部分
10、str.substring(start,end)返回字符串从start到end(不包括end)部分,运行start大于end值
11、str.substr(start,length)返回字符串从start开始,索取length长度的部分
12、str.trim()删除字符串前后出现的空格
13、str.repeat(n)重复字符串n次
 

函数

函数就是一个程序,函数可以里面的代码重复调用,不用重复写代码
**有以下几种函数方式**
 

函数声明

function hello() {
  alert( 'Hello everyone!' );
}
hello就是函数名
 

匿名函数

function () {
  alert( 'Hello everyone!' );
}
没有函数名就是匿名函数
 

匿名函数的四种调用方法

//第一种方法
var a=function(){
    console.log("Hello World!");
}
a();
//第二种方法
(function (){
   console.log("Hello World!");
})();
//第三种方法
(function (){
   console.log("Hello World!");
}());
//第四种方法
[function(){
   console.log("Hello World!");
}()];
 

函数表达式

let hello = function() {
  alert( "Hello" );
};
在这里函数被创建,并把里面的值分配给hello。
 

构造函数

1、它们的命名以大写字母开头。
2、它们只能由 "new" 操作符来执行。
例如:

function User(name) {
  this.name = name;
  this.isAdmin = false;
}
let user = new User("Jack");
alert(user.name); // Jack
alert(user.isAdmin); // false
 

嵌套函数

在一个函数内部创建另一个函数,就是嵌套函数
function sayHiBye(firstName, lastName) {
  // 辅助嵌套函数使用如下
  function getFullName() {
    return firstName + " " + lastName;
  }
  alert( "Hello, " + getFullName() );
  alert( "Bye, " + getFullName() );
}
 

传入多个参数

在JavaScript中,你传入多少个参数,就调用多少个参数,多传入参数是没用的
function sum(a, b) {
  return a + b;
}

alert( sum(1, 2, 3, 4, 5) ); //3
从上面代码可以看出,只有两个参数被调用

我们可以使用Rest参数...
就是前面三个点加上数组名称,意思是“将全部参数放在一个数组里”
function sumAll(...args) { // 数组名为 args
  let sum = 0;
  for (let arg of args) sum += arg;
  return sum;
}
alert( sumAll(1) ); // 1
alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3) ); // 6

当然,我们可以先传入两个参数,再把剩下的参数放进数组中
function sumAll(a, b, ...args) { // 数组名为 args
  let sum = 0;
  for (let arg of args) sum += arg;
  return sum;
}
alert( sumAll(1) ); // 1
alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3, 4, 5) ); // 15
 

闭包

“闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭
包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。”
 

作用域

从闭包中我们知道,正常情况下只能从内部读取外部的变量,无法外部读取内部的变量(其实有方法),这就是函数的作用域
{
  // 使用在代码块外不可见的局部变量做一些工作
  let message = "Hello"; // 只在此代码块内可见
  alert(message); // Hello
}
alert(message); // Error: message is not defined
 

如何在函数外部读取函数内部的变量?

这是我们经常碰见的情况,我推荐三种方法(更多不止)
 

第一通过return访问:

function bar(value) {
  var testValue = 'inner';
  return testValue + value;
}
console.log(bar('fun'));		// "innerfun"
return 返回只是变量(testValue + value),还需要调用该函数获取(bar('fun'));

错误的例子:
function bar(value) {
  var testValue = 'inner';
}
console.log(bar()); //undefined
虽然成功执行了,但没有返回,所以为undefined

错误的例子
function bar(value) {
  var testValue = 'inner';
  return testValue;
}
console.log(testValue); //testValue is not defined
需要通过函数来调用,直接调用会报错,因为外部无法读取内部变量
 

第二通过 闭包 访问函数内部变量:

function bar(value) {
  var testValue = 'inner';
  var rusult = testValue + value;
  function innser() {
     return rusult;
  };
  return innser();
}
console.log(bar('fun'));		// "innerfun"
 

第三立即执行函数:

用它来分离全局作用域,形成一个单独的函数作用域。
<script type="text/javascript">
    (function() {
      var testValue = 123;
      var testFunc = function () { console.log('just test'); };
    })();
    console.log(window.testValue);		// undefined
    console.log(window.testFunc);		// undefined
</script>
 

"new Function" 语法

这个创建函数的方法其实用到次数很少,但是很特别,所以后面才写下
 

语法

let fun = new Function()
 

特殊点

function getFunc() {
  let value = "test";
  let func = new Function('alert(value)');
  return func;
}
getFunc()(); // error: value is not defined
是不是非常眼熟,咦,这不是上面代码吗,只不过有个new,为什么这样报错了呢?
这就是new Function特殊处,当我们用new Function创建一个函数,那么该函数指向就不是当前的语法环境,而是全局
环境,因此,当我们访问value值,其实该函数访问是全局变量,你可以试试加个全局变量value看看,是不是很特殊?
 

总结

写完这些,我总结以下观点:
1、函数作用域,内部读取外部变量,外部无法读取内部变量
2、可以传入一个...数组接收全部参数
3、可以通过一些方法读取函数内部变量
    从上面例子知道,return等于把变量“导出”,调用该函数等于“引入”,只执行其中一步都不行。
4、new Function指向的是全局环境。
 

Object

对象

你们可以把对象当成一个抽屉,里面专门放文件,文件写有某个人名字(key),里面的东西(value)
就比如我们创建一个空的对象(抽屉)
let user = new Object(); // “构造函数” 的语法
let user = {};  // “字面量” 的语法
let caomaoHaiZeiTuan = {             一个对象(抽屉)
    chuanzhang: "路飞",       name就是名字(key),:右边就是对象(value)
    age: "22",            age就是名字(key),:右边就是对象(value)
    jiNeng: "橡胶机关枪",
    jingEr: "10亿赏金",
    chuanyuan: "索隆",       name就是名字(key),:右边就是对象(value)
    age2: "18",            age就是名字(key),:右边就是对象(value)
    jiNeng2: "二刀流",
    jingEr2: "8亿赏金",
}
简单来说,对象就是多了一个认证(属性),在草帽海贼团没成立前,以前我们都是喊路飞路飞的,等草帽海贼团成立了,
我们都应该喊,吖,那是草帽海贼团(caomaoHaiZeiTuan)船长(chuanzhang)路飞,年龄(age)22,技能(jiNeng)是橡
胶机关枪,赏金(jingEr)10亿啊哈!原来这样啊,一个对象可以包含多个属性,可以通过不同的属性读取对应的值
 

对象的引用

let user = { name: "John" };
let lada = user; // 它们是两个数吗?
结果很明显不是,lada只是引用了user的内容

let user = { name: 'John' };
let lada = user;
lada.name = 'hello'; // 通过 "lada" 引用来修改
alert(user.name); // 'hello',修改能通过 "user" 引用看到
还记得基本概念第六题吗?这就是引用类型跟基本类型的区别
如果我们想复制该对象的引用或者完全克隆一个新的对象(不互相引用)该如何实现呢?那可以看下浅拷贝(复制引用)和
深拷贝(完全独立,互不影响)
 

浅拷贝

三种方法(更多都有)

// 1,新建新对象,复制原来对象的值
let obj = {
    name:'AAA',
    age:18
}
let obj1 = {
    name:obj.name,
    age:obj.age
}
obj1.name = 'BBB'
// console.log(obj); // AAA
// console.log(obj1); // BBB

// 2,新建对象,循环添加
let obj2 = {}
for(let key in obj){
    obj2[key] = obj[key]
}
obj2.name = 'CCC'
// console.log(obj); // AAA
// console.log(obj2); // CCC

// 3,Object.assign()
let obj3 = Object.assign({},obj) // 第一个参数目标对象要加上
obj3.name = 'DDD'
console.log(obj); // AAA
console.log(obj3); // DDD
 

深拷贝

三种方法(更多都有)

1. 通过 JSON 对象实现深拷贝
用 JSON.stringify 把对象转换成字符串,再用 JSON.parse 把字符串转换成新的对象,像 function 无法转成
JSON,RegExp 对象也是无法通过这种方式深拷贝。
// 语法--
let deepObj = JSON.parse(JSON.stringify(obj))
// demo--
const obj1 = { a : 1, b : 2}
const obj2 = JSON.parse(JSON.stringify(obj1));
obj1.a = 2;
console.log(obj1); // { a:2, b:2 }
console.log(obj2); // { a:1, b:2 }
对于原对象中undefined、function、symbol 三种数据类型是无效的,因为这三种值会在转换过程中被忽略掉,所以对
有这三种属性的对象使用这种方式会造成上述三种属性的数据丢失。但是对没有这三种属性的数据来说使用这种方式简单
快捷。

2. 通过lodash函数库实现深拷贝
lodash是当前很热门的函数库,提供了 lodash.cloneDeep()可以快速实现对象或数组的深拷贝  loadsh中文网
// 引入loadsh函数库
import _ from 'loadsh'
// 使用cloneDeep实现深拷贝
var obj= [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(obj);
console.log(deep[0] === objects[0]); // => false

3. 使用递归进行深拷贝
function deepClone(source) {
  if (!source) return
  let target;
  if (typeof source === 'object') {
    // 根据source类型判断是新建一个数组还是对象
    target = Array.isArray(source) ? [] : {}
    // 遍历source,并且判断是source的属性才拷贝
    for (let key in source) {
      if (source.hasOwnProperty(key)) {
        if (typeof source[key] !== 'object') {
          target[key] = source[key]
        } else {
          // 如果内部属性存在复杂数据类型,使用递归实现深拷贝
          target[key] = deepClone(source[key])
        }
      }
    }
  } else {
    target = source
  }
  return target
}
 

原型

原型、继承、隐式原型、原型链

相信很多人都听说过这些词,但是对这些词不是很明白啥意思
 
所谓的原型其实指的就是一个prototype属性,每个函数都有一个prototype(原型)属性
隐式原型其实指的就是一个__proto__属性,每个对象都有一个__proto__(隐式原型)属性
继承就是对象的 _proto_属性指向构造函数的 prototype 属性指向的对象
原型链就是对象的 _proto_属性指向构造函数的 prototype 属性的链条

image.png

从图片我们可以知道,其实_proto就是指向上级,prototype指向就是自身

   function Outer() {
    name: "张三"
    }
    let animal = {
      eats: true
    };
    let rabbit = {
      jumps: true
    };
    Outer.prototype //{constructor: ƒ}
    指向Outer,每个函数都有一个原型
    Outer._proto_ //ƒ () { [native code] }
    
    rabbit.__proto__ = animal; 
    rabbit.eats //eats: true
    rabbit.prototype = animal;
    rabbit.eats //undefined
    animal.jumps //undefined
    我们可以看到,rabbit.__proto__ = animal,rabbit.eats=true,可以看出rabbit继承了animal的方法,而
    animal无法使用,当我们再用rabbit.prototype = animal,却发现rabbit无法继承animal方法,所以我们知
    道,隐式原型其实可以继承方法
    
    rabbit.prototype //undefined
 

类型识别有哪些方法

分别是:1. typeof  2. Object.prototype.toString  3. constructor  4. instanceof
 
  1. typeof

它返回值是一个字符串,该字符串说明运算数的类型。typeof一般只能返回如下几个结果:
number,boolean,string,function,object,undefined

console.log(typeof 'abc');  //string
console.log(typeof 1 );  //number
console.log(typeof true );  //boolean
console.log(typeof undefined );  //undefined
console.log(typeof null );  //object
console.log(typeof {name: 'moon'} );  //object
console.log(typeof function () {} );  //function
console.log(typeof [] );  //object
console.log(typeof new Date() );  //object
console.log(typeof /\d/ );  //object
function Person() {}
console.log(typeof new Person() );  //object
 

只能识别原始类型(null除外),不能识别对象类型

  1. Object.prototype.toString

它可以很严谨的识别原始类型和对象类型

//先把方法封装成一个函数
function type(obj) {
    return Object.prototype.toString.call(obj).slice(8,-1);
}
//字符串截取我们需要的部分
console.log(type('moon')); //String
console.log(type(1)); //Number
console.log(type(true)); //Boolean
console.log(type(undefined)); //Undefined
console.log(type(null));  //Null
console.log(type({})); //Object
console.log(type([])); //Array
console.log(type(new Date())); //Date
console.log(type(/\d/));  //RegExp
console.log(type(function () {})); //Function
function Person() {
}
console.log(type(new Person())); //Object
 
  1. constructor  

查看对象的构造函数

4.instanceof

判断对象和构造函数之间的关系

//能够判别内置对象
var a=new Array();
console.log(a instanceof Array); //true
console.log(a instanceof Object);//true.(因为Array是object的子类)
//能够判别自定义对象类型
function test(){};
var a=new test();
console.log(a instanceof test); //true
//不能判别原始数据类型
console.log(1 instanceof Number); //false
console.log('moon' instanceof String); //false
 

this

this算是最常用最重要之一了,新手对this是非常容易感到困惑的,
ES5中,其实你只要记得一句话:**谁调用this,this就指向谁**,记住这句话,再加上我下面的使用场景,理解是毫无
问题的。
 

场景1:全局环境中的this指向就是全局对象

var name = '吃饭';
function a(){
    var name = '睡觉';
    console.log(this.name);//吃饭
    console.log("this指向:" + this) //this指向:Window
}
a();
新手肯定对这个结果感到意外,明明this.name离"睡觉"更近啊,不应该指向"睡觉"吗,还记的我刚刚开始说的那句话吗
?**谁调用this,this就指向谁**,当我们执行a()发现,咦,a()前面没有东西调用啊,就是指向"睡觉"才对啊,其实
不是,前面没有调用的对
象的话,那么就是全局对象Window调用,Window.a(),注意:这不能在严格模式,否则为undefined
 

场景2:对象内部函数的this指向调用函数的当前对象

var name = "吃饭";
var a = {
    name: "睡觉",
    test : function () {
        console.log(this.name);      // 睡觉
    }
}
a.test()
相信有上一个场景大家对这个答案应该没什么疑惑了吧,我们可以看到test函数是由a调用的,所以this指向a的值
我改动一下代码,看看这个例子
var name = "吃饭";
var a = {
    name: "睡觉",
    test : function () {
        console.log(this.name);      // 睡觉
    }
}
window.a.test()
还是刚刚那句话“谁调用this,this就指向谁”,最后调用它的对象仍然是对象a。
 

场景3:匿名函数中的this指向全局对象

var name = "吃饭";
var a = {
    name: "睡觉",
    test : (function () {
        console.log(this.name);      // 吃饭
    })()
}
a.test()
因为匿名函数是一个没有指针的全局变量,那么它的指向的就是全局 就是window对象,所以最后是window调用,所以还
是刚刚那句话“谁调用this,this就指向谁”
 

场景4:setInterval和setTimeout定时器中的this指向全局对象

var name = "吃饭";
var a = {
    name : "睡觉",
    func1: function () {
        setTimeout( function() {
            console.log(this.name)
        },100);
    }
};
a.func1()
大家看看跟上一个匿名函数有啥区别,聪明的你肯定发现了,setTimeout执行也是一个匿名函数
看看setInterval的
var name = "吃饭";
var a = {
    name : "睡觉",
    func1: function () {
        setInterval( function() {
            console.log(this.name)
            clearInterval(a)
        },100);
    }
};
a.func1()
 

场景5:构造函数中的this指向构造出的新对象

var name = "吃饭"
function Person(name,age){
 this.name = name;
 this.sayName = function(){
  console.log(this.name);
 }
}
var a = new Person('睡觉');
a.sayName();
构造函数中的this指向构造出的新对象,new Person()其实已经是调用了这个函数
 

场景六:new Function中的this指向全局对象

var name = "吃饭"
function Foo(){
name : "睡觉"
 this.bar = function(){
  var f = new Function("alert(this.name)");
  f();//[object Window]
 }
}
var foo = new Foo();
foo.bar(); //吃饭
这个例子看完可能有点懵,还是那句话“谁调用this,this就指向谁”,当我们删除f()发现得出undefined,也就是说其
实是f()调用了this,而f()没有自已的name,所以它的指向是全局对象的name。
 

ES6的箭头函数

前面的场景其实都是ES5的,现在看看特殊的ES6箭头函数的this,箭头函数需要记得这句话:“箭头函数中没有 this 
绑定,必须通
过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则
,this 为 
undefined”,太长不理解没事,看看下面代码再来理解这句话
 
套用一下场景4的代码
var name = "吃饭";
var a = {
    name : "睡觉",
    func1: function () {
        setTimeout( () => {
            console.log(this.name)
        },100);
    }
};
a.func1() //睡觉
跟场景4不一样对不对,其实这里我们就可以看出,箭头函数的this其实是从内往外找的,我们再读读那句话,是不是瞬
间又理解了点再看看这个例子:
var name = "吃饭";
var a = {
    name : "睡觉",
    func1: function () {
        console.log(this.name)     
    },
    func2: function () {
        setTimeout( () => {
            this.func1()
        },100);
    }
};
a.func2() //睡觉
 

改变this的三种方法

使用 apply、call、bind 函数也是可以改变 this 的指向的
 
apply
var name = "吃饭";
var a = {
 name: "睡觉",
 test : function(){
  console.log(this.name);
 }
};
a.test() //睡觉
a.test.apply() //吃饭
a.test.apply(a) //睡觉
眼熟吧朋友们,这其实是场景2的代码,区别就是多了一个apply(),结果就变成了吃饭,三种结果,我相信你已经明白
apply是如何改变this了,没错,就是apply(this)
 
call
var name = "吃饭";
var a = {
 name: "睡觉",
 test : function(){
  console.log(this.name);
 }
};
a.test() //睡觉
a.test.call() //吃饭
a.test.call(a) //睡觉
眼熟吧,跟上面一模一样,其实它们区别只是传入的参数不一样,下面再说哦
 
bind
var name = "吃饭";
var a = {
 name: "睡觉",
 test : function(){
  console.log(this.name);
 }
};
a.test() //睡觉
a.test.bind() 
a.test.bind(a) 
你会发现除了第一个执行了,其他都没有执行,这就是bind特殊点,你需要再**抽它一下**
a.test.bind()() //吃饭
a.test.bind(a)() //睡觉
又出现了,很明显,bind需要你再执行它一次才行
 
apply、call、bind区别
从上面我们清楚了如何利用apply、call、bind改变this了,现在我们要了解它们之间的区别了
 
apply和call区别
其实 apply 和 call 基本类似,他们的区别只是传入的参数不同。
apply 和 call 的区别是 call 方法接受的是若干个参数列表,而 apply 接收的是一个包含多个参数的数组。
var name = "吃饭";
var a = {
 name: "睡觉",
 test : function(a,b){
  console.log(this.name + a + b);
 }
};
a.test.apply(a,["打游戏","上厕所"]) //睡觉打游戏上厕所

var name = "吃饭";
var a = {
 name: "睡觉",
 test : function(a,b){
  console.log(this.name + a + b);
 }
};
a.test.call(a,"打游戏","上厕所") //睡觉打游戏上厕所
一不小心爱好都写出来了,我们可以从这两个例子充分了解到apply和call区别了吧
 
call和bind区别
细心的同学可能已经发现call和bind的区别了,废话不多说,上代码
var name = "吃饭";
var a = {
 name: "睡觉",
 test : function(a,b){
  console.log(this.name + a + b);
 }
};
a.test.call(a,"打游戏","上厕所") //睡觉打游戏上厕所

var name = "吃饭";
var a = {
 name: "睡觉",
 test : function(a,b){
  console.log(this.name + a + b);
 }
};
a.test.bind(a,"打游戏","上厕所")() //睡觉打游戏上厕所
对,没错,区别在于你要再执行一次
 
最后感言一下:这是本人第一张文章,本人也只是学习半年多前端的菜鸟,里面要是有啥不对可以指正下,大家相互学习进步,这里只是讲一下JS的常用,还有很多没写到,以后本人会陆陆续续写下ES6、Vue等等看看能不能组成一个系列,我会把我这半年多所学的东西一步一步写上去,给自已知识来个保存。觉得可以的小伙伴就点个赞吧!写的真累,因为每个代码我都要验证,毕竟我也是菜鸟,不能误导别人

回复

我来回复
  • 暂无回复内容