美文网首页
JavaScript 知识点 - JS 基础

JavaScript 知识点 - JS 基础

作者: 千反田爱瑠爱好者 | 来源:发表于2018-08-27 09:41 被阅读9次

变量类型:根据存储方式区分

值类型(变量存放值)

let a = 100
let b = a
a = 200
console.log(b)    // 100

引用类型(变量存放地址):

对象,数组,函数

let a = {age: 20}
let b = a    // b和a都指向同一个地址,因此支持动态添加属性
b.age = 21
console.log(a.age)    // 21

typeof运算符

规律:只能区分值类型和函数(引用类型数组和函数不能判断)

判断值 输出结果
undefined undefined
ywh string
41 number
true boolean
{}, [], null object
console.log function

强制类型转换

字符串拼接

let a = 100 + 10      // 110
let b = 100 + '10'    // '10010'

== 运算符

// 以下判断返回结果都为true
100 == '100'
0 == ''
null == undefined

// 除了这个以外其余都用“===”
if (obj.a == null) {
    // ...
}

// 建议都使用`===`或参考jQuery源码推荐写法

if语句

// 注意当a未定义时,if (a == null) 或 if (a == undefined)会报错 

let a = true
let b = 100
let c = ''
if (a) {
    // true
}
if (b) {
    // true
}
if (c) {
    // false
}

逻辑运算符

10 && 0    // 0
'' || 'abc'    // 'abc'
!window.abc    // true

// 判断一个变量会被当做true还是false
let a = 100
!!a    // 反反

安全赋值(避免覆盖)

var a = a || {}    // a的值存在则不允许定义

内置函数

  1. Object
  2. Array
  3. Boolean
  4. Number
  5. String
  6. Function
  7. Date
  8. RegExp
  9. Error
  10. Math

原型和原型链

构造函数

  1. var a = {}var a = new Object()的语法糖;
  2. var a = []var a = new Array()的语法糖;
  3. function Foo(){...}var Foo = new Function(...)语法糖;
  4. 可使用a instanceof Array判断一个函数是否是一个变量的构造函数(如区分数组和对象)。
// 注意构造函数首字母要用大写
function Foo(name, age) {
    this.name = name
    this.age = age
    // return this    // 默认返回this
}

let f = new Foo('ywh', 18)    // 创建一个实例

原型规则

  1. 所有引用类型(数组,对象,函数)都具有共有的对象特性,即可自由扩展属性(null除外);
  2. 所有的引用类型都有一个__proto__属性(对象),即隐式原型,存放该类型共有属性的地址(指向构造函数的prototype,即(new Object).__proto__ === Object.prototype);
  3. 所有的函数都有一个prototype属性(对象),即显式原型;
  4. 当试图访问对象的某个属性,会先从对象本身查找,不存在则会从__proto__沿着原型链依次查找;
  5. f instanceof Foo的原理也是沿着原型链一层层往上判断,看可否达到Foo.protype,再试着判断f instance of Object
function Foo(name, age) {
    this.name = name
    this.age = age
}
Foo.prototype.alertName = function () {
    alert(this.name)
}

let f = new Foo('ywh')
f.printName = function () {
    console.log(this.name)
}

f.printName()    // 自身属性
f.alertName()    // 原型属性
f.toString()     // 原型的原型的属性

// new 创建对象的过程
// 1. 创建一个新对象
// 2. this指向这个新对象
// 3. 执行代码,对this赋值
// 4. 返回this

循环对象自身的属性:

var item
for (item in f) {
    if (f.hasOwnProperty(item))
        console.log(item)
}
// 高级浏览器已经在“for...in...”中屏蔽来自原型的属性,但还是建议加入判断

原型链继承的例子:

function Animal() {
    this.eat = function () {
        congole.log("animal eat")
    }
}

function Dog() {
    this.bark = function () {
        console.log("dog bark")
    }
}

Dog.prototype = new Animal()
var dog = new Dog()

实例:封装DOM查询

function Elem(id) {
    this.elem = document.getElementById(id)
}
Elem.prototype.html = function(val) {
    let elem = this.elem
    if (val) {
        elem.innerHTML = val
        return this
    }
    else {
        return elem.innerHTML
    }
}
Elem.prototype.on = function (type, fn) {
    let elem = this.elem
    elem.addEventListener(type, fn)
}

let div1 = new Elem('detail-page')
div1.html("<p>Hello World</p>").on("click", function(){
    alert("click")
})

执行上下文

  • 范围:一段<script>或者一个函数;
  • 全局:变量定义、函数声明
  • 函数:变量定义、函数声明、this、arguments
console.log(a)    // undefined
var a = 100   // 把var a提升到最上面,此处剩余a = 100,所以console.log时a还未被赋值

fn("ywh")    // "ywh" 20
function fn(name) {    // 被提升到“fn("ywh")”之前
    age = 20 
    console.log(name, age)
    var age // 被提升到“age = 20”之前
}

this

  1. thiscall的第一个参数,在执行时才确定值,定义时无法确认;
    • 作为构造函数执行;
    • 作为普通函数执行;
    • call,apply,bind
let a = {
    name: "A", 
    fn: function() {
        console.log(this.name)
    }
}

a.fn()    // this === a
a.fn.call({name: 'B'})    // this === {name: 'B'}
var fn1 = a.fn
fn1()    // this === window

作用域

  • ES6之前只有函数作用域与全局作用域,没有块级作用域;
if (true) {    // 此处没有隔离作用域,是全局声明
    var name = "ywh"
}
console.log(name)

var a = 100
funtion fn() {
    var a = 200
    console.log("fn", a)
}
console.log("global", a)
fn()

作用域链(树)

var a = 100
function fn1() {
    var b = 200
    function fn2() {
        var c = 300
        console.log(a)    // 当前作用域没有定义的变量,即“自由变量”,会从当前作用域向上查找
        console.log(b)
        console.log(c)    
    }
    fn2()
}
fn1()

闭包

使用场景

  • 函数作为返回值
  • 函数作为参数传递

主要用于封装变量,收敛权限

function fn1() {
    var a = 100
    return function() {
        console.log(a)    // a是自由变量,向父级作用域查找,因此是100
    }
}
// 函数作为返回值
var f1 = fn1()
var a = 200
f1()    // 100

// 函数作为参数传递
function fn2(fn) {
    var a = 200
    fn().call()
}
fn2(fn1)

实例:利用闭包保护变量

// 错误
var i, a
for (i = 0; i < 10; i ++ ) {
    a = document.createElement("a")
    a.innerHTML = i + "<br>"
    a.addEventListener("click", function(e) {
        e.preventDefault()
        alert(i)
    })    // 循环执行完才点击,i是自由变量,会从父作用域查找,此时i === 9,因此点击任何一个都会输出9
    document.body.appendChild(a)
}

// 正确
var i
for (i = 0; i < 10; i ++ ) {
    (function(i) {    
        var a = document.createElement("a")
        a.innerHTML = i + "<br>"
        a.addEventListener("click", function(e) {
            e.preventDefault()
            alert(i)   // 此处的i使用的是外部变量,因此构成闭包,值会一直保存在函数作用域不会被修改
        })
        document.body.appendChild(a)
    })(i)    // 封装成一个立即执行闭包函数
}

实例:使用闭包收敛权限

function isFirstLoad() {
    var _list = []    // 一直保存在内存中
    return funciton(id) {
        if (_list.indexOf(id) >= 0) {
            return false
        }
        else {
            _list.push(id)
            return true
        }
    }
}
var firstload = isFirstLoad()
firstload(10)    // true
firstload(10)    // false
firstload(20)    // true

异步和单线程

JS是单线程执行,因此很多场景下要使用异步。

同步:代码顺序执行,中间可能会阻塞

console.log(100)
alert(200)    // 同步执行,点确认前会阻塞
console.log(300)

异步:不考虑执行结果(或通过回调获取执行结果),调用立即返回;

使用异步的场景:在可能发生等待、且等待过程中不能阻塞(像alert一样):

  • setTimeoutsetInterval
  • ajax请求,动态<img>加载;
  • 事件绑定。
console.log(1)
setTimeout(function() {    
    console.log(2)
}, 0)
console.log(3)
setTimeout(function() {    
    console.log(4)
}, 1000)
console.log(5)
// 1, 3, 5, 2, 4

// $.get("https://www.baidu.com", function(data){console.log(data)})

Event-Loop(事件轮询):

  1. 顺序执行所有同步函数;
  2. setTimeout执行的异步函数会在等待完成后依次暂存在异步队列(单线程);
  3. 轮询异步队列,依次取出函数执行。

其他API

日期

Date.now()
var dt = new Date()
dt.getTime()
dt.getFullYear()
dt.getMonth()
dt.getDate()
dt.getHours()
dt.getMinutes()
dt.getSeconds()

数学

Math.random()    // 获取随机数

数组

// 遍历所有元素
var arr = [1, 2, 3]
arr.forEach(function(item, index) {    
    console.log(index, item)
})

// 判断是否所有元素都符合条件,some判断是否至少一个元素符合条件
var arr = [1, 2, 3]
var result = arr.every(function(item, index) {
    if (item < 4) {
        return true
    }
})
console.log(result)

// 排序
var arr = [1, 4, 2, 3]
var arr2 = arr.sort(function(a, b) {
    return a - b
})
console.log(arr2)


map    // 对元素重新组装生成新数组
filter    // 过滤符合条件的元素
// ...

对象

var obj = {
    x: 100, y: 200, z: 300
}

for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        console.log(key, obj[key])
    }
}

回答以下问题

  1. JS中使用typeof能得到的哪些类型?
  2. 何时使用==,何时使用===
  3. JS中有哪些内置函数?
  4. JS变量按照存储方式区分为哪些类型,并描述其特点。
  5. 如何理解JSON?
  6. 如何准确判断一个变量是数组类型?
  7. 写一个原型链继承的例子。
  8. 描述new一个对象的过程。
  9. zepto(值得阅读,或其他框架)源码中如何使用原型链?
  10. 如何理解变量提升?
  11. 说明this几种不同的使用场景。
  12. 创建10个<a>标签,点击时弹出来对应的序号。
  13. 如何理解作用域?
  14. 实际开发中闭包的作用?
  15. 同步和异步的区别是什么?分别举一个同步和异步的例子。
  16. setTimeout函数的用法。
  17. 前端使用异步的场景有哪些?
  18. 获取2017-06-10格式的日期。
  19. 获取随机数,要求是长度一致的字符串格式。
  20. 写一个能遍历对象和数组的通用forEach函数。

相关文章

网友评论

      本文标题:JavaScript 知识点 - JS 基础

      本文链接:https://www.haomeiwen.com/subject/dthziftx.html