2 ## JS基本介绍 3 + JS的用途:Javascript可以实现浏览器端、服务器端(nodejs)。。。 4 + 浏览器端JS由以下三个部分组成: 5 - ECMAScript:基础语法(数据类型、运算符、函数。。。) 6 - BOM(浏览器对象模型):window、location、history、navigator。。。 7 - DOM(文档对象模型):div、p、span。。。 8 + ECMAScript又名es,有以下重大版本: 9 - 旧时代: 10 - es1.0。。。es3.1 11 - 新时代: 12 - es5 13 - es6(es2015) 14 - es7(es2016)、es8(es2017) 15 16 ## 数据类型 17 + 基本数据类型——值类型:(数字、字符串、布尔值、null、undefined) 18 - undefined类型? 19 + 复杂数据类型——引用类型:(对象) 20 - 数组 21 - 函数 22 - 正则表达式 23 - Date 24 25 ## 对象的基本使用 26 ### 创建一个对象 27 ```js 28 var student={ 29 name:"李白" , //student有一个name属性,值为"李白" 30 grade:"初一" , 31 //a、student有一个say属性,值为一个函数 32 //b、student有一个say方法 33 say:function(){ 34 console.log("你好"); 35 }, 36 run:function(speed){ 37 console.log("正在以"+speed+"米/秒的速度奔跑"); 38 } 39 } 40 ``` 41 42 ### 对象是键值对的集合:对象是由属性和方法构成的 (ps:也有说法为:对象里面皆属性,认为方法也是一个属性) 43 + name是属性 grade是属性 44 + say是方法 run是方法 45 46 ### 对象属性操作 47 #### 获取属性: 48 #### 第一种方式:.语法 49 + student.name 获取到name属性的值,为:"李白" 50 + student.say 获取到一个函数 51 52 #### 第二种方式:[]语法 53 + student["name"] 等价于student.name 54 + student["say"] 等价于student.say 55 56 #### 号外:2种方式的差异: 57 + .语法更方便,但是坑比较多(有局限性),比如: 58 - .后面不能使用js中的关键字、保留字(class、this、function。。。) 59 - .后面不能使用数字 60 ```js 61 var obj={}; 62 obj.this=5; //语法错误 63 obj.0=10; //语法错误 64 ``` 65 66 + []使用更广泛 67 - o1[变量name] 68 - ["class"]、["this"]都可以随意使用 `obj["this"]=10` 69 - [0]、[1]、[2]也可以使用 70 - `obj[3]=50 = obj["3"]=50` 71 - 思考:为什么obj[3]=obj["3"] 72 - 甚至还可以这样用:["[object Array]"] 73 - jquery里面就有这样的实现 74 - 也可以这样用:["{abc}"] 75 - 给对象添加了{abc}属性 76 77 #### 设置属性 78 + `student["gender"]="男"` 等价于: `student.gender="男"` 79 - 含义:如果student对象中没有gender属性,就添加一个gender属性,值为"男" 80 - 如果student对象中有gender属性,就修改gender属性的值为"男" 81 + 案例1:`student.isFemale=true` 82 + 案例2:`student["children"]=[1,2,5]` 83 + 案例3: 84 ```js 85 student.toShanghai=function(){ 86 console.log("正在去往上海的路上") 87 } 88 ``` 89 90 #### 删除属性 91 + delete student["gender"] 92 + delete student.gender 93 94 95 96 ## 通过构造函数创建对象 97 ### 构造函数创建对象的例子: 98 + var xiaoming = new Object() --> var xiaoming = {}; 99 + var now = new Date() 100 + var rooms = new Array(1,3,5) --> var rooms = [1,3,5] 101 + `var isMale=/123/;` ==> `var isMale=new RegExp("123")` 102 - isMale是通过RegExp构造函数创建出来的对象 103 - isMale是RegExp构造函数的实例 104 105 + 以上例子中,Object、Date、Array都是内置的构造函数 106 107 ## 自定义一个构造函数来创建对象 108 + 构造函数 109 ```js 110 function Person(name,age){ 111 this.name=name; 112 this.age=age; 113 } 114 var p1=new Person("赵云",18) 115 ``` 116 + 说明:`p1就是根据【Person构造函数】创建出来的对象` 117 118 ### 构造函数的概念 119 + 任何函数都可以当成构造函数 120 `function CreateFunc(){ }` 121 + 只要把一个函数通过new的方式来进行调用,我们就把这一次函数的调用方式称之为:构造函数的调用 122 - new CreateFunc(); 此时CreateFunc就是一个构造函数 123 - CreateFunc(); 此时的CreateFunc并不是构造函数 124 125 ### 关于new Object() 126 + new Object()等同于对象字面量{} 127 128 ### 构造函数的执行过程 129 `var p1=new Person();` 130 + 1、创建一个对象 (我们把这个对象称之为Person构造函数的实例)- `_p1 ` 131 + 2、创建一个内部对象,`this`,将this指向该实例(_p1) 132 + 3、执行函数内部的代码,其中,操作this的部分就是操作了该实例(_p1) 133 + 4、返回值: 134 - a、如果函数没有返回值(没有return语句),那么就会返回构造函数的实例(p1) 135 - b、如果函数返回了一个基本数据类型的值,那么本次构造函数的返回值是该实例(_p1) 136 ```js 137 function fn(){ 138 139 } 140 var f1=new fn(); //f1就是fn的实例 141 142 function fn2(){ 143 return "abc"; 144 } 145 var f2=new fn2(); //f2是fn2构造函数的实例 146 ``` 147 - c、如果函数返回了一个复杂数据类型的值,那么本次函数的返回值就是该值 148 ```js 149 function fn3(){ 150 return [1,3,5]; 151 //数组是一个对象类型的值, 152 //所以数组是一个复杂数据类型的值 153 //-->本次构造函数的真正返回值就是该数组 154 //-->不再是fn3构造函数的实例 155 } 156 var f3=new fn3(); //f3还是fn3的实例吗?错 157 //f3值为[1,3,5] 158 ``` 159 160 161 162 ## 继承 163 ### JS中继承的概念: 164 + 通过【某种方式】让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承 `并不是所谓的xxx extends yyy` 165 166 ### 为什么要使用继承? 167 + 有些对象会有方法(动作、行为),而这些方法都是函数,如果把这些方法和函数都放在构造函数中声明就会导致内存的浪费 168 ```js 169 function Person(){ 170 this.say=function(){ 171 console.log("你好") 172 } 173 } 174 var p1=new Person(); 175 var p2=new Person(); 176 console.log(p1.say === p2.say); //false 177 ``` 178 179 ### 继承的第一种方式:原型链继承1 180 ```js 181 Person.prototype.say=function(){ 182 console.log("你好") 183 } 184 ``` 185 + 缺点:添加1、2个方法无所谓,但是如果方法很多会导致过多的代码冗余 186 187 ### 继承的第二种方式:原型链继承2 188 ```js 189 Person.prototype = { 190 //切记不能忘记 191 constructor:Person, 192 say:function(){ 193 console.log("你好"); 194 }, 195 run:function(){ 196 console.log("正在进行百米冲刺"); 197 } 198 } 199 ``` 200 + 注意点: 201 + a、一般情况下,应该先改变原型对象,再创建对象 202 + b、一般情况下,对于新原型,会添加一个constructor属性,从而不破坏原有的原型对象的结构 203 204 ### 继承的第三种方式:拷贝继承(混入继承:mixin) 205 + 场景:有时候想使用某个对象中的属性,但是又不能直接修改它,于是就可以创建一个该对象的拷贝 206 + 实际运用: 207 - jquery:$.extend:编写jquery插件的必经之路 208 - 基于jquery封装一个表格控件 209 210 ```js 211 var o1={ age:2 }; 212 213 var o2 = o1; 214 o2.age=18; 215 //1、修改了o2对象的age属性 216 //2、由于o2对象跟o1对象是同一个对象 217 //3、所以此时o1对象的age属性也被修改了 218 ``` 219 ```js 220 var o3={gender:"男",grade:"初三",group:"第五组",name:"张三"}; 221 var o4={gender:"男",grade:"初三",group:"第五组",name:"李四"}; 222 //上述代码中,如果使用拷贝继承对代码进行优化会非常和谐 223 224 //实现拷贝继承: 225 //1、已经拥有了o3对象 226 //2、创建一个o3对象的拷贝(克隆):for...in循环 227 228 229 //3、修改克隆对象,把该对象的name属性改为"李四" 230 231 ``` 232 233 + 实现1: 234 ```js 235 var source={name:"李白",age:15} 236 var target={}; 237 target.name=source.name 238 target.age=source.age; 239 ``` 240 241 + 浅拷贝和深拷贝 242 - 浅拷贝只是拷贝一层属性,没有内部对象 243 - 深拷贝其实是利用了递归的原理,将对象的若干层属性拷贝出来 244 ```js 245 var students=[ 246 {name:"",age:""}, 247 {name:"",age:""} 248 ] 249 ``` 250 251 + 上面的方式很明显无法重用,实际代码编写过程中,很多时候都会使用拷贝继承的方式,所以为了重用,可以编写一个函数把他们封装起来: 252 ```js 253 function extend(target,source){ 254 for(key in source){ 255 target[key]=source[key]; 256 } 257 return target; 258 } 259 extend(target,source) 260 ``` 261 262 + 由于拷贝继承在实际开发中使用场景非常多,所以很多库都对此有了实现 263 - jquery:$.extend 264 265 + es6中有了 <对象扩展运算符> 仿佛就是专门为了拷贝继承而生: 266 - 优点:简单的令人发指 267 ```js 268 var source={name:"李白",age:15} 269 //让target是一个新对象,同时拥有了name、age属性 270 var target={ ...source } 271 272 var target2={ ...source,age:18 } 273 ``` 274 275 ### 继承的第四种方式:原型式继承:(道格拉斯在蝴蝶书中提出来的) 276 + 场景: 277 - a、创建一个纯洁的对象:对象什么属性都没有 278 - b、创建一个继承自某个父对象的子对象 279 ```js 280 var parent={ age:18,gender:"男"}; 281 var student=Object.create(parent); 282 //student.__proto__===parent 283 ``` 284 + 使用方式: 285 - 空对象:Object.create(null) 286 - 287 ```js 288 var o1={ say:function(){} } 289 var o2=Object.create(o1); 290 ``` 291 292 ### 继承的第五种方式:借用构造函数实现继承 293 + 场景:适用于2种构造函数之间逻辑有相似的情况 294 + 原理:函数的call、apply调用方式 295 296 ```js 297 function Animal(name,age,gender){ 298 this.name=name; 299 this.age=age; 300 this.gender=gender; 301 } 302 function Person(name,age,gender,say){ 303 this.name=name; 304 this.age=age; 305 this.gender=gender; 306 307 this.say=function(){ 308 309 } 310 } 311 ``` 312 + 局限性:Animal(父类构造函数)的代码必须完全适用于Person(子类构造函数) 313 314 + 以上代码用借用构造函数实现 315 ```js 316 function Animal(name,age){ 317 this.name=name; 318 this.age=age; 319 } 320 function Person(name,age,address){ 321 Animal.call(this,name); 322 //this.name=name; 323 //this.age=age; 324 this.address=address; 325 } 326 ``` 327 328 + 寄生继承、寄生组合继承 329 330 ## 原型链(家族族谱) 331 + 概念:JS里面的对象可能会有父对象,父对象还会有父对象,。。。。。祖先 332 + 根本:继承 333 - 属性:对象中几乎都会有一个__proto__属性,指向他的父对象 334 -意义:可以实现让该对象访问到父对象中相关属性 335 + 根对象:Object.prototype 336 - var arr=[1,3,5] 337 - arr.__proto__:Array.prototype 338 - arr.__proto__.__proto__找到了根对象 339 340 ```js 341 function Animal(){} 342 var cat=new Animal(); 343 //cat.__proto__:Animal.prototype 344 //cat.__proto__.__proto__:根对象 345 ``` 346 + 错误的理解:万物继承自Object? 347 348 ## 闭包 349 ### 变量作用域 350 + 变量作用域的概念:就是一个变量可以使用的范围 351 + JS中首先有一个最外层的作用域:称之为全局作用域 352 + JS中还可以通过函数创建出一个独立的作用域,其中函数可以嵌套,所以作用域也可以嵌套 353 ```js 354 var age=18; //age是在全局作用域中声明的变量:全局变量 355 356 function f1(){ 357 console.log(name); //可以访问到name变量 358 var name="周董" //name是f1函数内部声明的变量,所以name变量的作用域就是在f1函数内部 359 360 console.log(name); //可以访问到name变量 361 362 console.log(age); //age是全局作用域中声明的,所以age也可以访问 363 } 364 365 console.log(age); //也可以访问 366 ``` 367 368 ```js 369 //多级作用域 370 //-->1级作用域 371 var gender="男"; 372 function fn(){ 373 //问题: 374 //gender:可以访问 375 //age: 可以访问 376 //height:不能访问 377 378 //-->2级作用域 379 return function(){ 380 //问题: 381 //gender: 通过一级一级作用域的查找,发现gender是全局作用域中声明的变量 382 //age: 383 //height: 384 console.log(gender); 385 386 //-->3级作用域 387 var height=180; 388 } 389 var age=5; 390 } 391 ``` 392 393 ### 作用域链 394 + 由于作用域是相对于变量而言的,而如果存在多级作用域,这个变量又来自于哪里?这个问题就需要好好地探究一下了,我们把这个变量的查找过程称之为变量的作用域链 395 + 作用域链的意义:查找变量(确定变量来自于哪里,变量是否可以访问) 396 + 简单来说,作用域链可以用以下几句话来概括:(或者说:确定一个变量来自于哪个作用域) 397 - 查看当前作用域,如果当前作用域声明了这个变量,就确定结果 398 - 查找当前作用域的上级作用域,也就是当前函数的上级函数,看看上级函数中有没有声明 399 - 再查找上级函数的上级函数,直到全局作用域为止 400 - 如果全局作用域中也没有,我们就认为这个变量未声明(xxx is not defined) 401 402 + 举例1: 403 ```js 404 var name="张三"; 405 function f1(){ 406 var name="abc"; 407 console.log(name); 408 } 409 f1(); 410 ``` 411 412 + 举例2: 413 ```js 414 var name="张三"; 415 function f1(){ 416 console.log(name); 417 var name="abc"; 418 } 419 f1(); 420 ``` 421 422 + 举例3: 423 ```js 424 var name="张三"; 425 function f1(){ 426 console.log(name); 427 var name="abc"; 428 } 429 f1(); 430 ``` 431 432 + 举例4: 433 ```js 434 var name="张三"; 435 function f1(){ 436 return function(){ 437 console.log(name); 438 } 439 var name="abc"; 440 } 441 var fn=f1(); 442 fn(); 443 ``` 444 445 + 举例5: 446 ```js 447 var name="张三"; 448 function f1(){ 449 return { 450 say:function(){ 451 console.log(name); 452 var name="abc"; 453 } 454 } 455 } 456 var fn=f1(); 457 ``` 458 459 ### 闭包的问题 460 ```js 461 function fn(){ 462 var a=5; 463 return function(){ 464 a++; 465 console.log(a); 466 } 467 } 468 var f1=fn(); 469 f1(); 470 f1(); 471 f1(); 472 ``` 473 474 ### 闭包问题的产生原因 475 + 函数执行完毕后,作用域中保留了最新的a变量的值 476 477 ### 闭包的应用场景 478 + 模块化 479 + 防止变量被破坏 480 481 ### 函数的4种调用方式 482 + 1、函数调用 483 ```js 484 var age=18; 485 var p={ 486 age:15 487 say:function(){ 488 console.log(this.age); 489 } 490 } 491 var s1=p.say() 492 s1(); //函数调用 493 ``` 494 + 2、方法调用 495 ```js 496 var age=18; 497 var p={ 498 age:15 499 say:function(){ 500 console.log(this.age); 501 } 502 } 503 p.say()//方法调用 504 ``` 505 + 3、new调用(构造函数) 506 ```js 507 var age=18; 508 var p={ 509 age:15 510 say:function(){ 511 console.log(this.age); 512 } 513 } 514 new p.say()//构造函数调用 515 ``` 516 + 4、上下文方式(call、apply、bind) 517 ```js 518 var length=21; 519 function f1(){ 520 console.log(this.length); 521 } 522 f1.call([1,3,5]) 523 f1.apply(this) 524 f1.call(5) 525 ``` 526 527 + 在ES6的箭头函数之前的时代,想要判断一个函数内部的this指向谁,就是根据上面的四种方式来决定的 528 529 530 531 532 533 ### es6内容 534 + 1、解构赋值 535 + 2、函数rest参数 536 + 3、箭头函数 537 - 箭头函数和普通函数有哪些不同?(4点) 538 + 4、对象的Object.assign 539 + 5、promise 540 + 6、generator 541 + 7、async 542 + 8、class 543 + 9、module 544 545 ### 原型 546 + 原型很多人开发用不到? 547 - 很多人都用es6/7/8开发,确实用的比较少 548 - 如果你用es5之前的版本开发代码(IE8、IE7。。。),可能天天都要写原型 549 - 理解了原型,才是理解了JS面向对象的核心 550 + 类继承其实本质上还是用原型继承来(包装)的
JS高级篇一:对象、构造函数、继承
猜你喜欢
转载自www.cnblogs.com/qfshini/p/12262750.html
今日推荐
周排行