如果生活中有什么使你感到快乐,那就去做吧,不要管别人说什么
文章目录
- 原型链
- 严格模式
- 高阶函数
- 闭包
- 递归
- 浅拷贝和深拷贝
原型链
- 概念:就是串联起来的结构
- 作用:提供一个成员的查找机制或者查找规则
- Javascript的成员查找机制(规则)
当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性- 如果没有就查找它的原型(也就是__proto__指向的prototype 原型对象)
- 如果还没有就查找原型对象的原型 (Object的原型对象)
以此类推一直找到Object为止 (null) - __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线
- 如果一个对象查找属性和方法,那么先从自身开始查找
- 找到的话使用自身的属性方法,如果找不到就会沿着原型链一直查找
- 只要在原型链上,那么一定可以使用
- 扩展对象
可以通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组增加自定义求偶数和的功能var arr = new Array(1,2,3) Array.prototype.sum = function() { // 求和 var he = 0 // 遍历 for (var i = 0; i < this.length; i++) { he = he + this[i] } // 返回值 return he } console.log(arr.sum())
- 继承
ES6:通过 构造函数 + 原型对象 模拟实现继承、被称为组合继承call()
:把父类的this指向子类- 属性的继承 (利用构造函数实现子类的继承)
function Hero(name,age) { this.name = name this.age = age } function Star(name,age,hobby,jineng) { Hero.call(this,name,age) this.hobby = hobby this.jineng = jineng } var obj = new Star('华晨宇',27,'唱歌','麦克风') console.log(obj)
- 方法的继承 (把父类的实例对象保存给子类的原型对象)
一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法// 父类原型对象 function Father() { } Father.prototype.say = function () { console.log('说话') } function Son() { } // 假设 : 如果子类已经继承下来这个方法,那么这个方法在 prototype // Son.prototype = Father.prototype // 1. 用父实例对象赋值给子原型对象 Son.prototype = new Father() // 2. 让子原型对象能够找回子构造函数 Son.prototype.constructor = Son var obj = new Son() // 有自己的方法 Son.prototype.hi = function () { console.log('哇哈哈哈') } obj.say() obj.hi() console.log(Son.prototype) console.log(Father.prototype)
总结:用构造函数实现属性继承,用原型对象实现方法继承
- 类的本质
- class本质还是function
- 类的所有方法都定义在类的prototype属性上
- 类创建的实例,里面也有__proto__ 指向类的prototype原型对象
- ES6的类它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
- 语法糖:语法糖就是一种便捷写法。 简单理解,有两种方法可以实现同样的功能,但是一种写法更加清晰、方便,那么这个方法就是语法糖
严格模式
- 作用
- 消除了Javascript语法的一些不合理、不严谨之处,减少了一些怪异行为。【例如变量,不声明就报错】
- 消除代码运行的一些不安全之处,保证代码运行的安全。
- 提高编译器效率,增加运行速度
- 禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的Javascript做好铺垫。比如一些保留字如:class, enum, export, extends, import, super 不能做变量名
- 开启严格模式:
"use strict"
- 为脚本开启严格模式
<script>"use strict"</script>
<script> "use strict" function fn () { n = 6 console.log(n) } fn() </script> 因为"use strict"加了引号,所以老版本的浏览器会把它当作一行普通字符串而忽略
- 为函数开启严格模式
<script>function fn () {"use strict"}</script>
function fn() { "use strict" // var n = 9 n = 9 console.log (n) } // fn() function fn () { n = 9 console.log(n) } fn() 将"use strict"放在函数体的第一行,则整个函数以"严格模式"运行
- 为脚本开启严格模式
- 严格模式中的变化
- 变量规定
- 变量申明必须加var,而且不准删除变量
- 在正常模式下,如果一个变量没有声明就赋值,默认是全部变量。严格模式禁止这种用法,变量都必须先用var命令声明,然后再使用
- 严禁删除已经声明变量 例如: delete x; 语法是错误的
- 函数变化
- 参数不能重名
- 函数不能有重名的参数
- 函数必须声明在顶层,新版本的JavaScript 会引入“块级作用域”(ES6 中已引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数。【if,for等里面定义函数也可以,但是现在不可以】
- 错误写法:
function fn(a, a) {console.log(a + a)} fn(1,2)
- 严格模式下this指向问题
- 严格模式下,普通函数this是undefined
- 以前在全局作用域函数中的this指向 window 对象;严格模式下全局作用域中函数的this是undefined
- 以前构造函数时不加new也可以调用,普通函数,this 指向全局对象;严格模式下,如果构造函数不加new调用, this 指向的是undefined ,如果给他赋值则会报错
- new实例化的构造函数指向创建的对象实例
- 定时器this还是指向window
- 事件、对象还是指向调用者
- 变量规定
高阶函数
- 概念:把函数作为参数,或者把函数作为返回值的函数
var n = function () { console.log(123) }
// 把函数当参数的函数是高阶函数
function fn(m) {
console.log(m)
m()
}
var n = function () { console.log('娃哈哈') }
fn(n)
// 把函数当做返回值的函数是高阶函数
function fun() {
var n = function () { console.log('娃哈哈') }
return n
}
// 函数的返回值是返回函数调用的位置
var re = fun()
console.log(re)
re()
function fn(f) {
f && f()
}
var n = function () {console.log(123) }
fn(n)
闭包
- 概念:有权访问另一个函数作用域中变量的函数
- 作用:延伸(局部)变量的作用范围
function fn1() {
var n = 3 // 父作用域
function fn2() {
console.log(n)
}
fn2() // 闭包函数 //子作用域
}
fn1()
// 如何在函数外面访问到函数内部的变量
function fn() {
var num = 6
return function fun() {
console.log(num)
}
// fun()
}
var n = fn()
console.log(n)
n()
递归
- 概念:如果一个函数在内部可以调用其本身,那么这个函数就是递归函数
- 注意:递归函数的作用和循环效果一样,由于递归很容易发生"栈溢出"错误(stack overflow),所以必须要加退出条件
// 利用递归求1~n的任意一个数的阶乘
function fn(n) {
// 判断
if (n == 1) { // 结束条件
return 1
}
return n * fn(n - 1);
}
console.log(fn(3))
// 利用递归求斐波那契数列
function fb(n) {
if (n === 1 || n === 2) {
return 1
}
return fb(n - 1) + fb(n - 2)
}
console.log(fb(3))
// 利用递归函数求斐波那契数列(兔子序列) 1、1、2、3、5、8、13、21...
// 用户输入一个数字 n 就可以求出 这个数字对应的兔子序列值
// 我们只需要知道用户输入的n 的前面两项(n-1 n-2)就可以计算出n 对应的序列值
// 利用递归遍历数据
var data = [
{
id: 1,
name: '家电'
},
{
id: 2,
name: '服饰'
}
]
// 写一个程序, 可以从指定数组中获取指定id的数据
function fn(arr, id) {
// arr : 代表数据的数组
// id : 代表要取出来的商品id
var obj = {}
// 遍历数组
arr.forEach(function (item) {
// item = {id : 1,name : '家电'}
if (item.id == id) {
obj = item
}
})
// 返回值
return obj
}
console.log(fn(data))
浅拷贝和深拷贝
- 浅拷贝
var obj = {
name : '张三丰',
age : 22
}
var newObj = {}
for (key in obj) {
newObj[key] = obj[key]
}
console.log(newObj)
- 深拷贝
var obj = {
name: '1张三丰',
age: 22,
messige: {
sex: '男',
score: 16
},
color: ['red', 'purple', 'qing']
}
var newObj = {}
function kaobei(newObj, obj) {
for (key in obj) {
if (obj[key] instanceof Array) {
newObj[key] = []
kaobei(newObj[key], obj[key])
} else if (obj[key] instanceof Object) {
newObj[key] = {};
kaobei(newObj[key], obj[key])
} else {
newObj[key] = obj[key]
}
}
}
obj.messige.sex = 99
kaobei(newObj, obj)
console.log(newObj)